我曾经在 Haskell 中编写嵌套的辅助函数(顺便说一句,偶尔使用外部函数的参数并且是递归的),如下所示(loop
):
sum a b = let
loop s i = if i > b then s else loop (s + i) (i + 1)
in loop 0 a
Common Lisp 中最清晰的类比是什么?
我在这里四处搜索,发现一些讨论集中在从函数返回函数(以及尝试调用此类“返回”函数时可能出现的问题),据我所知,情况并不完全相同。
我曾经在 Haskell 中编写嵌套的辅助函数(顺便说一句,偶尔使用外部函数的参数并且是递归的),如下所示(loop
):
sum a b = let
loop s i = if i > b then s else loop (s + i) (i + 1)
in loop 0 a
Common Lisp 中最清晰的类比是什么?
我在这里四处搜索,发现一些讨论集中在从函数返回函数(以及尝试调用此类“返回”函数时可能出现的问题),据我所知,情况并不完全相同。
标签用于定义局部函数。
CL-USER> (defun thing (x)
(labels ((helper (y) (loop for i from x to y collect i)))
(helper 5)))
THING
CL-USER> (thing 1)
(1 2 3 4 5)
它有点像函数的 let* 语句,因为您可以定义多个本地函数。所以在这里我们定义了 helper 和 double-it。
(defun thing (x)
(labels ((helper (y) (loop for i from x to y collect i))
(double-it (num) (* 2 num)))
(helper (double-it 10))))
你也可以使用 lambdas。在这种情况下,它相当整洁,尽管在这种情况下我仍然更喜欢标签的可读性。
CL-USER> (defun another-test (x)
(funcall #'(lambda (y) (loop for i from x to y collect i)) 10))
ANOTHER-TEST
CL-USER> (another-test 2)
(2 3 4 5 6 7 8 9 10)
标签也可以递归使用:
CL-USER> (defun test-recurse (x)
(labels ((rec-list (count)
(when (< count x)
(cons count (rec-list (+ 1 count))))))
(rec-list 0)))
TEST-RECURSE
CL-USER> (TEST-RECURSE 10)
(0 1 2 3 4 5 6 7 8 9)
希望能帮助到你!
就像玩“愚蠢的 Lisp 技巧”一样,我要指出,在 Scheme 中,类似于
sum a b = let
loop s i = if i > b then sum else loop (s + i) (i + 1)
in loop 0 a
是 letrec 或命名的 let:
(define (sum a b)
(letrec ((loop (lambda (s i)
(if (> i b)
s
(loop (+ s i) (+ i 1))))))
(loop 0 a)))
(define (sum a b)
(let loop ((s 0) (i a))
(if (> i b)
s
(loop (+ s i) (+ i 1)))))
Letrec,因为 Scheme 是一个 Lisp-1,为您提供了Baggerslabels
所描述的功能。命名的 let 可以在 Common Lisp 中使用宏来完成labels
:
(defmacro named-let (name bindings &body body)
`(labels ((,name ,(mapcar 'first bindings)
,@body))
(,name ,@(mapcar 'second bindings))))
(pprint (macroexpand
'(named-let loop ((s 0) (i a))
(if (> i b)
s
(loop (+ s i) (+ i 1))))))
;; (LABELS ((LOOP (S I)
;; (IF (> I B)
;; S
;; (LOOP (+ S I)
;; (+ I 1)))))
;; (LOOP 0 A))
然而,尾调用不一定在 Common Lisp 中被优化掉,所以这种迭代的递归并不是那么常见。迭代模拟是do
:
(defun sum (a b)
(do ((s 0 (+ s i))
(i a (+ i 1)))
((> i b) s)))
你也可以使用loop
,但它有点冗长(但如果你熟悉的话,也可能更具可读性do
:
(defun sum (a b)
(loop
for s = 0 then (+ s i)
for i = a then (+ i 1)
when (> i b) return s))