2015-09-29 4 views
0

Предположим, у меня есть две монады F и M (в стиле Скалаз) и функция f: A => F[B]. Я хотел бы создать функцию g: A => F[M[B]], которая сначала применяет f, а затем связывает F-монаду с pure[M]. Пример для наглядности:Преобразование монадической функции для возврата точки в другой монаде

// here, F = Option and M = List 
import scalaz.syntax.monad._ 
import scalaz.std.list._ 

def f(x: Int): Option[Int] = Some(x) 
def g(x: Int): Option[List[Int]] = f(x).map(t => List(t)) 

Здесь, реализация g использует внутреннюю монаду (List) конструктор явно. Я мог бы избежать этого следующим образом:

def g2[M[_]: Monad](x: Int): Option[M[Int]] = f(x).map(_.pure[M]) 

Теперь вопрос: У меня есть функция, которая ожидает что-то вроде g (так функция стоимости Int => Option[List[Int]]) и что-то вроде f в моих руках. Как я могу кормить друг друга? Проще говоря:

def f(x: Int): Option[Int] = ... 
def callMe(h: (Int => Option[List[Int]]) = ... 
//I can of course do that: 
callMe(t => f(t).map(_.point[List])) 

//How it without lambda expression? 
callMe(f.kindOfALift[List]???) 
callMe(f andThen ???) 

Проблема здесь может быть, конечно, отведенной для поддержки не только Int => Option[Int] но A => M[B] в целом, но это легкая часть. Жесткая часть (для меня) обертывает результат во внутреннюю монаду. Следующий шаг - заставить его работать над преобразованными монадами (поэтому вместо того, чтобы иметь монаду M, будет здорово заставить его работать с трансформатором monad MT). Любые намеки?

ответ

0

Просто измените g2 принять f в качестве аргумента:

def g2[A, B, M1[_]: Monad, M2[_]: Monad](f: A => M1[B]): A => M1[M2[B]] = 
    x => f(x).map(_.pure[M2]) 

Кроме этого будет иметь проблемы с выводом типа, так как обычно требуется указать M2 и нет никакого способа узнать, Scala вывести только некоторые аргументы типа. Но это легко поправимо:

implicit class FOp[A, B, M1[_]: Monad](f: A => M1[B]): A => M1[M2[B]] { 
    def kindOfALift[M2[_]: Monad] = x => f(x).map(_.pure[M2]) 
} 

callMe(f andThen ???)

f.andThen(_.map(_.point[List])) также должен работать, если это подходит.

+0

Я использую scalaz как мешок полезных ярлыков, поэтому я надеялся на то, что не нуждается в моих неявных классах ... 'f.andThen (_. Map (_. Point))' работает, конечно, но было бы здорово избежать лишних '_.map' –