【问题标题】:How to pass "applied function" as a parameter in Common Lisp如何在 Common Lisp 中将“应用函数”作为参数传递
【发布时间】:2019-05-10 20:57:41
【问题描述】:

我是 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

【问题讨论】:

    标签: clojure lisp common-lisp


    【解决方案1】:

    我不确定我是否正确理解了您的问题,但可能是这样的:

    (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)
    

    【讨论】:

    • 谢谢,你明白了,这就是我想要的。所以让它紧凑的是 Clojure 的语法糖,但使用 lambda 确实比我做的方式更清晰。
    • @PedroQueiroga 请参阅 github.com/cbaggers/fn 了解现有的更短的匿名函数语法(但请记住来自 Rainer Joswig 的警告)
    【解决方案2】:

    虽然 Daniels 的回答很完美,但我想指出 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)
    

    【讨论】:

      【解决方案3】:

      剩余参数

      也可以写成

      (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)
      

      风格

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-12
        • 1970-01-01
        • 1970-01-01
        • 2022-11-10
        • 2011-07-26
        • 2021-02-15
        相关资源
        最近更新 更多