2017-06-15 46 views
0

爲了解決我在使用Common Lisp時遇到的一些問題,我瀏覽了網絡並發現: Variable references in lisp 這與我的問題非常相關。Lisp /參數傳遞

閱讀這一部分:

想想功能! .................. 因此,要做你想做的事,代碼需要a)在範圍內或b)可以訪問範圍內的函數。

我想弄清楚它,但事情並不清楚。

首先,我不確定a)和b)在最後一句中指的是什麼。

第二我如何實際上使用提供的兩個代碼塊來獲得所需的結果?

在此先感謝您的任何相關提示。

+2

什麼是 '期望的結果'?事實上,你問什麼問題? – tfb

+0

基本上,您只能通過調用關閉一組變量(或變異字段,數組)的閉包來直接(範圍)或間接地設置您有權訪問的變量。閱讀http://www.gigamonkeys.com/book/variables.html – coredump

回答

1

我仍然無法弄清楚你問的是什麼問題,但我想你想知道如何在功能中的一個範圍內修改綁定,而這個功能看不到綁定。所以這是對這個問題的回答。

首先要理解的是,現代編程語言中的範圍非常簡單:如果您可以看到綁定(名稱和值之間的關聯),那麼您可以訪問該綁定,並且如果它是可變的,則可以進行變異它。早期的現代編程語言有許多神祕的規則,這些規則基於很久以前在小型計算機上的易用性(我們都被PDP-11的遺留問題所詛咒),但是現代的編程語言掃除了所有這些。在這個意義上,Common Lisp大多是一種現代編程語言。

因此,您需要做的是以某種方式捕獲綁定,然後將捕獲的綁定傳遞給您要調用的任何函數,以便在其中進行訪問或變異。捕獲綁定的方式是使用函數。

所以,在這裏是如何做到這一點的CL一個簡單的例子:

(defun foo (orig new) 
    (let ((x orig)) 
    (bar (lambda (&optional (value nil valuep)) 
      (if valuep 
       (setf x value) 
      x)) 
     new) 
    x)) 

(defun bar (c new) 
    (format t "~&initially ~S~%" (funcall c)) 
    (funcall c new) 
    (format t "~&then ~S~%" (funcall c))) 

在這段代碼被第一個參數創建bar功能訪問的x的結合,並且是這麼寫的所以不帶任何參數調用它將返回綁定的值,而用參數調用它將設置值。下面是在行動:

CL-USER 5 > (foo 1 2) 
initially 1 
then 2 
2 

所以你可以看到這個作品:的x綁定是通過調用其捕獲它的功能修改。我們可以避免所有這些顯式的funcall s和lambda s(我們可以避免前者在Lisp-1中,但它仍然不是很好)。但是,這在語法上很笨拙:如果我們可以避免所有這些顯式的funcall s和lambda s因此,這裏的一些代碼做(它的解釋如下)認爲:

(defmacro capture (binding) 
    "Capture a binding" 
    (let ((value (make-symbol "VALUE")) 
     (valuep (make-symbol "VALUEP"))) 
    `(lambda (&optional (,value nil ,valuep)) 
     (if ,valuep 
      (setf ,binding ,value) 
     ,binding)))) 

(defun captured (c &optional (value nil valuep)) 
    "Return the value of a captured binding, or set it" 
    (if valuep 
     (funcall c value) 
    (funcall c))) 

(defsetf captured captured) 

OK,所以宏觀capture只是語法糖它創建等同於一個原代碼的功能。它必須是一個宏,因爲該功能需要在它捕獲的綁定範圍內創建。

captured是那麼平凡函數剛剛調用由capture以適當的方式建立的功能:所以與其說(funcall c)我們可以說(captured c)

最後defsetf窗體教setf如何設置捕獲的綁定,所以(setf (captured x) y)將工作。

這裏是其使用上述foobar功能重新實現:

(defun foo (orig new) 
    (let ((x orig)) 
    (bar (capture x) new) 
    x)) 

(defun bar (c new) 
    (format t "~&initially ~S~%" (captured c)) 
    (setf (captured c) new) 
    (format t "~&then ~S~%" (captured c))) 

我認爲這是明顯的,這是更好的比所有明確funcall S和lambda S上方閱讀。它的工作方式相同:

CL-USER 6 > (foo 1 2) 
initially 1 
then 2 
2 

順便說一句,你可以捕捉expresssions,不只是變量綁定,當然,只要setf知道該怎麼跟他們做的(只要它們是什麼呼叫 '地方'):

(defun fish (l) 
    (bone (capture (car l))) 
    l) 

(defun bone (c) 
    (setf (captured c) 'bone)) 

現在

CL-USER 13 > (fish (list 1 2)) 
(bone 2)