所有,我开始看看Clojure语言,并且对我正在尝试做的事情有几个问题。广泛的目标是将序列函数every?
别名为all?
。我确定有一个函数或宏可以进行别名(或者这些行中的某些内容)但是我想知道到目前为止我知道的一些基本结构是否可行。我的方法是定义一个名为all?
的函数,将其参数应用于every?
实现。
我很想知道这是否可以不可知,所以我想参数我的别名函数接受两个参数,新名称(作为关键字)和旧名称(作为函数引用)。在努力实现这一目标时,我遇到了两个问题。
1)使用关键字定义命名函数会引发错误。显然它想要clojure.lang.IObj
。
user=> (defn :foo "bar")
java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to clojure.lang.IObj (NO_SOURCE_FILE:0)
是否有将关键字强制转换为IObj的函数,或其他方法来使用一些提供的值来参数化新定义函数的名称? (在Ruby中,define_method和其他技术一样)
irb(main)> self.class.instance_eval do
irb(main)* define_method(:foo) { "bar" }
irb(main)> end
=> #<Proc>
irb(main)> foo
=> "bar"
2)将函数的所有参数收集到单个变量中。甚至像(+ 1 2 3 4)
这样的基本函数也会采用可变数量的参数。到目前为止,我所见过的所有函数定义技术都采用了特定数量的参数,没有办法只聚合列表中的所有内容以便在函数体中进行处理。再一次,我要用Ruby完成的事情是这样的:
irb(main)> def foo(*args)
irb(main)> p args
irb(main)> end
=> nil
irb(main)> foo(1, 2, 3)
[1, 2, 3]
=> nil
感谢您提供的任何帮助!
答案 0 :(得分:17)
我将在要点中回答,因为这些问题可以整齐地分成若干单独的问题。
隐含在后续内容中的东西,但也许保证了它自己的子弹:由def
&amp;创建的顶级对象。公司(特别是defn
)是Vars。所以你真正想做的是别名 Var ;函数只是常规值,它们实际上没有名称(除非它们可能在其身体内部本地绑定了一个名称;但这与手头的问题无关)。
Clojure确实有一个“别名宏” - clojure.contrib.def/defalias
:
(use '[clojure.contrib.def :only [defalias]])
(defalias foo bar)
; => foo can now be used in place of bar
这优于(def foo bar)
的优点是它复制了元数据(例如docstring);它甚至似乎与当前HEAD中的宏一起使用,尽管我记得在早期版本中出现了一个阻止它的错误。
Vars以符号命名,而非关键字。 Clojure(和其他Lisps)中的符号文字不以冒号开头(:foo
是关键字,而不是符号)。因此,要定义一个名为foo
的函数,您应该编写
(defn foo [...] ...)
defn
是一个辅助宏,通过允许程序员使用def
&amp;的混合,轻松创建 new 函数保持Vars。 fn
语法。所以defn
对于创建具有预先存在的值(可能是函数)的Vars是不可能的,这是创建别名所必需的;请改为使用defalias
或简称def
。
要创建可变参数函数,请使用以下语法:
(fn [x y & args] ...)
x
和y
将是必需的位置参数;传递给函数的其余参数(任意数量的参数)将被收集到seq中,并以名称args
提供。如果不需要,您不必指定任何“必需的位置参数”:(fn [& args] ...)
。
要创建包含可变参数函数的Var,请使用
(defn foo [x y & args] ...)
要将函数应用于某些参数,您已将其组合成一个seqable对象(例如上面示例中的args
seq或者vector&amp; c。),请使用{{1 }}:
apply
如果您想编写函数来创建别名 - 而不是宏 - 您需要调查函数(defn all? [& args]
(apply every? args))
,{{1} },intern
- 可能with-meta
/ meta
,具体取决于函数是接受符号还是Vars。我将把细节作为练习留给读者。 : - )
答案 1 :(得分:6)
您需要做的就是绑定每一个?功能全部?符号,通过def完成:
(def all? every?)
答案 2 :(得分:3)
不要认为我可以在这里添加很多现有的解释,除非在Ruby旅行者的字典中填写关于参数收集和解构的几个空白:
(defn foo [& args] ; Ruby: def foo(*args)
(println args))
user=> (foo 1 2 3)
(1 2 3)
(defn foo [& args]
(+ args))
user=> (foo 1 2 3)
java.lang.ClassCastException ; + takes numbers, not a list
(defn foo [& args]
(apply + args)) ; apply: as Ruby proc.call(*args)
user=> (foo 1 2 3)
6
(defn foo [& args]
(let [[a b & other] args] ; Ruby: a, b, *other = args
(println a b other)))
user=> (foo 1 2 3)
1 2 (3)