Rich Hickey 在他的演讲“也许不是”中指出:
映射是(数学)函数!
在Clojure中,我们可以直接编写并调用
({:a 1:b 2}:b)=> 2
但是我觉得它们实际上不是一流的Clojure函数,或者是吗?
我可以使用关键字或其他方式调用地图:
user=> (:b {:a 1 :b 2 :c 3})
2
user=> ({:a 1 :b 2 :c 3} :b)
2
Run Code Online (Sandbox Code Playgroud)
但是我似乎无法使用Apply的任何一种方式:
user=> (apply #(:b %) {:a 1 :b 2 :c 3})
ArityException Wrong number of args (3) passed to: user/eval1762/fn--1763 clojure.lang.AFn.throwArity (AFn.java:429)
user=> (apply #({:a 1 :b 2 :c 3} %) :b)
IllegalArgumentException Don't know how to create ISeq from: clojure.lang.Keyword clojure.lang.RT.seqFrom (RT.java:542)
Run Code Online (Sandbox Code Playgroud)
而且我也不能直接将关键字应用于地图:
user=> (apply {:a 1 :b 2 :c 3} :b)
IllegalArgumentException Don't know how to create ISeq from: clojure.lang.Keyword clojure.lang.RT.seqFrom (RT.java:542)
Run Code Online (Sandbox Code Playgroud)
那么,它们是仅在数学意义上起作用,还是在应用类似于“正常” clojure函数的关键字意义上发挥更多作用?
就像您的前两个示例一样,映射是键的功能。地图实现的IFn接口就像“常规” Clojure函数一样。
apply在您的示例中不起作用的原因是由于在第二个位置传递了“序列”参数。
(apply #(:b %) {:a 1 :b 2 :c 3})
Run Code Online (Sandbox Code Playgroud)
在该示例中,地图参数正在变成键/值矢量/元组序列,因此它们可以被施加到#(:b %)(这不会无论如何工作,因为该匿名函数只需要一个参数)。这是地图变成序列并用作函数参数时的外观:
user=> (seq {:a 1 :b 2 :c 3})
([:a 1] [:b 2] [:c 3])
Run Code Online (Sandbox Code Playgroud)
第二个示例不起作用,因为:b它不是序列-它是一个关键字。这可以工作:
user=> (apply {:a 1 :b 2 :c 3} [:b])
2
Run Code Online (Sandbox Code Playgroud)
注意,使用apply和关键字序列调用map-as-function 并没有实际意义。
甲数学函数是一组有序对,使得不存在明显的对与相同的第一元件。这样定义的数学函数仅需一个参数。
Clojure映射是不言而喻的数学函数,因为不存在具有相同键的不同键/值对。此外,Clojure映射具有有限域(的集合keys)和范围/共域(的集合values)。
正如@TaylorWood所说,Clojure映射是Clojure函数,因为它们实现了clojure.lang.IFn。他们这样做是因为运算符会产生给定键的值,因此与其对数学函数的解释一致。
您的apply语法错误。你可以写
user=> (apply {:a 1, :b 2} [:a])
1
Run Code Online (Sandbox Code Playgroud)
要么
user=> (apply {:a 1, :b 2} :a [])
1
Run Code Online (Sandbox Code Playgroud)
您可以为该函数(的第一个参数apply)内联提供一些参数。其余部分是序列的最后一个参数apply。由于此处仅存在一个参数,因此我们可以在终端序列中将其内联或单独使用。
类似的考虑也适用于使用关键字作为参数。
回复@AlanThompson的评论
我已听过并阅读了该问题所指的Rich的演讲。我对函数的定义与他的一致。
我的说法“ 如此定义的数学函数仅需一个参数”,这显然是正确的。
您可以争辩说,我的定义不是传统的定义。但是,那是错误的。如果您阅读了我们都引用的Wikipedia文章的Multivariate_function部分,则会发现
更正式地说,n个变量的函数是一个域为n个元组的函数
...
使用函数符号时,通常会省略元组周围的括号,
f(x1 , x2)而不是f((x1 , x 2))。
换句话说,(数学)函数采用多个参数的想法是一种无害的非正式性,允许使用更简单的表示法。
那把编程语言留在哪里呢?它们中的大多数都具有任意Arity的功能:对于Clojure而言,任何有限的Arity集,包括无限的Arity。
考虑Clojure函数的最简单方法是,它们采用内联参数序列,也许是空参数。可以用这种方式来表达数学函数:从事物序列到事物的映射。但这并没有完成。