Scheme和Common Lisp中對函數作爲變量和返回值的處理方法差異

  研究下Scheme和Lisp在lamba上的區別。今天晚上特別鬱悶。本來想體會一下Lisp中函數作爲第一等變量等柑橘,想不到卻不知道載了多少個跟頭。

Scheme

  Scheme作爲Lisp的一個方言,由MIT研發,並且GPL的協議下發布。大家可以從GNU官網上下載其源碼,然後編譯安裝。Scheme相對與Lisp結合了Agol(不確定)。我們現在來看一下載Scheme語言中如何返回一個函數:

(define (repeat-2 fun)
  (lambda (x) (fun (fun x)))
  上述定義的函數將函數fun的功能重複兩遍。其使用方法如下,假設定義了加1函數incf,

((repeat-2 incf) 1)
  這樣就將incf重複了兩次。

Lisp

  如果對Scheme的使用方式比較熟悉,那麼在使用lisp實現時會覺得很奇怪。因爲Lisp解析器根據變量的位置不同來決定變量是函數還是變量。Lisp中由兩個函數boundp和fboundp,分別判斷一個名字是否時一個有值的變量或者函數。載Lisp中lambda是宏,其展開時會調用function。舉個例子。

(defun repeat-2 (fun)
  (lambda (x) (funcall fun (funcall fun x))))
  此時解析器會將其展開成如下:

(defun repeat-2 (fun)
  (function lambda (x) (funcall fun (funcall fun x))))
  Lisp允許我們只寫lambda只是提供了一個語法糖,允許我們直接使用。注意到將函數作爲變量值傳遞給函數時,調用方式不能像Scheme那樣直接調用,而是需要funcall或者apply來調用。repeat-2返回將指定的函數重複2次的功能,返回的函數值,我們不能直接使用,也必須使用funcall或者apply。相對於Scheme好像有點複雜。

(funcall (repeat-2 #'incf) 1)
  今晚在測試的時候使用Lisp系統自帶的incf,結果報錯,說incf是宏,不是函數。當時沒注意,以爲是調用方式出問題,便加了#'。後來又報錯說值不能放函數定義。後來回過頭來想起,原來incf是,他們封裝了set的功能。於是自己寫了incf-my,然後按照上面的方式執行一遍,結果OK。

  後來Google搜索了相關的使用方法。原來Lisp中有兩個Cell,姑且成爲function cell和alue cell。所以允許函數名字和變量名字相同,解析器是根據位置來確定到底時解析成函數還是變量。通過之前說的boundp和fboundp來判斷到底是變量還是函數。

  本文完。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章