What are the differences between mapcat in Clojure and flatMap in Scala in terms of what they operate on?
我了解Scala中flatMap的等效项是Clojure中的mapcat。
我有种种暗示,clojure中的mapcat仅适用于序列,而Scala中的flatMap更灵活。
我的问题是-Clojure中的mapcat和Scala中的flatMap之间的区别是什么?
假设:
-
我知道Scala具有丰富的类型系统,而Clojure具有可选的类型-我想知道mapcat接受的参数是否受限制,从而使其仅具有flatMap s功能的子集。
-
您认为集合在Clojure中意味着什么?就目前而言,"仅对集合有效"的陈述似乎非常奇怪,因为我无法想象mapcat(甚至map)在不能被视为包含多个值的事物上意味着什么。 map还可以处理不被视为clojure集合的String之类的东西,以及所有集合类型。 Clojure不是可选的类型-静态类型检查是可选的(并且不是核心语言),但是clojure中没有未类型化的值。
-
同意Clojure中的关于回收的信息-这是一个答案,我试图找出更多有关万一我错过的东西的含义:programmers.stackexchange.com/a/220150/13382
-
任何对象都可以实现ISeq,然后将成为mapcat的目标。期。他关于mapcat不使用协议的断言完全是100%错误的。 mapcat是根据concat和map来实现的,它们都在其args上调用seq。 seq适用于任何实现ISeq的东西(对于不实现ISeq的Java本机对象有特殊情况)。
-
如果我看了一下Scala,我确信我可以根据无根据的假设(Scala的行为应像clojure一样)做出同样无知的主张。
-
来自clojuredocs.org/clojure_core/clojure.core/mapcat的@noisesmith:"因此,函数f应该返回一个集合。"
-
@noisesmith"我无法想象mapcat(甚至地图)对不能被视为包含多个值的东西意味着什么"。它是Clojure中mapcat和map含义的一部分,但不是Scala中flatMap和map含义的一部分。我并不是说Clojure做错了任何事情,比Scala更糟糕,因为Scala这样做,它应该为这些操作起一个名字,等等。
-
此处的区别可能是,在clojure中,我们喜欢Sequence抽象,因此,即使像Strings,Records之类的东西或对重复操作(如itateate)的抽象也都可用作序列。在我看来,在clojure中说一些"仅对集合有效"就像在说"第四种"仅对依赖于机器的字节值有效。它是通用语言,如果我们想对它做任何有趣的事情,我们都会将其变成所有语言(甚至由于同源,我们的代码也是如此)。
-
可以肯定,我可能会缺少有关Scala语义的一些微妙之处。我担心我在这里表现得像" blub"程序员一样,争论着我尚不了解的功能。
-
谢谢noisesmith-我已经更新了问题收藏
-
感谢@noisesmith的有用反馈-您能否对@Alexys的以下答案发表评论,以确定它是否有效或有改善的机会?
-
@noisesmith"即使像字符串,记录之类的东西,或对诸如迭代之类的重复操作的抽象,也都可以作为序列使用……它是一种通用语言,如果我们想对它做任何有趣的事情,我们就会将其变成所有东西。"期货还是core.async渠道?
我对Scala有点了解,但在我看来,flatMap是monad中的Scala绑定函数,而mapcat是Clojure中序列monad的bind函数的可能实现。因此,它们对于序列是相同的。
但是,例如,Scala具有Futures的flatMap函数:它接受一个Future和一个映射函数,并返回一个Future,该Future将在输入Future完成后完成。在Clojure中,此操作似乎不是简单的地图猫。可以这样实现
1
| (defn flat-map [f mv] (mapcat (fn [v] (future (f @v))) mv)) |
所以不行。它们的作用不同,也不相同。在Scala中,flatMap是不同功能的通用名称,例如Futures的flatMap协调输入和输出期货。 Clojure中的简单mapcat无法使用,因为它不会返回未来。
-
" flatMap是List monad中的绑定函数"否,flatMap是所有bind函数的通用Scala名称。
-
@AlexeyRomanov谢谢,我根据您的评论编辑了答案。
在标准Scala库中:Responder,Future,Parser,ControlContext。它们都不是序列或特别是序列样的。 ParseResult也有轻微变化。
它们看起来非常相似,并且似乎在相同的事物上工作。通过查看文档和示例,我看不到功能上的差异。
mapcat适用于序列,几乎每种clojure数据类型都可以是序列。如果将尚未为seq传递给mapcat的东西传递给它,它将自动对其调用seq,因此实际上,您可以将几乎所有clojure值传递给mapcat。如果要遍历树,则需要调用prewalk或postwalk以指定遍历顺序。
-
"通过查看文档和示例,我看不到功能上的差异。" 请参阅以下示例:docs.scala-lang.org/overviews/core/futures.html
真正的区别是flatMap在类型上是多态的,而mapcat不是。因此,任何类型都可以决定提供类似行为的" flatMap"。这就是您获得诸如Futureflatableable之类的东西的方式。
在Clojure中,mapcat特定于可排序类型。可以将任何可序列化的序列强制转换为一个序列,并且可以映射和连接所有序列。 mapcat实现将检查输入是否可排序,如果是,它将在其上调用seq以将其强制为一个序列,然后它将对该序列进行映射和分类并将其归还给您。您不会得到原始类型的结果。
在Scala中,如果实现IterableLike特质(我认为这是正确的接口),则将获得默认的flatMap实现,有点像Clojure减去强制序列化。但是,许多类型还提供了flatMap的自定义实现,以这种方式使其具有通用性。