4

map接受一个函数和一个列表,并将该函数应用于列表的每个元素。例如,

(map f [x1 x2 x3])
;= [(f x1) (f x2) (f x3)]

在数学上,列表是自然数 ℕ 的偏函数。如果x : ℕ → X是某个列表,而f : XY是某个函数,则 map 将 ( f , x ) 对到列表 f○x : ℕ → Y。因此,map 和 comp 返回相同的值,至少在简单的情况下如此。

但是,当我们使用多个参数应用 map 时,会发生更复杂的事情。考虑这个例子:

(map f [x1 x2 x3] [y1 y2 y3])
;= [(f x1 y1) (f x2 y2) (f x3 y3)]

在这里,我们有两个列表x : ℕ → Xy : ℕ → Y具有相同的域,以及类型为f : X → ( YZ ) 的函数。为了评估元组 ( f , x , y ),map 必须在幕后做更多的工作。

首先,map 构造对角积列表 diag( x , y ):ℕ → X × Y,由 diag( x , y )(n) = ( x (n), y (n)) 定义。

其次,map uncurry 函数为 curry -1 ( f ) : X × YZ。最后,map 组合这些操作得到 curry -1 (f) ○ diag( x , y ) : ℕ → Z

我的问题是:这种模式可以概括吗?也就是说,假设我们有三个列表x : ℕ → Xy : ℕ → Yz : ℕ → Z,以及一个函数f : X → ( Y → ( ZW )))。map 是否将元组 ( f , x , y , z ) 发送到列表 curry -2 (f) ○ diag( x , y , z ) : ℕ → W

4

3 回答 3

6

似乎问题标题与正文中实际提出的问题无关;我会尝试解决这两个问题。

Clojure 方面

正如(map inc [1 2 3])和之类的例子所证明的那样(comp inc [1 2 3])——顺便说一句,这两个例子在 Clojure 中都非常有意义——即使在一个序列的情况下,Clojure 的功能map和操作也完全不同。根本不将其序列参数视为可调用对象的软件意义上的函数,而是以这种方式处理其所有参数;返回复合数据,而不返回;的返回值可以作为函数调用,而的返回值不是;等等compmapcompmapcompcompmap

(其他函数式语言类似地具有单独的“map”和“compose”高阶函数;在 Haskell 中,它们是map(以及更通用的fmap)和(.)。)

值得注意的是,map它没有对其输入函数执行实际的内存元组化,并且不对输入函数应用任何 deschönfinkelizing / uncurrying 转换。

数学方面

该模式当然可以很好地概括,但值得记住的是,什么是什么等的函数 - 在模型的底层,可以说 - 取决于往往是任意的表示的选择。有限序列可以完美地表示为具有有限序数作为域的(总)函数,或者作为 Kuratowski 元组,或者以您描述的方式,您不关心您的列表不一定是“无间隙”等。取决于表示选择,自然数的概念可能根本不会出现,表示列表的对象可能看起来也可能不像函数,其 codomain 是列表条目集合的超集等。

于 2013-09-17T19:27:20.873 回答
3

我不知道它是否有帮助,但是:

  • Clojure 没有像 Haskell 那样的柯里化。它确实有部分函数应用,但它与柯里化不同。
  • Clojure 的 map 更像是 Haskell 中的 zipWith、zipWith3 等
于 2013-09-17T18:11:56.067 回答
1

从技术上讲是的,map 可以被视为这样的组合函数,尽管在实践中它引入了一些 comp 没有的开销。

map生成一个惰性序列,该序列将在最终读取结果时计算一个序列。因此,它返回的序列并非严格意义上的类型表达式所暗示的结果。它还增加了序列的开销并更改了评估顺序,因为它是惰性的和分块的。

于 2013-09-17T18:14:28.987 回答