比较Haskell和Scala绑定/平面图示例

Kev*_*ith 16 haskell scala

bind(>>=)Haskell中的以下代码无法编译:

ghci> [[1]] >>= Just
<interactive>:38:11:
    Couldn't match type ‘Maybe’ with ‘[]’
    Expected type: [t] -> [[t]]
      Actual type: [t] -> Maybe [t]
    In the second argument of ‘(>>=)’, namely ‘Just’
    In the expression: [[1]] >>= Just
Run Code Online (Sandbox Code Playgroud)

但是,在Scala中,它确实编译并运行:

scala> List( List(1) ).flatMap(x => Some(x) )
res1: List[List[Int]] = List(List(1))
Run Code Online (Sandbox Code Playgroud)

Haskell的>>=签名是:

>>= :: Monad m => m a -> (a -> m b) -> m b

所以,在[[1]] >>= f,f类型应该是:a -> [b].

为什么Scala代码会编译?

bma*_*her 20

正如@chi解释的那样,Scala flatMap比Haskell更普遍>>=.Scala文档的完整签名是:

final def flatMap[B, That](f: (A) ? GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
Run Code Online (Sandbox Code Playgroud)

这隐含与此特定问题无关,因此我们也可以使用更简单的定义:

final def flatMap[B](f: (A) ? GenTraversableOnce[B]): List[B]
Run Code Online (Sandbox Code Playgroud)

只有一个问题,Option没有子类GenTraversableOnce,这里有一个隐式转换.Scala定义了一个隐式转换Option,Iterable其子类Traversable是其子类GenTraversableOnce.

implicit def option2Iterable[A](xo: Option[A]): Iterable[A]   
Run Code Online (Sandbox Code Playgroud)

隐式是在伴随对象中定义的Option.

查看隐含工作的更简单方法是将a分配OptionIterable val:

scala> val i:Iterable[Int] = Some(1)
i: Iterable[Int] = List(1)
Run Code Online (Sandbox Code Playgroud)

Scala使用一些默认规则来选择List作为执行Iterable.

您可以将TraversableOncemonad操作的不同子类型组合在一起的事实来自implicit class MonadOps:

  implicit class MonadOps[+A](trav: TraversableOnce[A]) {
    def map[B](f: A => B): TraversableOnce[B] = trav.toIterator map f
    def flatMap[B](f: A => GenTraversableOnce[B]): TraversableOnce[B] = trav.toIterator flatMap f
    def withFilter(p: A => Boolean) = trav.toIterator filter p
    def filter(p: A => Boolean): TraversableOnce[A] = withFilter(p)
  }
Run Code Online (Sandbox Code Playgroud)

这通过TraversableOnce上述方法增强了每一种方法.子类型可以自由地定义更高效的版本,这些将影响隐式定义.情况就是如此List.

  • 它只为"List","Vector"和其他类似的类型定义了这种方式.另一方面,`Option`有一个简单的`flatMap`,如你所料:`final def flatMap [B](f:(A)⇒选项[B]):选项[B]` (2认同)

chi*_*chi 11

引用Scala引用 List

final def flatMap[B](f: (A) ? GenTraversableOnce[B]): List[B] 
Run Code Online (Sandbox Code Playgroud)

因此,flatMap它比Haskell更通用(>>=),因为它只需要映射函数f来生成可遍历类型,不一定是a List.