我参加了scala odersky课程并认为Flatmap作为参数的函数采用Monad元素并返回不同类型的monad。
trait M[T] {
def flatMap[U](f: T => M[U]): M[U]
}
在Monad M [T]上,函数的返回类型也是相同的Monad,类型参数U可能不同。
但是我在互联网上看过一些例子,这个函数返回一个完全不同的Monad。我的印象是返回类型的函数应该是同一个Monad。有人可以简化下面的内容来解释如何在实际值而不是列表中的选项中生成。[/ p>
列表不是Scala中的Monad。
val l= List(1,2,3,4,5)
def f(x:int) = if (x>2) Some(x) else None
l.map(x=>f(x))
//Result List[Option[Int]] = List( None , None , Some(3) , Some(4) , Some(5))
l.flatMap(x=>f(x))
//Result: List(3,4,5)
答案 0 :(得分:2)
让我们从M[T]
本身不是单身的事实开始。它是一个类型构造函数。当它与两个运算符关联时,它会变成monad:bind
和return
(或unit
)。这些运营商也必须满足monad法则,但为了简洁,我们省略它们。在Haskell中,bind
的类型是:
class Monad m where
...
(>>=) :: m a -> (a -> m b) -> m b
其中m
是一个类型构造函数。由于Scala是OO语言,bind
看起来像(第一个参数是self):
trait M[T] {
def bind[U](f: T => M[U]): M[U]
}
此处M === m
,T === a
,U === b
。 bind
通常称为flatMap
。在真空中的纯球形世界中,它将成为OO语言中flatMap
的标志。 Scala是一种非常实用的语言,因此flatMap
List
的真正签名是:
final def flatMap[B, That](f: (A) ⇒ GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
它不是bind
,但如果您以bind
的形式提供f
并且确保(A) => List[B]
,那么它将作为一元That
。 1}}是List[B]
。另一方面,如果您提供不同的内容,Scala不会留意您,但会尝试找到一些有意义的转换(例如CanBuildFrom
或其他内容)(如果存在)。
<强>更新强>
您可以使用scalac
标记(-Xlog-implicits
,-Xlog-implicit-conversions
)来查看正在发生的事情:
scala> List(1).flatMap { x => Some(x) }
<console>:1: inferred view from Some[Int] to scala.collection.GenTraversableOnce[?] via scala.this.Option.option2Iterable[Int]: (xo: Option[Int])Iterable[Int]
List(1).flatMap { x => Some(x) }
^
res1: List[Int] = List(1)
答案 1 :(得分:1)
嗯,也许是令人困惑的,你给的签名实际上并不正确,因为它真的(简化形式):
def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): Traversable[B]
由于编译器是开源的,你实际上可以看到它正在做什么(带有完整的签名):
def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
def builder = bf(repr) // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
val b = builder
for (x <- this) b ++= f(x).seq
b.result
}
因此,您可以看到实际上并不要求f
的返回类型与flatMap
的返回类型相同。
答案 2 :(得分:1)
标准库中的flatmap
是一种比一元绑定方法更通用,更灵活的方法,如Odersky的例子中的flatMap
。
例如,List上flatmap的完整签名是
def flatMap[B, That](f: (A) ⇒ GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
它不需要传递给flatmap的函数来返回List,而是能够返回任何GenTraversableOnce
对象,这是一种非常通用的类型。
flatmap然后使用隐式CanBuildFrom
机制来确定要返回的适当类型。
因此,当您使用带有返回List的函数的flatmap时,它是一个monadic绑定操作,但它也允许您使用其他类型。