ĐẠi học bách khoa tphcm khoa công nghệ thông tin



tải về 176.16 Kb.
Chuyển đổi dữ liệu30.08.2016
Kích176.16 Kb.



ĐẠI HỌC BÁCH KHOA TPHCM

KHOA CÔNG NGHỆ THÔNG TIN






TPHCM, Tháng 10 – 2004

MÔN HỌC : NGÔN NGỮ LẬP TRÌNH

LÝ THUYẾT VÀ BÀI TẬP THỰC HÀNH GOLDEN COMMON LISP

LÝ THUYẾT VÀ BÀI TẬP THỰC HÀNH GOLDEN COMMON LISP

Mục lục


LÝ THUYẾT VÀ BÀI TẬP THỰC HÀNH GOLDEN COMMON LISP 1

LÝ THUYẾT VÀ BÀI TẬP THỰC HÀNH GOLDEN COMMON LISP 2

Mục lục 3

Lý thuyết LISP 1

I. Giới thiệu 1

II. Cài đặt và sử dụng gcLisp 1

III. Đặc điểm của gcLisp 3

IV. Lập trình với gcLisp 5

V. Nâng cao 17

VI. Tổng kết 20



Lý thuyết LISP

I.Giới thiệu


  • LISP – ngôn ngữ lập trình có tên lấy từ List Processing.

  • Vào mùa hè năm 1956, Allen Newell, J.C. Shaw, và Herbert Simon đã phát triển xử lý Lisp (Lisp processing) và tạo nên ngôn ngữ xử lý thông tin IPL (Information Processing Language) – ngôn ngữ trừu tượng thao tác trên symbols và danh sách.

  • Khi FORTRAN được xây dựng, McCarthy thiết kế một ngôn ngữ mới – LISP (Lisp Processor), lấy từ ý tưởng của IPL, FORTRAN và FLPL chạy trên IBM704

  • Vào thập niên 70, Guy Steele và Gerald Sussman định ra Scheme, kết hợp Algol và Lisp

  • Vào đầu thập niên 80, có khoảng 12 hệ Lisp khác nhau. Các hệ Lisp này không tương thích nhau. Do đó, một dự án nhằm định ra một ngôn ngữ Lisp chung nhất đã hình thành – dự án này sẽ kết hợp những đặc tính tốt nhất của các hệ Lisp thời đó vào một thể thống nhất

  • Phiên bản đầu tiên của Common Lisp chuẩn ra đời năm 1984 – kết hợp nhiều ý tưởng của ngôn ngữ lập trình như thông dịch và biên dịch hàm, dọn rác (garbage collection), gọi hàm đệ quy, theo vết và dò lỗi (tracing and debugging) và trình soạn thảo theo cú pháp.

II.Cài đặt và sử dụng gcLisp

II.1Cài đặt


  • Chép tập tin GC LISP.rar vào và giải nén ra thư mục \GC LISP

  • Vào thư mục \GC LISP, chạy tập tin caidat.bat để cài gcLisp vào đĩa cứng

  • Vào thư mụcC:\Gclisp, chạy tập tin Gclisp.exe để bắt đầu.


II.2Môi trường Gclisp


Chúng ta sẽ thấy cửa sổ gclisp như sau:

II.3Phím nóng

II.4Dòng lệnh


Đánh các dòng lệnh theo sau ký hiệu *

II.5Lệnh tiền tố (Prefix command)


  • Mọi lệnh đều nằm giữa dấu ngoặc đơn ( )


  • (function
    )

    Lisp sẽ đánh giá khi chúng ta đánh dấu ) cuối cùng

  • Lệnh có dạng tiền tố:

II.6Load file vào gclisp


  • Ví dụ: load first.lsp


* (load ‘first)





III.Đặc điểm của gcLisp

III.1Các đặc tính của ngôn ngữ


  • Từ khi được John McCarthy (MIT) nghĩ ra năm 1958, LISP được tinh chế dần đến version 1.5 và được sử sụng lâu dài về sau

  • Lisp là ngôn ngữ hướng chức năng (functional language hay applicative), dùng lối ký hiệu tiền tố (prefix) và dấu ngoặc đơn:

f(x,y, z) được ký hiệu là (f x y z)

Cũng như vậy x+y ký hiệu là (+ x y)

Bt. viết trong Lisp như thế nào ?



  • Lisp là ngôn ngữ thông dịch (interpreted language)

Ví dụ:


*(+ 3 4)

7
*(+ (* 3 4)(- 5 2))

15
*4

4

III.2Kiểu dữ liệu


Lisp là ngôn ngữ đặc trưng cho việc xử lý danh sách

Chương trình được biểu diễn bằng các danh sách và có thể thao tác trên đó như dữ liệu

(+ (* 3 4) (- 5 2))

chương trình: hàm + áp dụng vào hai đối số

dữ liệu: danh sách gồm ba thành phần

top-level, khi đóng vai trò là đối số của một hàm, một danh sách luôn được xem như là sự áp dụng một hàm

Lisp thao tác trên các loại dữ liệu:


  • Biểu thức expression::= atom | list

  • Danh sách list::= (expression1...expressionn)

Danh sách là một chuỗi các biểu thức ngăn cách nhau bởi khoảng trắng, tất cả đặt trong dấu ngoặc đơn

  • Atoms

atom::= số | chuỗi ký tự | symbols

  • Symbol (~ identifier): từ tạo bởi các ký tự bất kỳ, ngoại trừ ( ) ‘ ` “ ; và khoảng trắng

  • Boolean: Lisp không có kiểu boolean. Trong Lisp, nil mang giá trị logic sai và tất cả các biểu thức khác có giá trị đúng. Ký hiệu t dùng để chỉ trị logic đúng theo mặc định.

Các kiểu dữ liệu được xếp theo cấp bậc như sau:

Biến trong Lisp không có kiểu dữ liệu , cùng một biến có thể có nhiều kiểu dữ liệu khác nhau

Ví dụ:

*(setq a ‘(1 2 3))



(1 2 3)
*a

(1 2 3)
*(setq a 2)

2
*a

2

Kiểu được gán cho dữ liệu chứ không phải cho biến. Ta có thể biết kiểu dữ liệu của biến nhờ vào các vị từ (prédicat)



(numberp E) ;; trả về đúng nếu E là một số

(stringp E) ;; trả về đúng nếu E là một chuỗi ký tự

(listp E) ;; trả về đúng nếu E là một danh sách

(null E) ;; trả về đúng nếu E là danh sách rỗng

(atom E) ;; trả về đúng nếu E là atom

III.3Vị từ (Prédicats)


  • Vị từ kiểu (xem phía trên)

  • Vị từ so sánh số: < > >= <= <>

*(< 4 5)

T

*(> 4 5)



NIL

IV.Lập trình với gcLisp

IV.1Các hàm xử lý trên danh sách

IV.1.1FIRST và REST – CAR và CDR


  • FIRST trả về phần tử đầu tiên của danh sách

  • REST trả về danh sách theo sau phần tử đầu tiên

Cho đến gần đây, phần lớn lập trình viên LISP vẫn dùng CARCDR thay cho FIRST và REST. Ngoài chức năng tương tự, CAR và CDR có thể kết hợp với nhau.thành dạng phức hợp CxxR, CxxxR hay CxxxxR. Mỗi x tượng trưng cho A – CAR hay D – CDR.

Quy ước:


*(car nil)

NIL


*(cdr nil)

NIL


Bài tập:

  1. Lấy phần tử thứ ba của danh sách

(car (cdr (cdr l)))

có thể viết:

(caddr l)

CAR và CDR có thể kết hợp với nhau đến mức độ 4

Ví dụ:

(caadr l) = (car (car (cdr l)))



(cadar l) = (car (cdr (car l)))

  1. Làm thế nào trích ra chuỗi example trong danh sách:

L=((this) is (an (example)) more complex)

L=((this) is (an (example)) more complex)

(cdr l) = (is (an (example)) more complex)

(cdr (cdr l)) = ((an (example)) more complex)

(car (cdr (cdr l))) = (an (example))

(cdr (car (cdr (cdr l)))) = ((example))

(car (cdr (car (cdr (cdr l))))) = (example)

(car (car (cdr (car (cdr (cdr l)))))) = example


IV.1.2CONS, APPEND, LIST


  • LIST trả về danh sách các đối số

*(list ‘a (+ 3 1) ‘c)

(a 4 c)
*(list ‘(a b) ‘(c d))

((a b) (c d))
*(list ‘a nil)

(a nil)


  • CONS thêm một phần tử vào đầu danh sách

(cons ‘a ‘(2 3))

(a 2 3)
(cons `(a b) ‘(c d))

((ab) c d)
(list `a nil)

(a)


(CAR (CONS a l)) = a

(CDR (CONS a l)) = l

Bt. Cho biết giá trị của các biểu thức sau:



  1. (cons ‘a (cons ‘b (cons ‘c nil)))

(cons ‘a (cons ‘b (cons ‘c nil)))

= (cons ‘a (cons ‘b ‘(c)))

= (cons ‘a ‘(b c))

= (a b c)



  1. (list (car ‘(car ((1) (2)))) (cdr (cdr ‘((1) (2)))))

(list (car ‘(car ((1) (2))))

(cdr (cdr ‘((1) (2)))))

= (list ‘car

(cdr (cdr ‘((1) (2)))))

= (list ‘car

(cdr ((2))))

= (list ‘car nil)

= (list ‘car nil)

= (car nil)


  • APPEND kết hợp các phần tử của mọi danh sách đã cho

(setq l1 ‘(a b)

l2 ‘(x y))

= (x y)
(append l1 l2)

= (a b x y)


(append l1 ‘() l2 ‘())

= (a b x y)


IV.1.3NTHCDR, BUTLAST và LAST


  • NTHCDR cắt n phần tử đầu danh sách, với thông số đầu chỉ số phần tử cần cắt

*(setq l ‘(a b c d e))

(a b c d e)


*(nthcdr 2 l)

(c d e)


  • BUTLAST cắt n phần tử cuối danh sách, với thông số đầu là danh sách, thông số thứ hai chỉ số phần tử cần cắt

*(setq l ‘(a b c d e))

(a b c d e)


*(butlast l 2)

(a b c)
*(butlast l 10)

NIL


  • LAST trả về danh sách tất cả phần tử trừ phần tử cuối cùng đã bị loại ra

*(setq l ‘(a b c d e)

l1 ‘((a b) (c d)))

((a b) (c d))
*(last l)

(e)
*(last l1)

((c d))

IV.1.4LENGTH và REVERSE


  • LENGTH trả về chiều dài của chuỗi

*(setq l ‘(a b c d e))

(a b c d e)


*(length l)

5


  • REVERSE trả về chuỗi nghịch đảo

*(setq l ‘(a b c d e))

(a b c d e)


*(reverse l)

(e d c b a)


IV.1.5ASSOC


  • A
    Key

    Key
    SSOC
    gắn với một danh sách – association list hay còn gọi a-list

(setfl sarah ‘((height .54) (weight 4.4)))


Value



Value


heightweight là khóa trong danh sách được gán cho SARAH; .54 và 4.4 là các giá trị biểu thị bằng met và kilograms.

  • Có thể lấy các thành phần từ một danh sách dùng ASSOC, một khóa, và danh sách liên kết:

(ASSOC )

Ví dụ:


(assoc ‘weight sarah)

(WEIGHT 4.4)

Lưu ý ASSOC luôn trả về toàn bộ danh sách con tương ứng với khóa. Trong trường hợp có nhiều danh sách con cùng khóa, danh sách đầu tiên sẽ được trả về.

IV.1.6LISP cung cấp các thao tác trên Integer, Ratio, Floating-Point Numbers, ...


*(/ 1.234321 1.111)

1.111
*(/ 27 9)

3

Tuy nhiên với trường hợp chia không chẵn, kết quả là một phân số:



*(/ 22 7)

22/7


Dùng FLOAT nếu muốn kết quả trả về là số thực có dấu phẩy động:

(float (/ 22 7))

3.14286

Dùng ROUND để làm tròn kết quả:



*(round (/ 22 7))

3 ;Thương – số nguyên gần nhất

1/7 ;Phần dư
*(+ round (/ 22 7)) (round (7/3)))

5
*(round (/ 5 2))

2

Một số hàm tính toán học:

*(MAX 2 4 3)

4

*(MIN 2 4 3)



2
*(expt 2 3)

8

*(expt 3 2)



9

*(expt 3.3 2.2)

13.827085

*(sqrt 9)

3
*(abs -5)

5

IV.2Các câu lệnh điều kiện


  • Câu lệnh IF

(if E1 E2 E3)

Nếu E1 đúng, trả về giá trị E2 nếu không trả về giá trị E3

Ví dụ:

*(if (numberp 1) ‘(a number) ‘(not a number))



(A NUMBER)
*(if (numberp ‘a) ‘(a number) ‘(not a number))

(NOT A NUMBER)



  • AND

(and E1 E2 ... En) là sai nếu ít nhất một Ei sai

AND đánh giá các đối số từ trái sang phải và chỉ dừng khi gặp một đối số sai

Nếu mọi thông số đều đúng, and trả về thông số cuối cùng

Ví dụ:

*(setq x ‘a)



A
*x

A
*(and (numberp x) (> x 1) )

NIL
*(and (symbolp x) (list x) )

(A)


  • OR

(and E1 E2 ... En) là sai nếu ít nhất một Ei sai

AND đánh giá các đối số từ trái sang phải và chỉ dừng khi gặp một đối số đúng

Ví dụ:


*(setq x ‘a)

A
*x

A
*(or (numberp x) (> x 1) )

error > A is not a number


*(or (symbolp x) (list x) )

T

IV.3Định nghĩa hàm


(defun )



Symbol



đại diện cho các biến



biểu thức

Ví dụ:

*(defun square (x) (* x x))

SQUARE
*(square 3)

9
*(defun abs(x)

(if (>= x 0) x

(* -1 x) ) )

ABS

IV.4Chương trình đệ quy trong Lisp


Vòng lặp trong Lisp được thực hiện chủ yếu nhờ vào đệ quy

Ví dụ: Tính giai thừa



Trong Pascal, hàm n! được viết bằng vòng lặp:

function fac(integer:n):integer;

var i:integer

begin

fac:=1;


for i:=1 to n do

fac:=fac*i;

end

Định nghĩa đệ quy của giai thừa:



Trong Lisp:

(defun fac(n)

(if (= n 0)

1

(* n fac (1- n)) ) )



Bài tập:

  1. Viết hàm in ra phần tử thứ n trong danh sách

(defun nth (n l)

(if (= n 1)

(car l)

(nth (1- n) (cdr l)) ) )



  1. Ví dụ đệ quy chéo hay lời gọi đệ quy:

(defun pair (n)

(or (= n 0)

(impair (1- n)) ) )
(defun impair (n)

(and (<> n 0)

(pair (1- n)) ) )

IV.5Đánh giá


‘Exp là cách viết tắt của (quote Exp)

*‘a


A
*‘‘a

(QUOTE A)



QUOTE không đánh giá đối số

Ngược lại với quote là hàm eval đánh giá giá trị của đối số

*(setq l ‘(a b c))

(A B C)
*(eval (list ‘car ‘l))

A
*(eval (list ‘* (1+ 3) 2))

6

Giá trị của (eval ‘Exp) là Exp


IV.6Các dạng đặc biệt


(progn E1 ... En)

đánh giá tuần tự các biểu thức E1, ..., En từ trái sang phải và kết quả trả về là giá trị của biểu thức En

*(progn (setq x ‘(a b c))

(append x x) )

(A B C A B C)
*(progn)

NIL


với defun và đôi khi if, kiểu progn tiềm ẩn và n-airs

(defun name(p1 … pm) E1 … En)


(defun name(p1 … pm) (progn E1 … En))
(if Test E1 E2 … En)

(if Test E1 (progn E2 … En))

điều này không đúng trong Clisp

(prog1 E1 ... En)

đánh giá tuần tự các biểu thức E1, ..., En từ trái sang phải và kết quả trả về là giá trị của biểu thức E1

*(prog1 (setq x ‘(a b c))

(append x x) )

(A B C)

IV.7Các trường hợp điều kiện


(cond (Test1 E1 …)

(Test2 E2 …)

(Test3 E3 …)

(Testn En …) )



(if Test1 (progn E1 …)

(if Test2 (progn E2 …)

(if Test3 (progn E3 …)

(if Testn (progn En …)) … )



) )

Trong một mệnh đề kiểu (Test1), nếu Test1 đúng, kết quả của cond là giá trị của (Test1)

Ví dụ: Viết hàm trả về kiểu của đối số

*(type-of 1)

FIXNUM
*(type-of a)

SYMBOL


Giải:

(defun type-of (x)

(cond ((null x) ‘null)

((symbolp x) ‘symbolp)

((numberp x) ‘numberp)

((stringp x) ‘stringp)

((consp x) ‘consp)

(t ‘unknown-type) )

)

IV.8Biến cục bộ


(let ((var1 exp1) … (varm expm))

expm+1 … expn)

Chúng ta gán cho mỗi biến giá trị của biểu thức tương ứng, sau đó ta đánh giá

(progn expm+1 … expn)

Ví dụ:

*(let ((x (fac 4))) (* x x))



= 576

  • Các biến cục bộ che phủ các biến toàn cục

*(setq x 5)

5
*(let ((x 1)) x)

= 1
*x

5
*(let ((x 1)) (setq x 2) x)

2
*x

5


  • Các biến cục bộ che phủ các đối số của một hàm

*(defun foo(x)

(let ((x 1)) x ) )

FOO
*(foo 4)

1


  • Các liên kết được thực hiện song song

*(defun bar(x)

(let ((x 1) (y (1+ x)))

y) )

BAR
*(bar 4)



5

  • Dạng let* thực hiện một liên kết tuần tự các đối số

*(defun bar(x)

(let ((x 1) (y (1- x)))

y) )

BAR
*(defun bar1(x)



(let* ((x 1) (y (1- x)))

y) )


BAR
*(bar 3)

2
*(bar1 3)

0


  • let* tương ứng với let lồng nhau

* (defun bar(x)

(let ((x 1))

(let ((y (1+ x)))

y) ) )


BAR

IV.9Symbols


Có thể so sánh hai symbols nhờ hàm eq

*(eq ‘a ‘b)

NIL
*(eq ‘a ‘a)

T

(neq Exp) = (null (eq Exp))



  • Các trường của một symbol

Symbol là một đối tượng bao gồm nhiều trường:

CVAL: giá trị của symbol cũng như biến

PNAME: chuỗi ký tự tương ứng với tên của symbol (dùng cho máy in)

  • FVAL: hàm gắn liền với symbol, trường này không tồn tại trong LISP đơn trị

    LISP đa trị (bi-valued)

    LISP đơn trị (mono-valued)

    *(setq + 4)

    4
    *(+ + 3)

    7
    *(setq + *)

    var + indef



    *(setq + 4)

    4
    *(+ + 3)

    func + undef
    *(* 4 3)

    = 12


  • FTYPE: kiểu hàm

  • Ví dụ:


* (setq foo 3)

3
*(defun foo(x) …)

FOO

foo





IV.10Lập trình hướng dữ liệu


  • Ví dụ: Chúng ta muốn dùng cùng một hàm thực hiện việc cộng hai số và nối hai chuỗi

  • Giải pháp 1

(defun add(x y)

(cond ((numberp x) (+ x y))

((listp x) (append x y) ) )

)


  • Giải pháp 2

(putprop ‘add ‘+ ‘numberp)

(putprop ‘add ‘append ‘listp)

(defun add(x y)

(funcall (getprop ‘add (type-of x))

x y) )

funcall cho phép gọi các hàm tính toán


IV.11Lời gọi hàm tính toán


  • funcall: áp dụng giá trị của thông số thứ nhất (một hàm hay tên của một hàm) vào các thông số tiếp theo

(funcall ‘F E1…En) = (F E1…En)

IV.12Nhập/xuất cơ bản


  • Có thể dễ dàng viết các định nghĩa hàm trong một file (có thể edit) sau đó load file đó lên

load name

tên hay đường dẫn đến file chứa định nghĩa hàm



  • (read) đọc một biểu thức và trả về kết quả

* (+ (read) 3)

* 4


= 7
* (read)

* (+ 3 4)

= (+ 3 4)

IV.13Lưu ý


  • Có thể viết vòng lặp toplevel:

(defun toplevel ()

(print (eval (read)))

(toplevel) )

IV.14Hiệu chỉnh


  • Đây là ngôn ngữ tương tác (interactive), do đó chúng ta có thể kiểm tra mỗi hàm ở toplevel mà không bắt buộc phải định nghĩa các chương trình tests

  • Một kỹ thuật theo vết (trace) cho phép theo dõi quá trình thực hiện một hàm

*(defun fac(n)

(if (= n 0) 1 (* n (fac (1- n))) ) )

FAC
*(trace fac)

;Autoload: TRACE from “TRACE” in “C:\\GCLISP\\LISPLIB”

T

* (fac 2)



ENTERING: FAC, ARGUMENT LIST: (2)

ENTERING: FAC, ARGUMENT LIST: (1)

ENTERING: FAC, ARGUMENT LIST: (0)

EXITING: FAC, VALUE: 1

EXITING: FAC, VALUE: 1

EXITING: FAC, VALUE: 2

2


  • untrace cho phép trở về sự thực hiện bình thường của hàm

*(untrace fac)

(FAC)


*(fac 2)

2


  • trace cập nhật định nghĩa hàm theo vết bằng cách in ra kết quả từng giai đoạn

  • có thể theo dõi sự thực hiện nhiều hàm cùng lúc

V.Nâng cao

V.1Doublets

V.1.1Doublets


  • Một danh sách không rỗng được biểu diễn bằng một đối tượng có hai trường gọi là doublet

Tương tự như vậy, danh sách (1 2 3) được thể hiện bởi:



Hay đơn giản hơn:






V.1.2Pointed pair


  • Thông số thứ hai của cons có thể không phảI là một danh sách. Trong trường hợp đó, chúng ta gọi là cặp con trỏ (pointed pair)

*(cons ‘a ‘b)

(A . B)
*(car ‘(a . b))

A
*(cdr ‘(a . b))

B

V.1.3Ký hiệu pointed pair


  • Ký hiệu danh sách là viết tắt của ký hiệu pointed pair

*‘(1 . nil)

(1)
*‘(1 . (2 . (3 . nil)))

(1 2 3)

Nói chung, chúng ta có:



(exp.(exp1 … expN))=(exp exp1 … expN)

  • Chúng ta có thể kết hợp hai lối ký hiệu:

*‘(1 . (2 3))

(1 2 3)
*‘(1 . (2 . 3))

(1 2 . 3)

V.1.4Doublets


  • Mỗi biểu thức trong Lisp là một doublet hay một atom

expression ::= (expression.expression) | atom

  • Consp là một vị từ để kiểm tra thông số của nó có là một doublet hay không

(defun listp(p)

(or (null x)

(consp x) ) )

V.2Apply


  • (apply F L) áp dụng hàm F trên các phần tử của danh sách L

*(apply ‘append ‘((a b) (c d)))

(a b c d)


*(apply ‘+ ‘(1 2))

3
*(setq a ‘*)

*
*(apply a ‘(3 4))

12


  • (apply F L)  (eval (cons F L))

Bt. Đếm số symbols, numbers hay strings trong một list

(defun count(test l)

(if (null l) 0

(if (apply test (list (car l)))

(1+ (count test (cdr l)))

(count test (cdr l)) ) )

)

V.3Funcall và ứng dụng


  • (apply f (list e1 … en))  (funcall f e1 … e2)

*(setq a ‘+)

+
*(funcall a (+ 3 4) 5)

12

Lưu ý: Trong Lisp đơn trị (như Scheme), chúng ta có thể viết trực tiếp:



* (a (+ 3 4) 5)

= 12


vì ở đó có sự đánh giá hàm

Bt. Đếm số symbols, numbers hay strings trong một list

(defun count(test l)

(if (null l) 0

(if (funcall test (car l))

(1+ (count test (cdr l)))

(count test (cdr l)) ) )

)

Bt. Đếm số symbols, numbers hay strings trong một list


V.4Lambda expression


Dùng hàm count để đếm số số nguyên nhỏ hơn 10 trong danh sách

*(defun inf10(x)

(and (integerp x) (< x 10)) )

INF10
*(count ‘inf10 ‘(4 12 a 11 3))

2

Nhận xét : Chúng ta định nghĩa hàm inf10 chỉ để sử dụng một lần duy nhất



Có thể sử dụng một hàm không tên. Hàm như thế trong Lisp được gọi là lambda-expression va được viết:

(lambda header content)

*(count (lambda (x)

(and (integer x)

(< x 10) ) )

‘(4 12 a 11 3)

2

Có thể trực tiếp định nghĩa lambda-expression khi xử lý:



*(+ 10 ((lambda (x) (* x x)) 4) )

26

V.5Hàm vô danh và biến cục bộ


Các biến cục bộ được bắt đầu với let là các tham số của một hàm vô danh (anonymous)

(let ((var1 val1) … (varN valN)) corps)

( ( lambda (var1 … varN) corps) val1 … valN)



*(let ((x 1) (y 2)) (+ x y))

3

* ( ( lambda (x y) (+ x y) ) 1 2 )



3

VI.Tổng kết



Cơ sở dữ liệu được bảo vệ bởi bản quyền ©hocday.com 2016
được sử dụng cho việc quản lý

    Quê hương