如何在Common Lisp中将“应用功能”作为参数传递

时间:2019-05-10 20:57:41

标签: clojure lisp common-lisp

我是Common Lisp的新手,正在尝试从Clojure实现repeatedly。例如

(repeatedly 5 #(rand-int 11))

这将收集5个(rand-int 11)调用,并返回一个列表: (10 1 3 0 2)

当前,这是我正在做的:

(defun repeatedly (n f args)
  (loop for x from 1 to n
       collect (apply f args)))

看起来不太好,我必须这样称呼:(repeatedly 5 #'random '(11))。有没有办法像Clojure的语法那样使函数更直观?

然后,代码可能会变得很丑陋:(repeatedly 5 #'function (list (- x 1)))

https://clojuredocs.org/clojure.core/repeatedly

3 个答案:

答案 0 :(得分:6)

我不确定我是否正确理解了您的问题,但也许仅仅是这样:

(defun repeatedly (n function)
  (loop repeat n collect (funcall function)))

因为#(…)只是Clojure中lambda的简写。

CL-USER> (repeatedly 5 (lambda () (random 11)))
(0 8 3 6 2)

但这甚至更短:

CL-USER> (loop repeat 5 collect (random 11))
(5 4 6 2 3)

答案 1 :(得分:6)

尽管丹尼尔斯回答完美,但我想指出关于CL的一个很酷的问题。您可以实现与Clojure类似的阅读器宏。现在,由于#(1 2 3)是CL中的数组文字,因此我将同时实现具有[...][...]功能的#(...)

(set-macro-character #\[
  (lambda (stream char)
    (declare (ignore char))
    (let ((body (read-delimited-list #\] stream t)))
      `(lambda (&optional %1 %2 %3 %4 %5 &aux (_ %1)) ,body))))

(set-macro-character #\]
  (get-macro-character #\)))

我没有花时间搜索%s_,所以它不是最佳选择。以下是一些示例:

(mapcar [sqrt (+ (* %1 %1) (* %2 %2))] '(1 3 5) '(2 4 6))
; ==> (2.236068 5 7.81025)
(mapcar [* _ 2] '(2 4 6))    
; ==> (4 8 12)
(repeatedly 5 [rand-int 11]) 
; ==> (10 1 3 0 2)

答案 2 :(得分:6)

其他参数

一个人也可以写成

(defun repeatedly (n f &rest args)
  (loop repeat n collect (apply f args)))

因此无需自己创建参数列表。

然后称之为:

> (repeatedly 5 #'random (1- x))
(7 2 3 1 4)

代替(repeatedly 5 #'random (list (1- x)))

通过宏缩写的符号

出于某些目的,也可以通过宏实现短的lambda表示法:

> (defun repeatedly (n function)
    (loop repeat n collect (funcall function)))
REPEATEDLY

> (repeatedly 5 (lambda () (random 10)))
(1 7 1 7 8)

> (defmacro ⧨ (&body body) `(lambda () ,@body))
⧨

> (repeatedly 5 (⧨ (random 10)))
(9 3 0 7 0)

or alternatively:

> (defmacro ⧩ (&body body) `(lambda () ,body))
⧩

> (repeatedly 5 (⧩ random 10))
(9 7 7 7 5)

样式

通常也没有必要,也不希望将语言结构编写为 reader宏。最好将s-expressions的扩展名留在编程语言级别以下-> s-expressions主要是一种数据语法。

在大多数Lisp代码中,实际上可以找到使用的lambda表达式而没有任何缩写。通常的Lisp风格是使用符号名称,而不使用太多特殊字符或特殊词法/令牌语法。它使文本稍长,但具有其他优点。例如,人们在文字,阅读甚至运行的代码中看到相同的lambda ...