本地过程绑定

时间:2017-11-02 18:52:46

标签: syntax scheme lisp

我是Scheme和Lisp的新手,在学习之后我偶然发现了本地程序绑定中使用的神秘语法:

(define mock
    (lambda (s) 
      ;; this is what I don't understand
      (let splice ([l '()] [m (car s)] [r (cdr s)])
        (append
         (map (lambda (x) (cons m x)) r)
         (if (null? r) '()
             (splice (cons m l) (car r) (cdr r)))))))

我花了一段时间才意识到splice是一个有3个arities的范围程序。以ML-esque样式重写它似乎产生类似的输出:

(define mock2
    (lambda (s)
      ;; define `splice` first
      (define splice
        (lambda (la lb lc)
          (append
           (map (lambda (x) (cons lb x)) lc)
           (if (null? lc) '()
               (splice (cons lb la) (car lc) (cdr lc))))))
      ;; bind `splice` and its arguments together and call it with them
      (let ([sp splice] [l '()] [m (car s)] [r (cdr s)])
        (splice l m r))))

第二个版本有点长,看起来更有必要,但是在将splice定义为与参数并行绑定(或者只是按原样查看)并调用之前,将l定义为范围内的正常过程看起来很健康。

问题是这两个版本可以替换吗?如果是,您能帮助解释第一版本在m绑定表单中绑定局部变量(rsplice memberr(X,[X|_]):- !. memberr(X,[_H|T]):- memberr(X,T). lengthOfList(List,R):- lengthOfList(List,0,R). lengthOfList([],L,L). lengthOfList([_|Tail],Acc,R):- NewAcc is Acc + 1, lengthOfList(Tail,NewAcc,R). remove_second([],[]). remove_second([H|T],R):- remove_second(H,T,R,[]). remove_second(H,[],[H|[]],List):- integer(H), \+ memberr(H,List). remove_second(H,[],[],List):- integer(H), memberr(H,List). remove_second(Elem,[H2|Tail2],[Elem|R],List):- integer(Elem), ( \+ memberr(Elem,List) -> remove_second(H2,Tail2,R,[Elem|List]) ). remove_second(Elem,[H2|Tail2],R,List):- integer(Elem), ( memberr(Elem,List) -> remove_second(H2,Tail2,R,List) ). remove_second(Elem,[H2|Tail],[P|R],List):- ( \+ integer(Elem) -> lengthOfList(Elem,L), L > 0, remove_second(Elem,P), remove_second(H2,Tail,R,List) ). remove_second(Elem,[H2|Tail],[[]|R],List):- ( \+ integer(Elem) -> lengthOfList(Elem,L), L == 0, remove_second(H2,Tail,R,List) ). remove_second(Elem,[],[[]],_):- ( \+ integer(Elem) -> lengthOfList(Elem,L), L == 0 ). remove_second(Elem,[],[P],_):- ( \+ integer(Elem) -> lengthOfList(Elem,L), L > 0, remove_second(Elem,P) ). )的语法吗?

1 个答案:

答案 0 :(得分:2)

调用splice就像重新进入一个循环,这就是它的用途。无论如何,尾部调用是一个goto。它通常被命名为loop,而不是为它考虑一些特殊名称。

“看起来更健康”是值得商榷的,实际上对于Schemers你会失去这个,因为这是一个非常流行的Scheme结构,名为“named let”。它通常用letrec btw重写,如果/当想要重写它时,更好地理解它。内部define也可以使用,但是,为什么不首先使用(define (mock s) ...

所以,通常的方法是重写这个

(define mock                              ; or: (define (mock s) ...
    (lambda (s) 
      (let splice ([l '()] [m (car s)] [r (cdr s)])
        (append
         (map (lambda (x) (cons m x)) r)
         (if (null? r) '()
             (splice (cons m l) (car r) (cdr r)))))))

就是这样:

(define mock
  (lambda (s) 
    (letrec ([splice (lambda (l m r)      ; or: (define (splice l m r) ...
                       (append
                        (map (lambda (x) (cons m x)) r)
                        (if (null? r) '()
                            (splice (cons m l) (car r) (cdr r)))))])
      (splice '() (car s) (cdr s)))))

并以名为let 的方式编写它可以节省一个在一个地方定义它并在另一个地方调用,可能很远。无论如何,一个呼叫从一开始就进入它的身体,并命名为更好地反映那个

这是非常不言自明的。从一种形式到另一种形式的转换纯粹是语法上的,两者都可以互换使用。