首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >CL中的助手嵌套函数

CL中的助手嵌套函数
EN

Stack Overflow用户
提问于 2013-10-23 07:05:34
回答 2查看 3.9K关注 0票数 5

我曾经在Haskell (loop)中编写嵌套的助手函数(顺便说一句,它是外部函数的局部使用的参数,并且是递归的):

代码语言:javascript
运行
复制
sum a b = let
  loop s i = if i > b then s else loop (s + i) (i + 1)
  in loop 0 a

在通用Lisp中,最清晰的模拟是什么?

我在这里搜索,发现一些讨论集中在从函数返回函数(以及试图调用这些“返回”函数时可能出现的问题),据我所见,情况与此不完全相同。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-10-23 07:07:55

Labels用于定义本地函数。

代码语言:javascript
运行
复制
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*语句,因为您可以定义多个本地函数。在这里,我们有助手和双-它被定义。

代码语言:javascript
运行
复制
(defun thing (x)
   (labels ((helper (y) (loop for i from x to y collect i))
            (double-it (num) (* 2 num)))
     (helper (double-it 10))))

你也可以用兰巴达。在这种情况下,这是相当整洁的,尽管在这种情况下,我仍然更喜欢标签的可读性。

代码语言:javascript
运行
复制
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)

标签也可以递归地使用:

代码语言:javascript
运行
复制
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)

希望能帮上忙!

票数 9
EN

Stack Overflow用户

发布于 2013-10-23 13:18:10

标签和命名让如果您的Lisp优化尾调用

就像玩“愚蠢的Lisp把戏”一样,我要指出的是,在Scheme中,

代码语言:javascript
运行
复制
sum a b = let
  loop s i = if i > b then sum else loop (s + i) (i + 1)
  in loop 0 a

是letrec或命名let:

代码语言:javascript
运行
复制
(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,所以它为您提供了labels的功能,即Baggers described。命名的let可以在Common中使用围绕labels的宏完成

代码语言:javascript
运行
复制
(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))

Do和Do*在任何地方都应该是有效的

但是,在common中,尾调用并不一定是优化的,因此这种迭代的递归并不是很常见。迭代模拟是do

代码语言:javascript
运行
复制
(defun sum (a b)
  (do ((s 0 (+ s i))
       (i a (+ i 1)))
      ((> i b) s)))

循环也能工作。

您也可以使用loop,但它更冗长(但如果您熟悉do,也可能更易读)

代码语言:javascript
运行
复制
(defun sum (a b)
  (loop
     for s = 0 then (+ s i)
     for i = a then (+ i 1)
     when (> i b) return s))
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19535023

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档