2015-09-21 7 views
0

Я работаю через learning scalaz и Learn You A Haskell For Greater Good и задаюсь вопросом, как перевести пример filterM из LYAHFGG в Scala.Scalaz Writer Monad and filterM

fst $ runWriter $ filterM keepSmall [9,1,5,2,10,3]

с keepSmall определяется как

keepSmall :: Int -> Writer [String] Bool 
keepSmall x 
    | x < 4 = do 
     tell ["Keeping " ++ show x] 
     return True 
    | otherwise = do 
     tell [show x ++ " is too large, throwing it away"] 
     return False 

Мой наивный подход заканчивается с ошибками компиляции, и я понятия не имею, как идти вокруг этого вопроса!

val keepSmall: (Int => WriterT[Id, Vector[String], Boolean]) = (x: Int) => 
     if (x < 4) for { 
     _ <- Vector("Keeping " + x.shows).tell 
     } yield true 
     else for { 
     _ <- Vector(x.shows + " is too large, throwing it away").tell 
     } yield false 

println(List(9,1,5,2,10,3) filterM keepSmall) 

Ошибки компиляции:

Error:(182, 32) no type parameters for method filterM: (p: Int => M[Boolean])(implicit evidence$4: scalaz.Applicative[M])M[List[Int]] exist so that it can be applied to arguments (Int => scalaz.WriterT[scalaz.Scalaz.Id,Vector[String],Boolean]) 
--- because --- 
argument expression's type is not compatible with formal parameter type; 
found : Int => scalaz.WriterT[scalaz.Scalaz.Id,Vector[String],Boolean] 
required: Int => ?M[Boolean] 
    println(List(9,1,5,2,10,3) filterM keepSmall) 
          ^

и

Error:(182, 40) type mismatch; 
found : Int => scalaz.WriterT[scalaz.Scalaz.Id,Vector[String],Boolean] 
required: Int => M[Boolean] 
    println(List(9,1,5,2,10,3) filterM keepSmall) 
            ^

ответ

1

Проблема связана с тем, что Scala не могу знать, как соответствовать типу с тремя отверстиями INTO аргумент, ожидаемый filterM, который имеет только одно отверстие , заполненное Boolean.

Вы могли бы решить вашу проблему с помощью какой-то странный тип-лямбда синтаксис вроде этого (не проверял, может не работать):

val keepSmall: (Int => ({type L[T] = WriterT[Id, Vector[String], T]})#L) = ... 

или (гораздо проще) путем введения типа псевдоним следующим образом:

type MyWriter[T] = WriterT[Id, Vector[String], T] 
val keepSmall: (Int => MyWriter[Boolean]) = ... 

Это позволит убедиться, что аргумент, ожидаемый filterM, соответствует типу аргумента, который вы предоставляете.

+0

Вторая вещь, спасибо! Первый не компилируется - попытался это исправить, но мои знания слишком ограничены. Вот обратный вопрос: http://stackoverflow.com/questions/8736164/what-are-type-lambdas-in-scala-and-what-are-their-benefits Я думаю, быть доступным и в Haskell, но не в конкретном примере Writer, не так ли? http://stackoverflow.com/questions/4069840/lambda-for-type-expressions-in-haskell – mjaskowski

+0

Я мало знаю о том, как Haskell справляется с этим, но я подозреваю, что он немного более гибкий, когда частично применяя типы с несколькими параметрами. Я хотел бы знать, что такое отказ для типа лямбда. –