LISP


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

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

chicken start, load file, quit, compile file

$> 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

s-expressions

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


primitives 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"

atoms #f, #t

TODO

primitives cons, car, cdr;
predicate pair?

> (cons 1 2) 
(1 . 2)
> (set! x (cons 1 2))
> (car x)
1
> (cdr x)
2
> (pair? x)
#t
> (pair? 5)
#f

list structure

> (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 ())))

primitives 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)

primitives 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)

primitives length, append, max, min;
predicate 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))

numbers

primitives +, -, *, /, 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

predicates =, <, <=, >, >=

predicates - odd?, even?, positive?, negative?, zero?, integer?, real?

random nums

(random n)

> (map random (cdr '(1 2 3 4 5)))
(0 1 3 0)

complex numbers

(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)

bitwise primitives

(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)

strings

(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)

lambda

(define function_name (lambda (arg1 arg2 ...) (op arg1 arg2 ...)))

primitives 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

local variables

to define a local variable, use the let command

a let expression has two lists

> (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

primitives 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

primitives and, or, not

predicates - string?, number?, atom?, eq?, equal?

blocks: primitive 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


variable number of function' params

(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

primitives read, write, display, newline

TODO


успех Лиспа в свое время основывался на объективных факторах:
1) язык крайне прост в реализации и реализация эта компактна и помещалась в комп начала 60-х: тривиальный синтаксис, анализатор которого может написать любой (тогда) студент, да и внутренняя модель данных тоже крайне проста
2) это фактически единственный язык в 60-е годы поддерживавший сложные структуры данных, сборку мусора, символьную обработку, рефлексию
как только начали появляться альтернативы он стал стремительно утрачивать популярность. сейчас у него особых достоинств нет - существует по инерции ну и легаси

но и до сих пор его самая крутая фича - это гомоиконный синтаксис (когда код и данные представлены одинаково). это привело к простоте концепции языка и к сомнительной концепции макросов, которые на бумаге выглядят красиво, но которые тяжело отлаживать. еще - интерактивная разработка: хакнул по-быстрому чего-то в емаксе и у тебя тут же все подхватилось, а в эклипсе понадобится знание раздутого апи и куча рестартов

>> так в жабе кстати не просто "хакнул-перезапустил" - там в сложном и довольно давно работающем приложении можно метод на лету переменить

это много где есть. а в жабе сигнатуру метода уже "на горячо" - не поменяешь или другой класс - не подсунешь. фича лиспа именно в сочетании этой возможности и REPL, который, к тому же интегрирован в IDE. именно что все рядом и удобно. и, хотя, REPL много где теперь - связка lisp, repl, emacs по удобству этим всем пользоваться - делает кучу всего одной левой