2013-11-17 3 views
5

Работая на другое упражнение для реализации Monad.sequence() от Functional Programming in Scala, моего ответа отличается от официального/известно, чтобы быть правильным ответ:Реализация `sequence` на Монадах

def sequence[A](lma: List[F[A]]): F[List[A]]

Official:

def sequence[A](lma: List[F[A]]): F[List[A]] = 
    lma.foldRight(unit(List[A]()))((ma, mla) => map2(ma, mla)(_ :: _)) 

Mine:

def sequence[A](lma: List[F[A]]): F[List[A]] = F(lma.flatten)

Пример где F является Option:

scala> val x: List[Option[Int]] = List(Some(1), None) 
x: List[Option[Int]] = List(Some(1), None) 

scala> Some(x.flatten) 
res1: Some[List[Int]] = Some(List(1)) 

Является ли мой ответ (или дух его) законным здесь?

Я получаю следующее исключение для компиляции, но я уверен, связано ли это с моим отсутствием понимания конструкторов типов.

Monad.scala:15: error: not found: value F
F(lma.flatten)

ответ

5

Когда вы пишете Option(1), что на самом деле происходит то, что вы звоните в apply метод объекта Option компаньона. Это очень косвенно связано с типом Option, в общем случае вообще нет способа получить объект-компаньон Something (который является значением), если у вас есть только переменная типа, относящаяся к типу Something. На самом деле нет гарантии, что объект-компаньон даже существует, и даже если он существует, его метод apply может возвращать то, что полностью не является экземпляром типа Something. Тот факт, что X.apply(...) действительно возвращает X в случае List и Option, а классы корпусов - это вопрос конвенции.

Другая часть проблемы здесь - звонок List.flatten. Если вы посмотрите на «Full сигнатура» flatten в the docs, вы увидите, что она имеет неявный аргумент:

def flatten[B](implicit asTraversable: (A) => GenTraversableOnce[B]): List[B] 

Это означает, что вы можете использовать его только на List[A] если A может быть неявно преобразован в a GenTraversableOnce. Это вообще не так для любой старой монады.

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

+0

Спасибо, Тревис. Я всегда узнаю из ваших ответов. В качестве побочного вопроса, почему здесь используется 'foldRight' вместо' foldLeft'? –

+0

Спасибо! И я не совсем уверен в 'foldRight' здесь. В некотором смысле 'foldRight' проще, чем' foldLeft', поскольку вы можете думать об этом как о замене оператора cons предоставленной функцией и пустым списком с предоставленным начальным значением. И учитывая соответствующее нестрогое определение, 'foldRight' можно использовать в бесконечных списках (или потоках), тогда как' foldLeft' не может. –

+0

В качестве продолжения, как «foldRight», но не 'foldLeft', использоваться в бесконечном списке/потоке, если он реализован в терминах foldLeft? http://stackoverflow.com/questions/19547976/list-foldright-always-using-foldleft –