power corrupts
Lisp is power
study it hard
be evil
Lisp is designed to be extensible; it lets you define new operators yourself. Lisp programs tend to be short - the language gives you bigger concepts, so you don’t have to use many
comments start with a semi-colon
; simple.lsp - source file (set! x 5) ; asignment (display x) ; output to terminal (newline) (set! y (read)) ; read from terminal (display (+ x y)) (newline) ; endoffile
$> csi CHICKEN (c) 2008-2014, The Chicken Team (c) 2000-2007, Felix L. Winkelmann Version 4.9.0.1 (stability/4.9.0) (rev 8b3189b) linux-unix-gnu-x86-64 [ 64bit manyargs dload ptables ] bootstrapped 2014-06-07 #;1> (load "simple.lsp") ; loading simple.lsp ... 5 #;2> (exit) $> csi -q simple.lsp 5 #;1> Ctrl-d $> csc simple.lsp $> ./simple 5
the Lisp interpreter performs computations on s-expressions through a process called evaluation
the basic elements of s-expressions are lists and atoms
s-expression : atom | list list : () | (cons s-expression list) atom : number | string | symbol
lists are delimited by parentheses, and can contain any number of elements separated by white-space
atoms are everything else
the elements of lists are themselves s-expressions (in other words, atoms or nested lists)
in Lisp lists are geterogenious
set!
and define
Lisp uses a special function set!
that assigns the value of one of its arguments to the other argument:
> (set! x 47) 47 > (set! y (+ 4 7)) 11 > (+ 3 (set! z (* 3 7))) 24 > z 21 > (define s "Lisp") "Lisp" > s "Lisp"
#f
, #t
TODO
cons
, car
, cdr
; pair?
> (cons 1 2) (1 . 2) > (set! x (cons 1 2)) > (car x) 1 > (cdr x) 2 > (pair? x) #t > (pair? 5) #f
> (list 1 2 3) (1 2 3) > (set! m (list 1 2 3)) > (car m) 1 > (cdr m) (2 3)
+---+---+ +---+---+ +---+---+ | 1 | p |-->| 2 | p |-->| 3 | x | +---+---+ +---+---+ +---+---+
(cons 1 (cons 2 (cons 3 ())))
cadr
, caddr
, cadddr
,
cddr
, cdddr
, cddddr
> (set! x (list 1 2 3)) > (car x) 1 > (cdr x) (2 3) >(cadr x) 2 >(cddr x) (3)
set-car
, set-cdr
> (set! p (cons 1 2)) > p (1 . 2) > (set-car! p 4) > p (4 . 2) > (set-cdr! p (list 5 6 7)) > p (4 5 6 7)
length
, append
, max
, min
; null?
> (length '(3 4 5 6)) 4 > (append '(1 2 3) '(5 6 7)) (1 2 3 5 6 7) #;5> (max 2 3 1 5 4) 5 #;6> (min 2 3 1 5 4) 1 > (null? '()) #t > (null? (list)) #t > (set! p (list)) > (null? p) #t
quote
(and '
)Lisp evaluates everything. sometimes you don’t want Lisp to do that; in situations like these, quote is used to override Lisp’s normal evaluation rules:
(quote (+ 7 2))
Lisp programs can generate Lisp code and the quote function is crucial to engineer this functionality. if a list is quoted, evaluation returns the list itself; if it is not quoted, the list is treated as Lisp code, and evaluation returns its value:
> (list '(+ 0 1 1 2 3 5) (+ 0 1 1 2 3 5)) ((+ 0 1 1 2 3 5) 12) > (list (quote (1 2 3)) (list 1 2 3)) ((1 2 3) (1 2 3))
+
, -
, *
, /
, sqrt
, log
, exp
, sin
, cos
, tan
, asin
, acos
, atan
> (+ 1 2) 3 > (- 3 4) -1 > (* 5 6) 30 > (/ 7 8) 0.875 #b #B the integer is written in binary (base 2) #o #O the integer is written in octal (base 8) #d #D the integer is written in decimal (base 10) #x #X the integer is written in hexadecimal (base 16) (quotient n d) (remainder n d) (modulo n d) (gcd x… ) (lcm x…) (abs x) (max x1 x2 …) (min x1 x2 …) (truncate x) (round x) (floor x) (ceiling x) (integer-length n) (integer-length #b10101010) ⇒ 8 (integer-length #b1111) ⇒ 4 (integer-length 0) ⇒ 0 (integer-length -1) ⇒ 0 (integer-length -256) ⇒ 8 (integer-length -257) ⇒ 9
=
, <
, <=
, >
, >=
odd?
, even?
, positive?
, negative?
, zero?
, integer?
, real?
(random n)
> (map random (cdr '(1 2 3 4 5))) (0 1 3 0)
(set! x 3+4i)
(complex? x)
(make-rectangular real_part imaginary_part) (make-polar mag ang) (real-part z) (imag-part z) (magnitude z) (angle z)
(use numbers) (define (myfunc a b) (display (bitwise-and a b)) (newline) (display (bitwise-ior a b)) (newline) (display (bitwise-xor a b)) (newline) (display (bitwise-not a)) (newline)) (myfunc 255 5)
(number->string n [radix])
(string->number string [radix])
(string-length string)
(string-append "a" "b")
(string-ref string i)
(substring string startpos endpos)
(string=? string1 string2)
(string>? string1 string2)
(string<? string1 string2)
(string>=? string1 string2)
(string<=? string1 string2)
operators starting with '-ci' are case-insensitive
(string-ci=? string1 string2)
(string-ci<? string1 string2)
(string-ci>? string1 string2)
(string-ci<=? string1 string2)
(string-ci>=? string1 string2)
(define function_name (lambda (arg1 arg2 ...) (op arg1 arg2 ...)))
map
, foldr
, foldl
, for-each
> (map (lambda (x) (* 2 x)) '(5 6 7 8)) (10 12 14 16) > (foldr (lambda (x y) (+ x y)) 0 '(5 6 7 8)) 26 > (foldr (lambda (x y) (* x y)) 1 '(5 6 7 8)) 1680 > (for-each (lambda (x) (display x)) '(6 7 8)) 678
to define a local variable, use the let
command
a let
expression has two lists
let
, where these variables are bounded> (let ((x 8) (y 3) (z 5)) (+ x y z)) 16 > (define myfunc (lambda (x) (let ((a 5) (b 6)) (+ a b x)))) > (myfunc 10) 21
cond
(and if
)> (define (fun1 x) (cond ((< x 0) (- x)) ((= x 0) 0) ((> x 0) x))) > (define (fun2 x) (if (< x 0) (- x) x)) > (fun2 12) 12 > (fun2 (- 12)) 12
and
, or
, not
string?
, number?
, atom?
, eq?
, equal?
begin
;; file block.scm (define p (begin (set! x (+ 1 2)) (set! y (+ 4 5)) (* x y)))
> (load "block") ; loading block.scm ... > p 27 >
apply
> (apply + (list 1 2)) 3
eval
TODO
(define f (lambda (a b . cs) (list a b cs))) (set! x (f 1 2 3 4 5)) (display x) (newline) (define (g . xs) (list xs)) (set! y (g 1 2 3 4 5)) (display y) (newline)
> (load "varpar.lsp") ; loading varpar.lsp ... (1 2 (3 4 5)) ((1 2 3 4 5))
(define (make-account init-bal) (let ((bal init-bal)) (lambda (op . args) (cond ((eq? op 'withdraw) (set! bal (- bal (car args)))) ((eq? op 'deposite) (set! bal (+ bal (car args)))) ((eq? op 'lookup ) bal)))))
> (load "balance.lsp") loading balance.lsp ... > (set! x (make-account 100.0)) > (x 'lookup) 100.0 > (x 'withdraw 10.2) > (x 'lookup) 89.8 > (x 'deposite 300.1) > (x 'lookup) 389.9
read
, write
, display
, newline
TODO
успех Лиспа в свое время основывался на объективных факторах:
1) язык крайне прост в реализации и реализация эта компактна и помещалась в комп начала 60-х: тривиальный синтаксис, анализатор которого может написать любой (тогда) студент, да и внутренняя модель данных тоже крайне проста
2) это фактически единственный язык в 60-е годы поддерживавший сложные структуры данных, сборку мусора, символьную обработку, рефлексию
как только начали появляться альтернативы он стал стремительно утрачивать популярность. сейчас у него особых достоинств нет - существует по инерции ну и легаси
но и до сих пор его самая крутая фича - это гомоиконный синтаксис (когда код и данные представлены одинаково). это привело к простоте концепции языка и к сомнительной концепции макросов, которые на бумаге выглядят красиво, но которые тяжело отлаживать. еще - интерактивная разработка: хакнул по-быстрому чего-то в емаксе и у тебя тут же все подхватилось, а в эклипсе понадобится знание раздутого апи и куча рестартов
>> так в жабе кстати не просто "хакнул-перезапустил" - там в сложном и довольно давно работающем приложении можно метод на лету переменить
это много где есть. а в жабе сигнатуру метода уже "на горячо" - не поменяешь или другой класс - не подсунешь. фича лиспа именно в сочетании этой возможности и REPL, который, к тому же интегрирован в IDE. именно что все рядом и удобно. и, хотя, REPL много где теперь - связка lisp, repl, emacs по удобству этим всем пользоваться - делает кучу всего одной левой