比较Haskell和Scala绑定/平面地图示例 [英] Comparing Haskell and Scala Bind/Flatmap Examples

查看:139
本文介绍了比较Haskell和Scala绑定/平面地图示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的 bind(>> =)代码在Haskell中不能编译:

  ghci> [[1]]>> =只是
<互动>:38:11:
无法将类型'Maybe'与'[]'
匹配期望类型:[t ] - > [[t]]
实际类型:[t] - >也许[t]
在'(> =)'的第二个参数中,即'Just'
在表达式中:[[1]]>> = Just

但是,在Scala中,它实际上是编译和运行的:



< pre class =lang-scala prettyprint-override> scala> List(List(1)).flatMap(x => Some(x))
res1:List [List [Int]] = List(List(1))

Haskell的>> = 签名是:

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



因此,在 [[1]]>> = f f 的类型应该是: a - > [b]



为什么要编译Scala代码?

解决作为@chi解释Scala的 flatMap 比Haskell的>> = 。 Scala文档的完整签名是:
$ b $ pre $ final def flatMap [B,That](f:(A)⇒GenTraversableOnce [ (b):隐式bf:CanBuildFrom [List [A],B,That]):那

这个隐含的内容与这个特定的问题无关,所以我们可以使用更简单的定义:

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

一个问题, Option 不是 GenTraversableOnce 的子类,这里有一个隐式转换。Scala定义了一个隐式转换, code>选项 Iterable 它是 Traversable 的一个子类,它是一个 GenTraversableOnce

 隐式def option2Iterable [A](xo:选项[A]):Iterable [A] 

隐式定义在< c $ c> Option 。



一个简单的wa y看到在工作中隐含的是将一个 Option 赋给一个 Iterable val

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

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



您可以将 TraversableOnce 的不同子类型与monad操作相结合,这个事实来自隐式类 code> MonadOps

 隐式类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


的情况

The following bind(>>=) code, in Haskell, does not compile:

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

But, in Scala, it does actually compile and run:

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

Haskell's >>= signature is:

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

So, in [[1]] >>= f, f's type should be: a -> [b].

Why does the Scala code compile?

解决方案

As @chi explained Scala's flatMap is more general than the Haskell's >>=. The full signature from the Scala docs is:

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

This implicit isn't relevant for this specific problem, so we could as well use the simpler definition:

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

There is only one Problem, Option is no subclass of GenTraversableOnce, here an implicit conversion comes in. Scala defines an implicit conversion from Option to Iterable which is a subclass of Traversable which is a subclass of GenTraversableOnce.

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

The implicit is defined in the companion object of Option.

A simpler way to see the implicit at work is to assign a Option to an Iterable val:

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

Scala uses some defaulting rules, to select List as the implementation of Iterable.

The fact that you can combine different subtypes of TraversableOnce with monad operations comes from the 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)
  }

This enhances every TraversableOnce with the methods above. The subtypes are free to define more efficient versions on there own, these will shadow the implicit definitions. This is the case for List.

这篇关于比较Haskell和Scala绑定/平面地图示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆