Clojure中的mapcat和Scala中的flatMap在操作的对象上有哪些不同之处?

10

我知道在Scala中,flatMap的等价物是Clojure中的mapcat

我有一点猜想,在Clojure中,mapcat只能处理序列,而Scala中的flatMap更加灵活。

我的问题是:从它们所操作的内容来看,mapcat和Scala中的flatMap有什么区别?

假设:

  • 我知道Scala拥有丰富的类型系统,而Clojure则是可选类型 - 我想知道是否有限制了mapcat接受参数的能力,使其只具有flatMap的一部分功能。

1
在Clojure中,你认为集合意味着什么?就目前而言,“仅适用于集合”这个说法似乎非常奇怪,因为我无法想象mapcat(或者甚至是map)在不能被视为包含多个值的东西上会意味着什么。此外,map适用于像String这样的东西,它们不被认为是Clojure集合,以及所有集合类型。Clojure不是可选类型 - 静态类型检查是可选的(也不在核心语言中),但在Clojure中不存在未经类型标记的值。 - noisesmith
同意在Clojure中使用'collections' - 这是一个答案,我正在尝试了解更多关于它的含义,以便确定是否有什么我错过了:http://programmers.stackexchange.com/a/220150/13382 - hawkeye
任何对象都可以实现ISeq接口,这样就可以成为mapcat的目标。 这个人声称mapcat不使用协议是完全错误的100%。 mapcat是基于concat和map实现的,两者都在其参数上调用seq。 seq适用于任何实现ISeq的东西(对于不实现ISeq的Java本地对象有特殊情况)。 - noisesmith
1
@noisesmith 来自 http://clojuredocs.org/clojure_core/clojure.core/mapcat 的内容:"因此函数 f 应该返回一个集合。" - Alexey Romanov
3
“我无法想象对于一个无法被视为包含多个值的东西,‘mapcat’(或‘map’)会意味着什么。” 正是如此。 这是Clojure中“mapcat”和“map”的一部分含义,但不是Scala中“flatMap”和“map”的含义。 我并 是说Clojure做错了什么,比Scala更糟糕,它应该有一个名称来表示这些操作,因为Scala有,等等。 - Alexey Romanov
显示剩余6条评论
4个回答

5

我对Scala有一些了解,似乎flatMap是Scala单子(Monad)中的bind函数,而mapcat则是Clojure序列单子(sequence monad)的一种可能实现。因此,它们在序列方面是相同的。

但是,例如Scala还针对Futures提供了一个flatMap函数:它接受一个Future和一个映射函数,并返回一个在输入Future完成后将完成的Future。这个操作在Clojure中似乎不是一个简单的mapcat。它可以采用以下方式实现:

(defn flat-map [f mv] (mapcat (fn [v] (future (f @v))) mv))

所以,不一样,无论是在它们操作的方面还是在Scala中flatMap是不同函数的常用名称,例如Futures的flatMap协调输入和输出的futures。在Clojure中简单的mapcat不起作用,因为它不会返回future。


1
flatMap 是 List Monad 中的 bind 函数。不,flatMap 是所有 bind 函数在 Scala 中的通用名称。 - Alexey Romanov
@AlexeyRomanov 谢谢你,我根据你的评论编辑了我的答案。 - icamts

4
他们看起来非常相似,并且似乎处理同一种类型的事情。从文档和示例中(链接),我看不出有什么功能上的区别。 mapcat 适用于序列,而且几乎每种Clojure数据类型都可以是一个序列。如果你传递的参数不是一个 seq,它会自动调用seq,因此实际上你可以将几乎所有Clojure值传递给mapcat 。如果你想遍历树,则需要调用 prewalkpostwalk 来指定遍历顺序。

1
从文档和示例中看,我看不出有任何功能上的区别。请查看以下示例:http://docs.scala-lang.org/overviews/core/futures.html - Alexey Romanov

4

1
真正的区别在于flatMap对类型是多态的,而mapcat不是。因此,任何类型都可以决定提供类似于“flatMap”的行为。这就是你得到像Futures这样的可flatMap对象的方式。
在Clojure中,mapcat特定于seqable类型。任何seqable都可以被强制转换为序列,并且所有序列都可以映射和连接。mapcat实现将检查输入是否为seqable,如果是,则调用seq对其进行强制转换为序列,然后将映射和连接该序列并将其返回为序列。你不会得到原始类型的结果。
在Scala中,如果实现IterableLike trait(我认为这是正确的接口),则会获得默认的flatMap实现,它有点像Clojure的实现,但没有强制转换为序列。但是,许多类型还提供了自定义的flatMap实现,使其具有通用性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接