Scheme语言入门
2019獨角獸企業重金招聘Python工程師標準>>>
Scheme語言入門
最早聽說 LISP,是 Stallman 的 GNU Emacs 中將 LISP 作為嵌入語言,定制和增強 Emacs。GNU Emacs 是一個文本編輯器,文本就是一種符號,而 Lisp 正好就是針對符號計算發明的,因此在GNU Emacs 中使用 Lisp 是順理成章的事情。
Lisp 語言的歷史已經很久了,幾乎與 Fortran 一樣長。二十世紀五十年代,計算機科學家先是發明了針對數字計算的 Fortran 語言,后來針對符號計算,由MIT 的John McCarthy于1960年開發出了Lisp(List processing)語言。該語言原來是為表處理而設計的編程語言,后來廣泛用于處理人工智能問題。Lisp 程序中充滿了一對對嵌套的小括號,這些嵌套的符號表達式體現著遞歸。遞歸是數學上的基本概念之一,從遞歸理論出發,一切可以計算的函數最終都可以劃歸為幾種基本的遞歸函數的種種組合。
1994年時眾多 Lisp 版本又得到了相當的統一,統一之后的版本稱為Common LISP。Common Lisp 含有非常豐富的庫,僅僅語言的規范就長達千頁以上,包括面向對象的 CLOS。
Scheme 語言是 Lisp 的一個現代變種、方言,誕生于1975年,由 MIT 的 Gerald J. Sussman and Guy L. Steele Jr. 完成。Scheme語言的規范很短,總共只有50頁,甚至連Common Lisp 規范的索引的長度都不到,但是卻被稱為是現代編程語言王國的皇后。它與以前和以后的 Lisp 實現版本都存在一些差異,但是卻易學易用。
DSSSL需要完成的工作是解析文檔,它的設計就采用了Scheme語言。本書時介紹DocBook的專著,因此并不打算寫一個Scheme大全,只是想通過蜻蜓點水的介紹使讀者認識Scheme,能夠達到看懂和簡單的修改DSSSL。
Scheme特點
Scheme語言具有它獨特的魅力,看看Scheme的語法特點:
-
括號嵌套
Lisp 程序中充滿了一對對嵌套的小括號,這些嵌套的符號體現了最基本的數學思想——遞歸。
-
語法簡潔
Scheme語言的規范很短,總共只有50頁。
-
函數編程語言
一個函數(Function)是這個編程語言中所謂的第一等的公民。也就是說函式可以像一個 int 或者 float 一樣被很方便的傳遞來傳遞去。這也就是所謂"Functional 編程語言"中,Functional 一詞的由來。
-
自動內存管理
自動內存管理可不是JAVA的專利呦。
-
可移植性好
Scheme開發的程序有很好的可移植性,這是由于Scheme是一種解釋語言,在不同的平臺都可以有相應的解釋器。
-
適合于作為腳本語言和嵌入語言
語法簡潔,這使得Scheme的實現可以非常的經濟,一個Scheme解釋器可以非常的小巧。Scheme可以作為腳本語言而內嵌于一些工具之中,如:GNU Emacs。
其他特點還有,關鍵字對大小寫不敏感。
數據結構
-
數字
下面都是合法的數字表示方法:47,1/3,2.3,4.3e14,1+3i。
-
字符
字符前面需要用#\做前綴。如下面都是合法字符:
#\a #\A #\b #\B #\space #\newline
-
字符串
由雙引號括起來的字符組成字符串。如:"A little string"
-
布爾值
布爾值True和False分別用 #t 和 #f 表示。
-
列表
用圓括號括起來的,可以包含任何數據類型的稱為列表。如: (a little (list of) (lists))
-
數組(vector)
用#為前綴,如: #(1 2 "string" #\x 5)
-
函數(或稱為過程)
把函數作為一種數據類型,是Scheme語言的特色。
-
符號
符號除了不能夠以數字開頭的任何字符可組成符號。如:Symbols: this-is-a-symbol foo a32 c$23*4&7+3-is-a-symbol-too!
表達式和函數
注釋
分號開始一段注釋。如:
(+?3?1)?;return?4?
常量表達式
常量表達式
常量表達式返回本身的值。如:
3.14?;?返回?3.14?#t?;?返回布爾值?#t?#\c?;?返回字符?#\c?"Hi!"?;?返回字符串?"Hi!"引用(Quotation)
語法:(quote obj) ?或者簡寫為 'obj
(+?2?3)???;?返回?5?'(+?2?3)??;?返回列表?(+?2?3)?(quote?(+?2?3))?;?返回列表?(+?2?3)表達式記法
Scheme的表達式的寫法有些特別,表達式用括號括起來。括號里面的第一個出線的是函數名或者操作符,其它是參數。Scheme的這種表達式寫法可以叫做前置式。下面是一些Scheme的表達式的例子以及其對應的C語言的寫法。
??Scheme???????????????????????????????C?------------------------------------------------------------------?(+?2?3?4)???????????????????????(2?+?3?+?4)??(<?low?x?high)??????????????????((low?<?x)?&&?(x?<?high))??(+?(*?2?3)??????????????????????(*?4?5))?((2?*?3)?+?(4?*?5))??(f?x?y)?????????????????????????f(x,?y)??(define?(sq?x)?(*?x?x))?????????int?sq(int?x)?{?return?(x?*?x)?}?
賦值和函數定義
let 表達式和賦值
語法:(let ((var val) ...) exp1 exp2 ...)
說明:let 表達式的賦值只在表達式內部有效。
示例:
(let?((x?2)?(y?3))?(+?x?y)); 先賦值: x=2, y=3,再計算x+y的值,結果為5。注意 (x 2) 和 (y 3) 外還有一層括號。
更多的示例:
(let?((f?+))???(f?2?3))??;?return?5??(let?((f?+)?(x?2))???(f?x?3))??;?return?5??(let?((f?+)?(x?2)?(y?3))???(f?x?y))??;?return?5用define 和 set! 賦值
語法:(define var exp) ?, (set! var exp)
說明:define和 set! 表達式的賦值在全局有效。define 和 set! 的區別是define既能賦值又能定義變量,而set!只能對已經定義的變量賦值。
示例:
(define?a?1)???a?;?return?1?(set!?a?2)?a?;?return?2?(let?((a?3))?a)??;?return?3?a?;?return?2?(let?((a?3))?(set!?a?4)?a)?;?return?4?a?;?return?2?(let?((a?3))?(define?a?5)?a)?;?return?5?a?;?return?2?(set!?b?1)?;?錯誤,b尚未定義lambda 表達式和函數定義
語法:(lambda (var ...) exp1 exp2 ...)
說明:lambda 表達式用于定義函數。var ... 是參數,exp1 exp2 ...是函數的執行 部分。通常需要結合局部定義 let 或者全局定義表達式 define,再進行函數調用。
示例:
((lambda?(x)?(+?x?x))?(*?3?4))??;?return?24說明:先用lambda定義了函數,參數是x,函數返回x+x。同時該語句也完成了函數調用,實參是 12 (等于3*4),因此返回值是 24 (等于12+12)。
在let表達式中定義函數。
Scheme語言中,函數作為一種數據類型,通過賦值語句,將lambda表達式賦值給相應的函數。
示例:
(let?((double?(lambda?(x)?(+?x?x))))???(list?(double?(*?3?4))?????????(double?(/?99?11))?????????(double?(-?2?7))))?????;?return?(24?18?-10)說明:let表達式將lambda定義的函數賦值給double,參數是x,返回 x+x。接下來分別三次調用 double 函數,并將結果以列表形式返回。list 表達式負責生成列表。
用define全局定義表達式來定義函數。
用 let 定義的函數只能在 let 表達式中有效,如果想定義在整個程序中有效的函數定義,需要用到全局定義表達式——define。
示例:
(define?double?(lambda?(x)?(+?x?x)))?(double?12)????????????;?return?24?(double?(*?3?4))???????;?return?24說明:define表達式定義了全局有效的函數 double。兩次調用double的返回值都是 24。
定義函數的簡寫
用 define 定義的函數的語法可以簡化,即將 lambda 去掉。即將語法
(define?var0???(lambda?(var1?...?varn)?????e1?e2?...))簡寫為:
(define?(var0?var1?...?varn)???e1?e2?...)示例:
(define?(double?x)?(+?x?x))?(double?12)????????????;?return?24?(double?(*?3?4))???????;?return?24說明:本例是前一個例子的簡化版本。更簡介,明了。
順序計算表達式
語法:(begin exp1 exp2 ...)
說明:順序執行表達式 exp1, exp2, ...,返回最后一個表達式的結果
示例:
(define?x?3)?(begin???(set!?x?(+?x?1))???(+?x?x))?????????????;?返回結果?8?
說明:begin 表達式,依次先用set!表達式為x賦值為4,在運算x+x,返回結果8。
條件表達式
關系運算符
(<?-1?0)???#t?(>?-1?0)???#f??(eqv??'a?'a)??#t邏輯運算
(not?#t)???#f?(not?#f)??#t??(not?1)???#f?(not?'(a?b?c))???#f??(or)???#f?(or?#f)???#f?(or?#f?#t)???#t?(or?#f?'a?#f)???a??(and)???#t?(and?#f)???#f?(and?#f?#t)???#f?(and?#f?'a?#f)???#f?(and?'a?#t?'b)?'bif 表達式
語法:(if test consequent alternative)
說明:如果test表達式為真,返回 consequent,否則返回 alternative。
示例:
(define?(abs?n)?????(if?(<?n?0)?????????(-?0?n)?????????n))說明:函數abs功能為取絕對值。
cond 表達式
語法:(cond (test exp) ... (else exp))
說明:多路分支判斷表達式,類似于C語言的 "if ... else if ... else"。
示例:
(define?abs???(lambda?(n)?????(cond???????((=?n?0)?0)???????((<?n?0)?(-?0?n))???????(else?n))))說明:用cond表達式重新實現取絕對值函數 abs。
case 表達式
語法:(case exp0 clause1 clause2 ... )
clause 的語法結構為:((key1 ...) exp1 ...) 最后一個表達式的結構可以為:(else exp1 exp2 ...)
說明:類似于C語言的 "switch ... case..." 語句。
示例:
(let?((x?4)?(y?5))???(case?(+?x?y)?????((1?3?5?7?9)?'odd)?????((0?2?4?6?8)?'even)?????(else?'out-of-range)))?;?返回?odd說明:case 表達式先計算 x+y 的值為9,接下來在key中進行匹配,并返回對應的表達式的值 'odd。
循環
do 表達式
語法:(do ((var1 val1 update1) ...) (test res ...) exp ...)
說明:類似于C語言的for循環。先將val1賦值給var1,...,之后循環開始,在每次循環的開始,先執行表達式 test,如果返回布爾值真,則循環終止,并返回結果 res,如果表達式 test返回布爾值#f,則運行表達式 exp...,之后依次用 update1 ... 的值來為變量 var1 ... 重新賦值。
示例1:計算階乘 n! = n*(n-1)!
(define?factorial???(lambda?(n)?????(do?((i?n?(-?i?1))?(a?1?(*?a?i)))?????????((zero??i)?a))))??(factorial?10)??;?返回?3628800說明:其對應的C語言實現如下
long?factorial(int?n)?{?int??i=n;?long?a=1;?for?(i=n;;?i--)?{?if?(i?==?0)?return?a;?a?*=?i;?}?}示例2:計算fibonacci數列:f(n+1)=f(n)+f(n-1) , n>0, f(1)=1, f(0)=0
(define?fibonacci???(lambda?(n)?????(if?(=?n?0)?????????0?????????(do?((i?n?(-?i?1))?(a1?1?(+?a1?a2))?(a2?0?a1))?????????????((=?i?1)?a1)))))??(fibonacci?6)??;?返回?8說明:其對應的C語言實現如下
long?fibonacci(int?n)?{?long?f=1;?int?i?=?n;?int?a1=?1;?int?a2=?0;?if?(n?==?0)?return?0;?while(1)?{?if?(i?==?1)?return?a1;?i--;?a1=a1+a2;?a2=a1;?}?}map 表達式
語法:(map procedure list1 list2 ...)
說明:列表 list1 list2 ... 必須具有同樣的長度;過程 procedure 接受的參數個數同列表的個數,各個列表中對應的變量分別作為過程 procedure 的參數被執行, 將每次的運算結果以列表形式返回。
(map?abs?'(1?-2?3?-4?5?-6))??;?返回?(1?2?3?4?5?6),abs接受一個參數?(map?(lambda?(x?y)?(*?x?y))??????'(1?2?3?4)??????'(8?7?6?5))?返回(8?14?18?20)?,lambda?(x?y)?接收兩個參數for-each 表達式
語法:(for-each procedure list1 list2 ...)
說明:同 map表達式, 但是不返回結果列表。
?
轉載于:https://my.oschina.net/zhoukuo/blog/349453
總結
以上是生活随笔為你收集整理的Scheme语言入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 春节后面试别人的经历总结之一,好岗位分享
- 下一篇: “《三国演义》人物出场统计“实例讲解