Клейсли Стрелка с писателем в Скале. Почему он не компилируется?

Это продолжение моего предыдущего вопроса. Похоже, я до сих пор не понял. Сейчас я пытаюсь составить функции, которые возвращают монаду Writer.

scala> val f = {x: Int => Writer ("выполняется" + x + ";", x + 1)}
f: Int => scalaz.WriterT[scalaz.Id.Id,String,Int] = 

scala> Kleisli(f) >=> Kleisli(f):16: ошибка: параметры типа для метода не применяются: (f: A => M[B])scalaz.Kleisli[M,A,B] в объекте Kleisli существуют так, что его можно применять к аргументам (Int => scalaz.WriterT[scalaz.Id.Id,String,Int])
 --- потому что --- тип выражения аргумента не совместим с формальным типом параметра; найдено: Int => scalaz.WriterT [scalaz.Id.Id, String, Int] обязательно:?A =>?M

              Kleisli(f) >=> Kleisli(f)

Почему он не компилируется?

1 ответ

Решение

Когда компилятор Scala ожидает тип в форме M[B] и вы даете что-то вроде WriterT[Id, String, Int]К сожалению, это просто недостаточно умно, чтобы понять, что вы хотите исправить первые два параметра типа и использовать монаду для WriterT[Id, String, _],

Есть несколько возможных способов обойти это ограничение. Первый - определить псевдоним типа:

type StringWriter[A] = WriterT[Id, String, A]

Теперь вы можете предоставить явные параметры типа (фактически вы можете сделать это без псевдонима, но тип lambdas сделает строку в два раза длиннее и в десять раз нечитаемой):

scala> Kleisli[StringWriter, Int, Int](f) >=> Kleisli[StringWriter, Int, Int](f)
res0: scalaz.Kleisli[StringWriter,Int,Int] = Kleisli(<function1>)

Scalaz теперь предлагает более приятное решение с помощью "неприменимой уловки" Майлза Сабина:

val ff = Kleisli.kleisliU(f) >=> Kleisli.kleisliU(f)

kleisliU по сути, просто хорошая версия Kleisli.apply который использует новый тип класса (по имени Unapplyза кулисами, чтобы направить систему определения типа к правильному способу разделения WriterT[Id, String, Int],

Другие вопросы по тегам