繁体   English   中英

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

[英]Comparing Haskell and Scala Bind/Flatmap Examples

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

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

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

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

Haskell的>>=签名是:

>>= :: Monad m => ma -> (a -> mb) -> mb

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

为什么Scala代码会编译?

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

final def flatMap[B, That](f: (A) ⇒ GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That

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

final def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): List[B]

只有一个问题, Option不是GenTraversableOnce子类,这里有一个隐式转换GenTraversableOnce定义了从OptionIterable的隐式转换,它是Traversable的子类,它是GenTraversableOnce的子类。

implicit def option2Iterable[A](xo: Option[A]): Iterable[A]   

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

查看隐式工作的更简单方法是为Iterable val分配一个Option

scala> val i:Iterable[Int] = Some(1)
i: Iterable[Int] = List(1)

Scala使用一些默认规则,选择List作为Iterable的实现。

您可以将TraversableOnce不同子类型与monad操作组合在一起,这一事实来自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)
  }

这会使用上述方法增强每个TraversableOnce 子类型可以自由地定义更高效的版本,这些将影响隐式定义。 List就是这种情况。

引用List的Scala引用

final def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): List[B] 

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM