- Khi FORTRAN được xây dựng, McCarthy thiết kế một ngôn ngữ mới – LISP LispProcessor, 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 Su
Trang 1ĐẠI HỌC BÁCH KHOA TPHCM KHOA CÔNG NGHỆ THÔNG TIN
LÝ THUYẾT VÀ BÀI TẬP THỰC HÀNH
GOLDEN COMMON LISP
TPHCM, Tháng 10 – 2004
Trang 2LÝ THUYẾT VÀ BÀI TẬP THỰC HÀNH
GOLDEN COMMON LISP
Trang 3Mục lục
I Giới thiệu 1
II Cài đặt và sử dụng gcLisp 1
II.1 Cài đặt 1
II.2 Môi trường Gclisp 1
II.3 Phím nóng 2
II.4 Dòng lệnh 2
II.5 Lệnh tiền tố (Prefix command) 2
II.6 Load file vào gclisp 3
III Đặc điểm của gcLisp 3
III.1 Các đặc tính của ngôn ngữ 3
III.2 Kiểu dữ liệu 4
III.3 Vị từ (Prédicats) 5
IV Lập trình với gcLisp 5
IV.1 Các hàm xử lý trên danh sách 5
IV.1.1 FIRST và REST – CAR và CDR 5
IV.1.2 CONS, APPEND, LIST 6
IV.1.3 NTHCDR, BUTLAST và LAST 7
IV.1.4 LENGTH và REVERSE 8
IV.2 Các câu lệnh điều kiện 8
IV.3 Định nghĩa hàm 9
IV.4 Chương trình đệ quy trong Lisp 9
IV.5 Đánh giá 10
IV.6 Các dạng đặc biệt 11
IV.7 Các trường hợp điều kiện 11
IV.8 Biến cục bộ 12
IV.9 Symbols 13
IV.10 Lập trình hướng dữ liệu 14
IV.11 Lời gọi hàm tính toán 14
IV.12 Nhập/xuất cơ bản 14
IV.13 Lưu ý 15
IV.14 Hiệu chỉnh 15
V Nâng cao 15
V.1 Doublets 15
V.1.1 Doublets 15
V.1.2 Pointed pair 16
V.1.3 Ký hiệu pointed pair 16
V.1.4 Doublets 16
V.2 Apply 17
V.3 Funcall và ứng dụng 17
V.4 Lambda expression 18
V.5 Hàm vô danh và biến cục bộ 18
VI Tổng kết 18
Trang 4Lý 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 (InformationProcessing 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 (LispProcessor), 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ươngthích nhau Do đó, một dự án nhằm định ra một ngôn ngữ Lisp chung nhất đã hìnhthà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ộtthể 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ưởngcủ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.1 Cà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.2 Môi trường Gclisp
Chúng ta sẽ thấy cửa sổ gclisp như sau:
Trang 1
Trang 5II.3 Phím nóng
- <Alt>-H to get help
- <Alt>-E to enter the LISP Explorer
- <Ctrl>-E to enter the editor
- <F1> to exit editor into Lisp Environment
- <F8> to load a file into the editor
- <F9> to save a file
- <F10> to save a file as another name
II.4 Dòng lệnh
Đánh các dòng lệnh theo sau ký hiệu *
II.5 Lệnh tiền tố (Prefix command)
- Mọi lệnh đều nằm giữa dấu ngoặc đơn ( )
- Lisp sẽ đánh giá khi chúng ta đánh dấu ) cuối cùng
- Lệnh có dạng tiền tố:
Trang 2
(function <parameter>)
Trang 6II.6 Load file vào gclisp
- Ví dụ: load first.lsp
III Đặc điểm của gcLisp
III.1 Cá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 đếnversion 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)
Kết quả
* (load ‘first)
Trang 7III.2 Kiể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
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ả đặttrong 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:
Trang 4
expression list atom
symbol
real nil
list
number
interger
Trang 8Biế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ácnhau
(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
IV Lập trình với gcLisp
IV.1 Các hàm xử lý trên danh sách
IV.1.1 FIRST 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 CAR và CDR 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ạngphứ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
Trang 5
Trang 92 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.2 CONS, APPEND, LIST
LIST trả về danh sách các đối số
Bt Cho biết giá trị của các biểu thức sau:
1 (cons ‘a (cons ‘b (cons ‘c nil)))
Trang 6
Trang 10(cons ‘a (cons ‘b (cons ‘c nil)))
= (cons ‘a (cons ‘b ‘(c)))
= (cons ‘a ‘(b c))
= (a b c)
2 (list (car ‘(car ((1) (2)))) (cdr (cdr ‘((1) (2)))))
(list (car ‘(car ((1) (2))))
= (list ‘car nil)
= (list ‘car nil)
IV.1.3 NTHCDR, 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))
Trang 11*(last l1)
((c d))
IV.1.4 LENGTH 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.5 ASSOC
ASSOC 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)))
height và weight 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áchliên kết:
(ASSOC <key> <asociation list>)
Trang 12(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
Trang 9
Trang 13Nếu mọi thông số đều đúng, and trả về thông số cuối cùng
(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
error > A is not a number
*(or (symbolp x) (list x) )
Trang 14IV.4 Chương trình đệ quy trong Lisp
Vòng lặp trong Lisp được thực hiện chủ yếu nhờ vào đệ quy
Trang 15(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ố
*(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
…(Testn En …) )
Trang 12
Trang 16(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ố
IV.8 Biế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)
Trang 18(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ụ:
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
Giải pháp 2
(putprop ‘add ‘+ ‘numberp)
(putprop ‘add ‘append ‘listp)
3
…EXPR
“foo”
foo
Trang 19IV.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ả
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
Trang 16
Trang 20*(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
Tương tự như vậy, danh sách (1 2 3) được thể hiện bởi:
Hay đơn giản hơn:
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)
Ký hiệu danh sách là viết tắt của ký hiệu pointed pair
*‘(1 nil)
Trang 17
trường car
trường cdr
Trang 21*‘(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:
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.2 Apply
(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)))
(apply F L) (eval (cons F L))
Bt Đếm số symbols, numbers hay strings trong một list
Trang 22Nhậ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à expression va được viết:
lambda-(lambda header content)
V.5 Hà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)
Trang 233
VI Tổng kết
Trang 20