Table of contents
EchoLisp is (yet another one) implementation of Lisp, not very far from Scheme, as far as syntax and concepts are concerned. For the novice reader, it is recommended to read an introduction to Scheme or Lisp before browsing this reference manual.
EchoLisp offers lexical scoping, tail call elimination, access to the browser local storage, a graphical library, complex numbers, large integers, a JSON library, {sets}, streams, syntax rules, background operations for complex drawings, CSS styled objects, rational numbers, good performances, a compiler, auto-completion, a notebook/worksheets interface and many more.
Last, and not the least, a complete on-line help system is available. See usage, apropos and help functions in the help chapter.
You can find code examples in the Rosetta Code wiki.
EchoLisp est une mise en oeuvre de Lisp, utilisant la syntaxe et les concepts de Scheme. Le lecteur novice trouvera ici en franรงais une excellente introduction ร Scheme, avant de naviguer dans ce manuel de rรฉfรฉrence.
EchoLisp fournit entre autres l'accรฉs ร la mรฉmoire persistante du navigateur, une librairie graphique, le calcul sur nombres complexes ou les grands nombres , une librairie JSON, des {ensembles}, des streams, des 'rรจgles de syntaxe' - macro รฉlaborรฉes - ร la Scheme, des fonctions qui travaillent en arriรจre-plan, des styles CSS, des fonctions de calcul sur les fractions, de bonnes performances, la compilation de fonctions, l' auto-complรฉtion pour faciliter la saisie.
Enfin, et non le moindre, un systรจme d'aide en ligne est disponible. Voir les fonctions usage, apropos et help dans le chapรฎtre help.
Des exemples de code sont proposรฉs dans le wiki Rosetta Code.
You can run EchoLisp as an inline WebApp - URL http://www.echolalie.org/echolisp, or download and decompress the echolisp.zip file. Click onto the index.html file in the directory used for extraction to locally run EchoLisp.
EchoLisp uses worksheets stored in a notebook. Worksheets have cells. Each cell has an input field - named stdin -, an output field - named stdout -, and an optional plotter field (an HTML canvas). Functions and buttons are provided to create/open/save worksheets in the notebook (browser local storage), add/show/hide/remove cells in a worksheet.
Cells come in two flavors :
You can toggle a cell type by pressing the ๐ or ๐ button. Cells are activated - given focus - by clicking inside the input field, or pressing a cell button.
;; open a worksheet at loading time (define (preferences) (worksheet-open "sandbox"))
(+ 42 624)
[0]โ 666
1000
[1]โ 1000
&1
[2]โ 1000
(+ &1 &0 &1)
[3]โ 2666
(* &3 &3)
[4]โ 7107556
"simon "
[5]โ "simon "
(string-append &5 "gallubert")
[6]โ "simon gallubert"
The lisp reader procedure will try to present choices based on the first characters you type and the frequency of preferred symbols.
To read and eval an input file located on your disk. EchoLisp input files have the ".txt" or ".scm", or ".glisp" extension. See todo.glisp for a simple application demo. On Mac OS X systems, TextWrangler is an excellent text editor to write syntax colored lisp source code. UTF-8 is the preferred encoding to use.
(*) According to the browser, it may be necessary to click on the tab labelled 'EchoLisp functions reference' to activate the help page or to allow permission to open this page.
;; usage : procedures with syntax, and arguments types. (usage cons) โ (cons item list1) (cons item null) (cons item1 item2) ;; (usage ...) can look for substrings (us app) โ (append list1 list2 โฆ ) ;; apropos : list of procedures names with min-arity:max-arity (apropos vect) โ #(๐ for*/vector:2:n ๐ for/vector:2:n ... vector-sort!:2 vector:0:n vector?:1 ) (ap list) โ #(๐ for*/list:2:n ๐ for/list:2:n alist?:1 circular-list:1:n ... vector->list:1 ) (ap ".*filter$") โ #(filter:2 stream-filter:2 vector-filter:2 ) ;; Opening help pages (help sin) โ "sin:1" ; opens page (or tab) help.html#sin (help append) โ "append:1:n" ; opens help.html#append ;; Symbol information (set by the user) (define (f x) (sin (cos (log x)))) (info 'f "hairy function") (f 6) โ -0.21741901623942123 (info 'f) โ "hairy function" (?? w) ; try me ;; documentation string (define (order a m) "multiplicative order : (order a m) โ n : a^n = 1 (mod m)" (assert (= 1 (gcd a m))...) (usage order) โ order : multiplicative order : (order a m) โ n : a^n = 1 (mod m)
Call of function function-id with arguments which evaluate to values of type typei, and evaluates to 'result'. Arguments types may be :
;; Examples - this is a comment
;; User input (source code) style may be changed in this document.
;; Click ๏ธ ๐จ
;; Or hit the +/- keys.
(here an example of user input)
โ output ;; as computed and printed
A symbolic expression - expression or expr for short - is either an atom or a list of zero or more expression(s).
Atoms are the basic components of expressions, and may be of type symbol or identifier, number, boolean, string.
(*) May include Unicode characters, as supported by your browser
; valid symbols
x let* รฉlรฉment PI aNoTher elvis! null + * f_4 ;; space separated
string->list jean-albert&antoinette
แผฯฮฟฮผฮฟฯ
๐-my-hidden-function-๐
other...
*calendar*
$รงยง^jqrTs%
&3
NSRunLoop DefWindowProc PERFORM exit jmpne
sort/name a|filter
(make-symbol "cat") โ cat
(make-symbol "cat") โ cat_1
; numbers
1 4e+10 -4 +666 0 ;; integer - exact
3.14 0.6789 ;; decimal - inexact
0xabcdef ;; hexadecimal - integer - exact
3/4 ;; rational - exact
1+i ;; complex - inexact
100_000_000 : 100000000
; strings
""
"I am a string"
"๐ฎ You have mail"
"A newline \n inside"
; lists or expressions
()
(cos PI) or [cos PI]
(a b c ( d e f (g h [ i 333 ])))
(๐ด โช๏ธ ๐ต ( ๐ โฐ ๐ ))
(+ 3 4)
[(= a b) hit!!] or ((= a b) hit!!)
("composite" 4555 log (tan PI))
; vectors
#()
#(1 2 3 5)
#(๐ต "๐ด " ( 3 4) (+ simon antoinette))
; start-end delimiters
(f |abc| ) โ (f | abc | )
; โ invalid symbols โ
albert:antoinette
_x
#sharp
@me
๐ : This is not a tomato. This is a symbol, the name of which is the Unicode character '๐'.
Every EchoLisp program is represented by a symbolic expression. The aim is to evaluate this expression. The evaluation rules are the following:
(*) It is not possible, in the current implementation, to redefine a system predefined symbol. We use the words 'function' or 'procedure' to denote the same thing.
;; a simple program
(define bonjour "Je te salue vieil Ocรฉan !") ;; defining and binding the symbol 'bonjour'
(display bonjour "color:blue") ;; native function call, with two parameters
โ Je te salue vieil Ocรฉan !
#f โ #f #t โ #t (not #f) โ #t (not 666) โ #f (not null) โ #f (or 1 2 3 #f 4) โ 1 (or (= 1 2) (= 1 3) 666) โ 666 (and (write 1) (write 2) (write 3) #f 4) โ 1 2 3 #f (and 1 2 3 4) โ 4 (not 0) โ #f (not (not ())) โ #t (not 'elvis) โ #f (define dead #f) โ dead (not dead) โ #t (if #t "true" "false") โ "true" (if #f "true" "false") โ "false" (if null "true" "false") โ "true" (boolean? #f) โ #t
(+ 42 666) โ 708 (+ 1/2 67 1/3) โ 407/6 (- 10 0.567) โ 9.433 (- 444) โ -444 (* 1/7 7/9) โ 1/9 (* 1 2 3 4 5 6 7) โ 5040 (/ 6) โ 1/6 (/ 6 7 8) โ 3/28 ;; rational result (// 6 7 8) โ 0.10714285714285714 ;; float result (min PI 22/7 42) โ 3.141592653589793 (max 10 8 6 4) โ 10 (apply max (iota 100)) โ 99 (lib 'math) (sigma identity 0 100) โ 5050 ;; = 100 * 101 / 2 - ๐ฉ young Gauss
Infinity -Infinity PI โ 3.141592653589793 PI/2 โ 1.5707963267948966 -PI โ -3.141592653589793 E โ 2.718281828459045 I โ 0+i LOG2 โ 0.6931471805599453 JOUR โ 86400 ;; 24 heures * 3600 secondes DAY โ 86400 ;; 24 * 3600 (cos PI) โ -1 (exp (* I PI)) โ -1+0i ;; eiπ = - 1 ๐ฉ Euler (log E) โ 1 (tan PI/2) โ 16331239353195370 (* I I) โ -1+0i (+ Infinity 7) โ Infinity (* Infinity -2016.2016) โ -Infinity
Set inclusion : Integer ⊂ Rational ⊂ Complex ⊂ Number. All predicates end with '?' and return #t (true) or #f (false).
(number? 42) โ #t (number? 'elvis) โ #f (integer? (- 6)) โ #t (rational? (/ 4 5)) โ #t (rational? (// 4 5)) โ #f (exact? PI) โ #f E โ 2.718281828459045 (inexact? E) โ #t (positive*? 0) โ #f (complex? 3+4i) โ #t (rational? 12) โ #t (complex? 9) โ #t (zero? 0+0i) โ #t
(even? 77) โ #f
(odd? 0) โ #f
(floor PI) โ 3
(ceil PI) โ 4
(ceil -PI) โ -3
(round E) โ 3
(square? (* 666 42 666 7 6)) โ #t
(square? 144/49) โ #t
(modulo 2015 7) โ 5
(modulo 2015 -5) โ 0
(quotient 9 4) โ 2
(1+ 7) โ 8
(1+ 22/7) โ 29/7
(1- I) โ -1+i
(add1 PI) โ 4.141592653589793
;; 49 nuances of gray
(lib 'plot.lib)
(define (quarante-neuf-nuances-de-gris x y)
(let ((x (modulo (floor x ) 7))
(y (modulo (floor y) 7))) (gray (// (+ x (* 7 y)) 48))))
(plot-rgb quarante-neuf-nuances-de-gris 7 7)
All of these functions work for integers < 2e+9. For larger integers, the bigint.lib may be used.
(gcd 42 666) โ 6
(gcd 42 666 33333333) โ 3
(lcm 42 666) โ 4662
(= (* 42 666) (* (gcd 42 666) (lcm 42 666))) โ #t
(factor 101) โ 101
(factor (* 3 5 7 9)) โ 3
(prime-factors 2015) โ (5 13 31)
(group (prime-factors 666)) โ ((2) (3 3) (37))
(prime? 101) โ #t
(primes 10) โ { 2 3 5 7 11 13 17 19 23 29 }
(next-prime 1000000000) โ 1000000007
(random-prime 1000000000) โ 125910523
(random-prime 2) โ 2
(lib 'bigint)
Lib: bigint.lib loaded.
(prime-factors (* 3 5 7 9 11 13 15 17)) โ (3 3 3 3 5 5 7 11 13 17)
(next-prime 1.e+20) โ 100000000000000000039
Perform logical operations on each corresponding bit - numbered from 0 to 31 - of two integers n and m. If n or m are not integers, they are converted.
(define (<< n m) (arithmetic-shift n m )) (define (>> n m) (arithmetic-shift n (- m))) (>> 666 1) โ 333 (>> 133 1) โ 66 (number->string 666) โ "666" (number->string 666 2) โ "1010011010" (number->string 666 16) โ "29a"
NB: more combinatoric functions are defined in the list.lib library.
(factorial 10) โ 3628800
(factorial 100) โ 9.33262154439441e+157
(Cnp 4 2) โ 6
(Cnp 1000 10) โ 2.6340956046197025e+23
;; (implode '(a b c)) -> ((a) (b) (c))
(define (implode lst) (cond ((null? lst) null) (else (map list lst))))
;; output all combinations of lst p to p.
;; Exemple only. Use the combinations function defined in list.lib.
(define (combine lst p) (cond
((null? lst) null)
((< (length lst) p) null)
((= (length lst) p) (list lst))
((= p 1) (implode lst))
(else (append
(map cons (circular-list (car lst)) (combine (cdr lst) (1- p)))
(combine (cdr lst) p)))))
(Cnp 5 3) โ 10
(combine '( albert simon antoinette ludwig elvis) 3) โ
((albert simon antoinette) (albert simon ludwig) (albert simon elvis) (albert antoinette ludwig) (albert antoinette elvis) (albert ludwig elvis) (simon antoinette ludwig) (simon antoinette elvis) (simon ludwig elvis) (antoinette ludwig elvis)) ;; 10 triplets
(define perm #(1 3 2 0))
(vector-permute! #(a b c d) perm) โ #( b d c a)
(lib 'bigint)
Lib: bigint.lib loaded.
(Cnp 1000 10) โ 263409560461970212832400
(factorial 100) โ
9332621544394415268169923885626670049071596826438162146
8592963895217599993229915608941463976156518286253697920
827223758251185210916864000000000000000000000000
22/7 โ 22/7 ;; no spaces to read a rational (rational 100 3450) โ 2/69 ;; creation (rational? 78) โ #t ;; an integer is also a rational (rational? 0.3) โ #f (rational? 22/7) โ #t (num 22/14) โ 11 (den 42/666) โ 111 (/ 44 14) โ 22/7 42/666 โ 7/111 (/ 1 2) โ 1/2 (// 1 2) โ 0.5 (+ 1 1/2 1/4 1/8) โ 15/8 (+ 666.42 1/2) โ 666.92 (+ 22/7 I) โ 3.142857142857143+i (expt 22/7 7) โ 3028.81317429691 PI โ 3.141592653589793 (rationalize PI 0.01) โ 22/7 (rationalize PI) โ 333/106 (rationalize PI 0.000001) โ 355/113 (// 355 113) โ 3.1415929203539825 (rationalize PI 0.000000001) โ 103993/33102 (// 103993 33102) โ 3.1415926530119025
and all usual functions: exp, expt, log, sin, ..
(plot-z-mod log -4 -4) โ plot log(z) in rectangle [-4-4i 4+4i].
3.2-4.8i โ 3.2-4.8i ;; no spaces to read a complex (complex? I) โ #t I โ 0+i (complex 3 4) โ 3+4i ;; creation (define z (complex 3 4)) โ z z โ 3+4i (angle z) โ 0.9272952180016122 (magnitude z) โ 5 (polar (magnitude z) (angle z)) โ 3+4i (conjugate z) โ 3-4i (exp (* I PI)) โ -1+0i ;; Euler formula (define (f z) (/ (1+ (* z z z)))) โ f ;; 1 / (z3+1) (f I) โ 0.5+0.5i (f 0.42-3i) โ -0.01366639866973426-0.03383001817614986i ;; Three poles of 1 / (z3+1) (lib 'plot.lib) โ Lib: plot.lib loaded. (plot-z-mod f -3 -3) โ plot f(z) in rectangle [-3-3i 3+3i].
z ∈ 𝓒 - x ∈ 𝓡
(fract PI) โ 0.14159265358979312 (abs -PI) โ 3.141592653589793 (cos PI) โ -1 (sin 22/7) โ -0.00126448893037729 (cos I) โ 1.5430806348152437+0i (sin I) โ 0+1.1752011936438014i (+ (* (cos I)(cos I)) (* (sin I) (sin I))) โ 1+0i (atan2 0 5) โ 0 (atan2 5 0) โ 1.5707963267948966 ;; PI/2 (log 6) โ 1.791759469228055 (log -3) โ NaN (log -3+0i) โ 1.0986122886681098+3.141592653589793i (exp (log 666)) โ 666.0000000000001 (expt 3 4) โ 81 (expt -3 4) โ 81 (expt 3 -4) โ 0.012345679012345678 (expt -3 -4.5) โ 0-0.007127781101106491i (sqrt 1000000000000) โ #1000000 (sqrt -9) โ 0+3i (sqrt I) โ 0.7071067811865476+0.7071067811865476i (cbrt -27) โ -3 (cbrt 0+i) โ 0.8660254037844389+0.49999999999999944i
(random) โ 0.621223164399653 (random-seed 'elvis) โ 0.03779020818580782 (random) โ 0.4152655335541243 (random) โ 0.5532895568415128 (random-seed 'elvis) โ 0.03779020818580782 (random) โ 0.4152655335541243 (random 100) โ 55 (shuffle '(a b c d)) โ (c a d b) (shuffle (iota 16)) โ (5 14 6 13 3 2 8 11 12 9 1 0 15 7 4 10) (unicode->list 9824 9831) โ (โ โก โข โฃ โค โฅ โฆ โง) (shuffle (unicode->list 9824 9831)) โ (โก โง โค โ โฆ โข โฃ โฅ) ;; sum of 1000000 random numbers (for/sum ((i 1000000)) (random)) โ 500188.5688371864 (for/sum ((i 1000000)) (random)) โ 499835.121561366 ;; random integers list (define (rand-list n (range 100) (acc null)) (if (zero? n) acc (rand-list (1- n) range (cons (random range) acc)))) โ rand-list (rand-list 22) โ (6 70 59 68 21 75 57 94 36 94 77 94 16 26 15 19 67 91 66 17 92 52) ;; throw dices (define (dice) (unicode->string (+ 0x2680 (random 6)))) โ dice (dice) โ โ (dice) โ โ (dice) โ โ
(define simon 999999) โ simon (symbol? 'simon) โ #t (symbol? simon) โ #f (number? simon) โ #t (procedure? append) โ #t (define (simon x)(+ x x)) โ simon (procedure? simon) โ #t (gensym) โ #:g1001 (symbol? (gensym)) โ #t (null? ()) โ #t (null? null) โ #t (null? 0) โ #f (list? '(a b c)) โ #t (pair? '(simon antoinette)) โ #t (pair? '(simon . antoinette)) โ #t (list? null) โ #t (pair? null) โ #f
(eq? 'simon 'antoinette) โ #f (eq? "simon" "simon") โ #t (eq? "simon" (string-append "si" "mon")) โ #t (eq? 0.5 2/4) โ #f (eqv? 0.5 2/4) โ #t (equal? 0.5 6/12) โ #t (eq? '(1 2 3) '(1 2 3)) โ #f (equal? '(1 2 3) (append '(1) '(2 3))) โ #t (eq? '#(1 2 3) '#(1 2 3)) โ #f (equal? '#(1 2 3) '#(1 2 3)) โ #t
(= 0.5 1/2) โ #t (= PI 3.14159) โ #f (= I 0+i) โ #t (= (sqrt 4) 2) โ #t (> I 8) ๐ฅ error: '>' : argument type is not correct : 0+i
(first '(1 2 3)) โ 1 (rest '(1 2 3)) โ (2 3) (cdr '(1)) โ null (define noms '(albert (ludwig wittgenstein) (simon gallubert) elvis)) (first noms) โ albert (rest noms) โ ((ludwig wittgenstein) (simon gallubert) elvis) (second noms) โ (ludwig wittgenstein) (third noms) โ (simon gallubert) (car noms) โ albert (caadr noms) โ ludwig (cdadr noms) โ (wittgenstein) (cdddr noms) โ (elvis) (cdr noms) โ ((ludwig wittgenstein) (simon gallubert) elvis)
๐ ๐ ๐ take may also be used to extract elements from various sequences types : (take vector n), (take string n), (take stream n), (take hash n), (take generator n), (take table n), (take function:1 n), etc. For compatibility or ignored reasons, (take list n) or (drop list n) may be written as (take n list) or (drop n list).
drop may also be used to drop elements from various sequences types : (drop vector n), (drop string n), (drop generator n).
(define nums (iota 9)) โ nums
nums โ (0 1 2 3 4 5 6 7 8)
(length nums) โ 9
(length noms) โ 4
(length '((d e f g h i) (x y z ludwig t))) โ 2
(last nums) โ 8
(list-tail nums 8) โ (8)
(list-tail nums 4) โ (4 5 6 7 8)
(list-tail nums -2) โ (7 8)
(list-ref nums 6) โ 6
(sublist nums 2 6) โ (2 3 4 5)
(last noms) โ elvis
(take '(a b c d e) 3) โ (a b c)
(take (iota 1000) 7) โ #{ 0 1 2 3 4 5 6 } ;; a list, also a set.
(take factorial 10) โ (1 1 2 6 24 120 720 5040 40320 362880)
(lib 'sequences)
(take 10 [7 50/3 ..])
โ (7 50/3 79/3 36 137/3 166/3 65 224/3 253/3 94)
(define oops (circular-list 'a 'b 'c 'd))
oops โ (a b c d a ..โ)
(length oops) โ Infinity
(list-ref oops 12567) โ d
'(42 . 666) โ {42 . 666} ;; pair
(define couple (cons 'albert 'antoinette)) โ couple
couple โ {albert . antoinette}
(car couple) โ albert
(cdr couple) โ antoinette
(pair? couple) โ #t
(list? couple) โ #f
(define other '(simon . antoinette)) โ other
other โ {simon . antoinette}
(pair? other) โ #t
Sublists - i.e. consecutive rests - of a list can be marked, unmarked with symbols, or any object. This does not modify the sublists, nor the items in the lists. If (mark-print) is #t ,marks appear in the printed output before the marked sublist.
(define persons '( Basin Ducret Potain Swann Verdurin)) (mark (rest persons) '๐ณ) persons โ (Basin ๐ณ Ducret Potain Swann Verdurin) (mark (member 'Swann persons) '๐) persons โ (Basin ๐ณ Ducret Potain ๐ Swann Verdurin) (length persons) โ 5 (mark-filter persons) โ ((๐ Swann Verdurin) (๐ณ Ducret Potain ๐ Swann Verdurin)) (mark-filter persons '๐) โ ((๐ Swann Verdurin)) ;; extract all marked items (map car (mark-filter persons)) โ (Swann Ducret) ;; unmark all (maplist unmark persons) persons โ (Basin Ducret Potain Swann Verdurin) ;; default print color for marks is red (mark (list-tail persons -1) 666) โ (Basin Ducret Potain Swann 666 Verdurin) (mark-print #f) โ #f ;; hide marks persons โ (Basin Ducret Potain Swann Verdurin) ;; Load combinations.glisp (maplist unmark persons) (comb-next persons 3) โ (Basin Ducret Potain) (comb-next persons 3) โ (Basin Ducret Swann) (comb-next persons 3) โ (Basin Ducret Verdurin) (comb-next persons 3) โ (Basin Potain Swann) ... (comb-next persons 3) โ (Potain Swann Verdurin)
null โ null ;; the empty list () โ null ;; the same ;; construction (cons 666 null) โ (666) (cons 9 (cons 8 (cons 7 (cons 6 null)))) โ (9 8 7 6) (cons 42 (iota 9)) โ (42 0 1 2 3 4 5 6 7 8) (list 6 7 8 9) โ (6 7 8 9) ;;dotted pairs (cons 'a 'b) โ (a . b) (rest (cons 'a 'b)) โ b (define friends '(jean albert simone)) โ friends (define other '(antoinette maurice)) โ other ;; new lists creation (append friends other) โ (jean albert simone antoinette maurice) (append other friends other) โ (antoinette maurice jean albert simone antoinette maurice) (cons 'snoopy friends) โ (snoopy jean albert simone) (list (list friends other (list (list other)))) โ (((jean albert simone) (antoinette maurice) (((antoinette maurice))))) ;; chirurgy : modifies friends friends โ (jean albert simone) (nconc friends other) friends โ (jean albert simone antoinette maurice) (set-car! friends 'elvis) friends โ (elvis albert simone antoinette maurice) (set-cdr! friends null) friends โ (elvis)
Iota, range and srange constructors return sets - which are also lists - of numbers. (range) works with integers, and (srange) handles any number type. step may be negative. Default values are start=0, step=1. Note that the end value is not included in the generated interval.
(iota 7) โ #{0 1 2 3 4 5 6}
(reverse (iota 8)) โ (7 6 5 4 3 2 1 0)
(range 4 9) โ #{4 5 6 7 8}
(range 4 16 3) โ #{4 7 10 13}
(srange 23 5 -7/4) โ #{ 23 85/4 39/2 71/4 16 57/4 25/2 43/4 9 29/4 11/2 }
(define somelist ' (a b c d e f g 666 h)) โ somelist
(member 42 somelist) โ #f ;; ๐ต does not return (), but #f
(member 'd somelist) โ (d e f g 666 h)
(filter number? somelist) โ (666)
(filter-count symbol? somelist) โ 8
(circular-list 'dog 'after 'tail) โ (dog after tail dog after ..โ)
(circular-list 1 2 3) โ (1 2 3 1 2 ... โ)
(cdddr (circular-list '(a b))) โ ((a b) (a b) (a b) ..โ)
(define (unicode->list from to)
(for/list ((i (in-range from to))) (unicode->string i)))
(unicode->list 0x1F628 0x1F637)
โ (๐จ ๐ฉ ๐ช ๐ซ ๐ฌ ๐ญ ๐ฎ ๐ฏ ๐ฐ ๐ฑ ๐ฒ ๐ณ ๐ด ๐ต ๐ถ ๐ท)
(define L (shuffle (iota 16))) โ L
L โ (13 10 5 3 2 0 7 6 1 9 15 4 11 8 12 14)
(list-sort < L) โ (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
(define (my-sort-function a b)(write 'compare a b) (> a b)) โ my-sort-function
(list-sort my-sort-function '(albert simon martine maurice))
compare albert simon
compare albert martine
compare simon martine
compare albert maurice
compare simon maurice
compare martine maurice
โ (simon maurice martine albert)
(define L '(๐ฟ ๐ฟ ๐ฟ ๐ ๐น ๐น ๐ป ๐ฟ ๐ฟ ๐ป))
(group L)
โ ((๐ฟ ๐ฟ ๐ฟ) (๐) (๐น ๐น) (๐ป) (๐ฟ ๐ฟ) (๐ป))
(group* L)
โ ((๐ฟ ๐ฟ ๐ฟ ๐ฟ ๐ฟ) (๐) (๐น ๐น) (๐ป ๐ป))
(flatten '((๐น ๐น) (๐ป) (๐ฟ ๐ฟ ๐ฟ ๐ฟ ๐ฟ) (๐)))
โ (๐น ๐น ๐ป ๐ฟ ๐ฟ ๐ฟ ๐ฟ ๐ฟ ๐)
(define task '(0 1 2 4 6 7 8 11 12 14 15 16 17 18 19 27 28 29 30 31 32 33))
(define ( g1 a b) (or (= a b) (= b (1+ a)))) ;; n and n+1 are considered equal
(group task g1)
โ ((0 1 2) (4) (6 7 8) (11 12) (14 15 16 17 18 19) (27 28 29 30 31 32 33))
(define L '((a b) (a c) (b d) (b e) (a z) (a x)))
(define (same u v) (eq? (first u) (first v)))
(group* L same)
โ (((a b) (a c) (a z) (a x)) ((b d) (b e)))
This library imports various operations on lists. The list-xxx! operations modify the list in place. Other operations return a new list. These functions do not operate on circular lists.
To create a new shallow copy of a list, use (append list ()) .
;; see selection sort for examples of use.
(lib 'list)
(list-rotate '(a b c d) 1) โ (b c d a)
(list-rotate '(a b c d) 40000001) โ (b c d a)
(list-partition (shuffle (iota 15)) < 9.5)
โ ((3 6 9 0 7 1 4 2 5 8) (12 13 14 10 11))
(define L '( 6 7 4 7 4 8 3 4))
(while (list-replace! L 4 666))
L โ (6 7 666 7 666 8 3 666)
(sublists (iota 3)) โ (() (2) (1) (1 2) (0) (0 2) (0 1) (0 1 2))
(length (sublists (iota 20)) ) โ 1048576 ;; 220
(for ((p (in-permutations 3))) (write p))
โ (0 1 2) (0 2 1) (2 0 1) (2 1 0) (1 2 0) (1 0 2)
(list-permute '(a b c d) '( 3 2 1 0)) โ (d c b a)
(list-permute '(a b c d) '( 0 0 1 2)) โ (a a b c)
(list-permute '(a b c d) #( 0 0 1 2)) โ (a a b c)
(combinations '(a b c d) 3) โ ((a b c) (a b d) (a c d) (b c d))
(combinations/rep '(a b) 3) โ ((a a a) (a a b) (a b b) (b b b))
An environment is a set of bindings which can be seen as a list ((name1 value1)(name2 value2) ...). Function calls, let forms, for loops create new environments, which are chained using the 'parent' link. Functions are provided to inspect environment, or create new ones. The printed form of an environment is #|environment name| .
Applies an operator to a list of values. operator and vali are evaluated before application. The operator may be a lambda expression i.e. an anonymous function such as (lambda(x) (+ x x)), a built-in function : sin, cos, .. , a user defined function or an expression which evaluates to an operator.
(sin 7) โ 0.656986598
(sin (+ 4 3)) โ 0.656986598
(sin (length '(a b c d e f g))) โ 0.656986598
((lambda(x) (sin x)) 7) โ 0.656986598
(define (f x) (sin x)) โ f
(f 7) โ 0.656986598
((lambda (x) ((if (> x 6) sin cos) x)) 7) โ 0.656986598
(define xsin sin) โ xsin
(xsin 7) โ 0.656986598
(define a 0) โ a
(set! a sin) โ a
(a 7) โ 0.656986598
(apply + '(1 2 3 4 5)) โ 15
(apply * (range 1 11)) โ 3628800 ;; โi iโ{1โฆ10} = 10!
(apply + (iota 1000)) โ 499500 ;; โi iโ{0โฆ999}
;; ๐ Sum of squares of the 7 first primes.
(apply + (map * (primes 7) (primes 7))) โ 666
(take factorial 10)
โ (1 1 2 6 24 120 720 5040 40320 362880)
(define (f n) (cos (* PI n)))
(take f 12)
โ (1 -1 1 -1 1 -1 1 -1 1 -1 1 -1)
A lambda expression - λ-expr - is an anonymous function with no arguments, a fixed number of arguments, or variable number of arguments. λ-exprs support default values for arguments. λ-exprs evaluate to themselves. To apply a λ-expr to a list of values, write ( λ-expr val1 ... valn) .
The λ-expr evaluates in sequence its body, a list of expressions expri, and the returns the value of the last evaluated expri.
λ-exprs with free variables inside - i.e. variables which are not arguments, are said to be closures. The value - binding - of a free variable is taken from the λ-expr definition environment.
๐ Lambda formal parameters such as x, y, name are printed out as _x, _y, _name ...
(lambda (x) (+ x x)) โ (ฮป (_x) ( + _x _x)) ;; self evaluates ((lambda (x) (+ x x)) 42) โ 84 ;; apply λ-expr to 42 ((lambda (x y z t) (+ x y z t)) 1 2 3 4) โ 10 ((lambda (x y . rest) (write x y rest) (+ x y)) 1 2 3 4 5 6) ;; binds rest to (3 4 5 6) 1 2 (3 4 5 6) โ 3 ;; binds all to list of argument values ((lambda all all) 'a 'b 'c 'd) โ (a b c d) ;; default value for nom ((lambda (prenom (nom 'gallubert)) (list prenom nom)) 'simon) โ (simon gallubert) ((lambda (prenom (nom 'gallubert)) (list prenom nom)) 'simon 'de-jeumont-schneidre) โ (simon de-jeumont-schneidre)
Closures are no more, no less than lambda expressions with their own environment. The free variables inside the lambda definition are bound to their values at lambda definition time.
;; f returns a closure, with free variables y and z (define ( f y z) (lambda (x) (writeln (environment-bindings (environment-current))) (+ x y z))) (define g (f 100 333) ) g โ (๐ ฮป (_x) (#writeln (#environment-bindings (#environment-current))) (#+ _x y z)) (g 666) ;; show the lambda environment bindings (("y" 100) ("z" 333)) โ 1099 ;; simple currying : transform an n-args procedure into a lambda expression with (n-1) arguments. (define (kurry proc x0) (lambda(y) (proc x0 y))) (kurry * 2) โ (๐ ฮป (_y) (proc x0 _y)) (define *-2 (kurry * 2)) (*-2 666) โ 1332 ;; Example : drawing a family of curves (s-curve x gamma) ;; (define (f-gamma x gamma) (lambda(x) (s-curve x gamma))) ;; and plot (f-gamma x gamma) - which is a function of x only - for each gamma ;; See or load curves.glisp;; Example : implement stack operations in message passing style ;; See or load snippets
A function - or procedure - is a named lambda expression. (define (f x y) (+ x y)) is the same as (define f (lambda(x y) (+ x y))). Evaluating f - the symbol - will return its associated lambda expression.
Primitives - built-in - functions symbols such as sin,append, ... evaluate as #sin, #append which is the printed representation of a built-in procedure.
Good practice: the first expression of the body may be a documentation string, which will be displayed by (usage function-id) or (us function-id).
(define (f x) (+ x x)) โ f f โ (ฮป (_x) (#+ _x _x)) (define (g x) "square : (g x) โ x^2" (* x x)) โ g (us g) (define (h x) (+ (f x) (g x))) โ h (f 1000) โ 2000 (g 1000) โ 1000000 (h 1000) โ 1002000 (define (w u) (f (g (h u)))) โ w (w 12) โ 56448 (define (f x y . rest) (write x y rest) (+ x y)) โ f (f 12 13 14 15 16) 12 13 (14 15 16) โ 25 (define (f x . add-list) (* x (apply + add-list))) โ f (f 10 1 2 3 4 5) โ 150 ;; 10 * (1+2+3+4+5) ;; default values (define (hit x (target 0) (precision 0.0001)) (if (< (abs (- x target)) precision) "OK" "KO")) โ hit (hit 0.01) โ "KO" (hit 0.00000001) โ "OK" (hit (acos -1) PI) โ "OK" (define (multi-valued x y z) (values (+ x y) (+ x z) (+ y z))) โ multi-valued (define-values (a b c) (multi-valued 11 12 13)) โ (a b c) a โ 23 b โ 24 c โ 25
Tail call elimination is implemented in EchoLisp for recursive tail calls.
(define (multiplier n m (acc 0)) ;; perform m additions
(if (zero? m) acc
(multiplier n (1- m) (+ acc n)))) โ multiplier
(multiplier 3 1000) โ 3000
(multiplier 3 1000000) โ 3000000
(time (multiplier 3 1000000)) โ 3000000
1099 msec
(time (multiplier PI 1000000)) โ 3141592.6535849427
1091 msec
(trace 'multiplier) โ #t
(multiplier 3 4) โ 12
๐ก [0] --> multiplier _n 3
๐ก [0] --> multiplier _m 4
๐ก [0] --> multiplier _acc 0
๐ก [0] multiplier <-- 12
;; ๐ The following is NOT tail call recursive : see [stack depth] in trace.
(define (multiplier n m)
(if (= 1 m)
n
(+ n (multiplier n (1- m))))) โ multiplier
(multiplier 3 4) โ 12
๐ก [0] --> multiplier _n 3
๐ก [0] --> multiplier _m 4
๐ก [1] --> multiplier _n 3
๐ก [1] --> multiplier _m 3
๐ก [2] --> multiplier _n 3
๐ก [2] --> multiplier _m 2
๐ก [3] --> multiplier _n 3
๐ก [3] --> multiplier _m 1
๐ก [3] multiplier <-- 3
๐ก [2] multiplier <-- 6
๐ก [1] multiplier <-- 9
๐ก [0] multiplier <-- 12
(multiplier 3 1000000)
๐๏ธ error: stack[10002] : stack overflow : 10001
For functions which take one integer argument - and may return any object - , and in case of frequent access or recursive calls, the cache allows to compute once, store and retrieve the values of (f n). The computation of (f n) should not include side effects, or take into account the values of global variables which may change.
;; fob(n) = fob(n-1) + fob(n-2) + fob(n-3) (define *calls* 0) ;; calls counter (define (fob n) (++ *calls*) ;; bumps counter (if (< n 3) n (+ (fob ( - n 1)) (fob (- n 2)) (fob (- n 3))))) โ fob (fob 20) โ 101902 *calls* โ 128287 ;; ๐ (remember 'fob) โ #t (set! *calls* 0) โ *calls* (fob 20) โ 101902 *calls* โ 21 ;; ๐ (define (fib n) (if (< n 2) n (+ (fib (1- n)) (fib (- n 2))))) (time (fib 27)) โ 196418 time:435 msec (define (fib n) (+ (fib (1- n)) (fib (- n 2)))) (remember 'fib #(0 1)) ;; first two values in cache (time (fib 27)) โ 196418 time:0 msec
curry is functionally equivalent to: (define (curry proc . left-args) (lambda right-args (apply proc (append left-args right-args))))
(-> 0 sin cos display) โ 1 ;; same as (display ( cos (sin x)))
(define (f x) (-> x (* 10) (/ 2) (writeln "f"))) ;; same as (writeln (/ (* x 10) 2) "f")
(f 4)
โ 20 "f"
(define (g x) (->> x (* 10) (/ 2) (writeln "g"))) ;; same as (writeln "g" (/ 2 (* 10 x)))
(f 4)
โ "g" 1/20
;; using on an infinite list [0 ..]
;; sum of the first 10 even squares
(lib 'sequences)
( ->> [0 ..] (map * _ _ ) (filter even?) (take 10) (apply +))
โ 1140
(define add42 (curry + 42)) โ add42
(add42 666) โ 708
(map (curry cons 'simon) '( gallubert garfunkel et-merveilles))
โ ((simon . gallubert) (simon . garfunkel) (simon . et-merveilles))
;; an other way :
(map cons (circular-list 'simon) '( gallubert garfunkel et-merveilles))
โ ((simon . gallubert) (simon . garfunkel) (simon . et-merveilles))
(define f (compose sin cos)) โ f
(f 7) โ 0.6844887989926141
(sin(cos 7)) โ 0.6844887989926141
(define abscos (compose abs cos)) โ abscos
(abscos PI) โ 1
(define g (compose exp log)) โ g
(g 42) โ 42.00000000000001
(define cos10 (iterate cos 10)) โ cos10
(cos10 1.0) โ 0.7442373549005569
(define cos100 (iterate cos10 10)) โ cos100
(cos100 0.6) โ 0.7390851332151605
(cos 0.7390851332151605) โ 0.7390851332151608 ;; ๐ fixed point found
Inline functions are standard javascript mathematical expressions -strings - compiled into functions. They may be used for speed, or convenient one-liners, for function plotting, etc. They use up to 4 parameters, namely and mandatorily x,y,z,t. They cannot be re-defined into standard lambda functions. An inline function must use the return keyword. The ^ (exponentiation) operator is allowed: x^4 is expanded into pow(x,4).
Known constant and functions (all arguments values ar numbers) :
[E, PI, SQRT2, acos, asin, atan, atan2, ceil, floor, hsl , max, min, random, sin, cos, tan, log, pow, exp, random, round, rgb ,sqrt, cbrt, fract, /* integers */ isprime, factor, factorial, issquare, gcd, lcm, powmod] .
(inline (sphere x y z) "x-= 3 ; return x^2 + y^2 + z^2 - 25") (plot-3d-xyz sphere)
Functions may be compiled into javascript functions, for better performance and lesser clarity. Speed improvement is x3 or x4. Note that no type checking nor trace is performed by compiled functions. The printed name of a compiled function is #_๐ท_name, or #_๐ถ_name for "float" functions.
options-string may include the following options:
(lib 'plot)
(lib 'compile)
(define (pixel x y)
(rgba (atan x) (atan y) 0 (+ (sin x) (sin y))))
pixel โ (ฮป (_x _y) (#rgba_clamp (#atan _x) (#atan _y) 0 (#+ (#sin _x) (#sin _y))))
(compile 'pixel "-v-f")
๐ก [0] compiling _๐ถ_pixel ((#rgba_clamp (#atan _x) (#atan _y) 0 (#+ (#sin _x) (#sin _y))))
;; generated code:
var ref,top = _blocks[_topblock];
/* */return (
/* */_rgba_clamp(Math.atan(_stack[top]),Math.atan(_stack[1 + top]),0,
(Math.sin(_stack[top]) + Math.sin(_stack[1 + top])))
/* */);
pixel โ (ฮป (_x _y) (#_๐ถ_pixel))
;; "-float" option in action
(define (f x y) (+ x y))
(compile 'f)
f โ (ฮป (_x _y) (#_๐ท_f))
(f 1/4 1/3) โ 7/12
(compile 'f "-float")
f โ (ฮป (_x _y) (#_๐ถ_f))
(f 1/4 1/3) โ 0.5833333333333333
The let family forms introduce local bindings which are only valid inside the (let ....) lexical scope. A (let ...) form generates one (or more) λ expressions with their own environments.
(let ((x 3)(y (+ 10 20))) (* x y)) โ 90 (let ((x 3) (y (+ x x))) (* x y)) โ โ error: |user| : unbound variable : x (let* ((x 3) (y (+ x x))) (* x y)) โ 18 (letrec [(local-even? (lambda (n) (if (= n 0) #t (local-odd? (- n 1))))) (local-odd? (lambda (n) (if (= n 0) #f (local-even? (- n 1)))))] (list (local-even? 23) (local-odd? 23))) โ (#f #t) (let countdown [(i 10)] (if (= i 0) 'liftoff (begin (write i) (countdown (- i 1))))) 10 9 8 7 6 5 4 3 2 1 โ liftoff
An other way to use local variables/functions inside functions is to define them inside the function body, or to declare them as optional arguments. These variables are allocated onto the stack.
;; let
(define (f x y)
(let ((r2 (+ (* x x) (* y y))))
;; computations using r2 here ...
r2))
f โ (f (_x _y) ((#ฮป (_r2) _r2) (+ (* _x _x) (* _y _y))))
(f 30 40)
โ 2500
;; local define
(define (f x y)
(define r2 (+ (* x x) (* y y)))
;; ...
r2)
f โ (f (_x _y _r2) (set! _r2 (+ (* _x _x) (* _y _y))) _r2)
;; optional arg
(define (f x y (r2))
(set! r2 (+ (* x x) (* y y)))
;; ...
r2)
f โ (f (_x _y _r2) (set! _r2 (+ (* _x _x) (* _y _y))) _r2)
;; defining an internal function
(define (f x y)
(define (g a b) (+ (* a a) (* b b)))
;; ...
(g x y))
f โ (f (_x _y _g) (set! _g (#ฮป (_a _b) (+ (* _a _a) (* _b _b)))) (_g _x _y))
(f 3 4)
โ 25
N.B: Definitions of variables or functions are possible inside a function definition. These variables will act as local variables. See a convoluted example.
(define a 123) โ a a โ 123 (define b PI) โ b b โ 3.141592653589793 (set! b "albert") โ b b โ "albert" (define cube (lambda(x) (* x x x))) โ cube (cube 666) โ 295408296 (define-values (a b c) (values 10 (* 10 10) (* 10 10 10))) โ (a b c) (+ a b c) โ 1110 (define-constant PI/4 (/ PI 4)) โ PI/4 PI/4 โ 0.7853981633974483 ;; local - inner - definitions (define (f x y) (define local-z ( + x y)) ;; var (define (local-f u v) (* u v)) ;; function (local-f local-z local-z)) ;; call of locally defined function (f 10 20) โ 900
(define x 42) โ x
(set! x 666)
x โ 666
(define a 100) โ a
(+= a 333) โ 433
a โ 433
(define assign 0)
(set! assign set!)
(assign assign 333)
assign โ 333
;; local binding for x
((lambda (x) x) 'albert) โ albert
((lambda (x) (set! x 'antoinette) x) 'albert) โ antoinette
;; global
x โ 666
;; errors
(set! not-defined 2015)
โ error: set! : unbound variable : not-defined
;; values
(define-values (albert simon) (values 42 84))
(set!-values (albert simon) (values simon albert))
albert โ 84
map applies a function to successive elements of list(s), and returns the list of results. foldl and foldr applies a function to successive elements of list(s) and return the accumulated result. foldl applies from left to right, foldr applies from right to left. Iterations stops as soon as the last element of one of the lists is reached.
maplist applies a function to successive rests of a list, and returns the list of results.
Let lista = (a1 a2 โฆ an) and listb = (b1 b2 โฆ bn), fun:i a function which takes i arguments.
(define alist '(a1 a2 a3 a4)) โ alist (define blist '(b1 b2 b3)) โ blist (for-each write alist blist) โ null a1 b1 a2 b2 a3 b3 (iota 9) โ (0 1 2 3 4 5 6 7 8) (map even? (iota 9)) โ (#t #f #t #f #t #f #t #f #t) (map * (iota 10) (iota 10)) โ (0 1 4 9 16 25 36 49 64 81) (map cons alist blist) โ ((a1 . b1) (a2 . b2) (a3 . b3)) (map (lambda(x) (* x 666)) (iota 10)) โ (0 666 1332 1998 2664 3330 3996 4662 5328 5994) (map * (iota 7) (circular-list 999)) โ (0 999 1998 2997 3996 4995 5994) (foldl + 0 (iota 10)) โ 45 ;; = 1 + 2 + .. + 9 (foldl cons null alist) โ (a4 a3 a2 a1) (foldr cons null alist) โ (a1 a2 a3 a4) (foldl string-append "" alist blist) โ "a3b3a2b2a1b1" (foldr string-append "" (iota 5) (iota 5)) โ "0011223344" (any (lambda ( x y) (= 42 (* x y))) (range 100) (rest (range 100))) โ (6 . 7)
Vectors implement variable length arrays of lisp objects.. Vectors do self-evaluate.
(vector? 'elvis) โ #f (vector 8 9 '(+ 5 7) 10) โ #(8 9 (+ 5 7) 10) (define simon (make-vector 7)) โ simon simon โ #(0 0 0 0 0 0 0) (vector-fill! simon 666) โ #(666 666 666 666 666 666 666) (define simon (list->vector (range 2 17 3))) โ simon simon โ #(2 5 8 11 14) (vector-ref simon 3) โ 11 [simon 3] โ 11 (vector-set! simon 3 1000) โ 1000 simon โ #(2 5 8 1000 14) (vector-map * simon simon simon) โ #( 8 125 512 1000000000 2744) (vector-filter prime? simon) โ #(2 5) (vector-member 1000 simon) โ 3 (define (cube x) (* x x x)) โ cube (define simon (build-vector 10 cube)) โ simon simon โ #(0 1 8 27 64 125 216 343 512 729) (vector-sort! > simon) โ #(729 512 343 216 125 64 27 8 1 0) (define inside (make-vector 5 444)) inside โ #(444 444 444 444 444) (vector-set! simon 4 inside) simon โ #(729 512 343 216 #(444 444 444 444 444) 27 8 1 0) (vector? simon) โ #t
Types are used to check - at run-time - that function call arguments values conform to the function signature, that structures slots values are well typed, or to check that a given set of values conforms to a pattern. Types may describe different kind of patterns : atoms (numbers, symbols, etc.) , finite lists, infinite lists, lists of lists, vectors, instances of structures. A Type is defined by a type-expression, which is one of :
Types do auto-evaluate. Use (type-inspect type-name) to see the inside. The make-type function do not evaluate its arguments.
(lib 'types) (make-type NumPair (Number Number)) ;; A list of two numbers (type-check '( 6 7) NumPair) โ #t (type-check '( 6 abcd ) NumPair) ๐ก error: NumPair : type-check failure : abcd (make-type NumList (Number ...)) โ NumList - a list of n numbers (type-check (iota 42) NumList) โ #t ;; Type : integers in range [1 .. 10] ;; defined by a predicate (define (one-ten? x) (in-interval? x 1 10)) (make-type one-ten [Integer & one-ten?]) ;; or defined by a choice (make-type One-ten [ 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 ]) (type-check 7 One-ten) โ #t (type-check 42 One-ten) โ error: One-ten : type-check failure : 42 ;; Handling the exception (define (on-error-10 n) (writeln n 'out-of-range) 10) (type-check 12 One-ten on-error-10) 12 out-of-range โ 10
Types may be declared for functions arguments or structures fields. Assigned values will be checked against the argument or the field type. A type declaration has the following syntax : type-name:variable-id.
(lib 'types) (define (sum-list NumList:xs) (apply + xs)) (signature 'sum-list) โ (NumList) (sum-list (iota 8)) โ 28 (sum-list "albert") โ error: NumList : type-check failure : albert โ 'sum-list:xs' (define (surface real:a real:b real:c ) ;; Hรฉron formula - a,b,c are the triangle sides (define p (// (+ a b c ) 2)) (sqrt (* p (- p a) (- p b) (- p c)))) (surface 3 4 5) โ 6 (signature 'surface) โ (Real Real Real _) (surface "heron" 4 5 ) ๐ฃ error: Real : type-check failure : heron โ 'surface:a'
Typed vectors are constant sized vectors, with predefined elements type and size. See reference for more information. They allow quick access, and less memory consumption. The available types are : uint8, uint8-clamped, uint32, int32, float32, float64. Note: pop, push, .. operations will not work on fixed length vectors.
(lib 'vlib) (make-float32-vector 4 42.5) โ #float32( 42.5 42.5 42.5 42.5) (make-uint32-vector 8) โ #uint32( 0 0 0 0 0 0 0 0)
Bit-vectors - sets of #f/#t values - are implemented using uint32 vectors
.The empty set is โ
, or null. A set is โ
, or an unordered list of numbers, symbols, strings, lists or sets, without duplicates. The sets { a b} and { b a} are the same set. ( a a b) is a list, but not a set.
For convenience, make-set - the set constructor - re-orders the elements with the following precedence order : โ
< number < symbol or string < list < set .
Sets do self evaluate.
(make-set '( b b b a b 1 "b" c (e f) (f e) (f e) 12)) โ { 1 12 a b c (e f) (f e) }
(define A (make-set ' ( ๐ ๐ ๐ ๐ ))) (define B (make-set ' ( ๐ ๐ ๐ )))
(set-intersect A B) โ { ๐ ๐ }
(set-union A B) โ { ๐ ๐ ๐ ๐ ๐ }
(set-substract A B) โ { ๐ ๐ }
(set-sym-diff A B) โ { ๐ ๐ ๐ }
(set? โ
) โ #t
(set-intersect (range 7 999) (range 995 2000)) โ { 995 996 997 998 }
;; power set : set of all subsets : 2Card(A) elements.
(define (set-cons a A) (make-set (cons a A)))
(define (power-set e)
(cond ((null? e)
(make-set (list โ
)))
(else (let [(ps (power-set (cdr e)))]
(make-set
(append ps (map set-cons (circular-list (car e)) ps)))))))
(power-set B) โ { โ
{ ๐ } { ๐ ๐ } { ๐ ๐ ๐ } { ๐ ๐ } { ๐ } { ๐ ๐ } { ๐ } }
;; The Von Neumann universe
(define V0 (power-set null)) V0 โ { โ
}
(define V1 (power-set V0)) V1 โ { โ
{ โ
}}
(define V2 (power-set V1)) V2 โ { โ
{ โ
} { โ
{ โ
}} {{ โ
}}}
(define V3 (power-set V2)) V3 โ { โ
{ โ
} { โ
{ โ
}} { โ
{ โ
} { โ
{ โ
}}} { โ
{ โ
} { โ
{ โ
}} {{ โ
}}} { โ
{ โ
} {{ โ
}}} { โ
{ โ
{ โ
}}} { โ
{ โ
{ โ
}} {{ โ
}}} { โ
{{ โ
}}} {{ โ
}} {{ โ
} { โ
{ โ
}}} {{ โ
} { โ
{ โ
}} {{ โ
}}} {{ โ
} {{ โ
}}} {{ โ
{ โ
}}} {{ โ
{ โ
}} {{ โ
}}} {{{ โ
}}}}
(define V4 (power-set V3)) (length V4) โ 65536
;; Cartesian products of A and B : set of all pairs ( a . b) such as a โ A, b โ B.
(define-syntax-rule (Card A) (length (make-set A)))
(define (set-product A B)
(make-set
(for*/list ((a A)(b B)) (cons a b))))
(define ranks {A R D V 10 9 8 7 6 5 4 3 2})
(define suits {โ โฅ โฆ โฃ})
(style 'โฆ "color:#c00000")
(style 'โฅ "color:#c00000")
(set-product ranks suits) โ { (2 . โ ) (2 . โฃ) (2 . โฅ) (2 . โฆ) (3 . โ ) (3 . โฃ) (3 . โฅ) (3 . โฆ) (4 . โ ) ... (R . โฅ) (R . โฆ) (V . โ ) (V . โฃ) (V . โฅ) (V . โฆ) }
(Card (set-product ranks suits)) โ 52
All functions which return a string return a new string. There is no 'character' type in EchoLisp. Characters are simply strings of length 1. See for example string->list and unicode->string. Input string delimiters are " ..." or #' ... '#.
Use \n to insert a new line character, \" to protect the double quote.
'here-strings' are delimited by #<< ... >>#. They may include new lines, separators, etc.
(string-delimiter "|") "B B King" โ |B B King| #'She says: "Here he comes"'# โ |She says: "Here he comes"| #<<
He says: "Here I am". >># โ |He says: "Here I am".|
char-code may be decimal: 1028, hexadecimal:0x404, unicode:#\u0404
(define intro "Longtemps je me suis couchรฉ")
(string-length intro) โ 27
(string-ref intro 3) โ "g"
(string-append intro " de bonne heure.") โ "Longtemps je me suis couchรฉ de bonne heure."
(string-join (iota 4) " - ") โ "0 - 1 - 2 - 3"
(string-append "[" (string-join (iota 4) ",") "]") โ "[0,1,2,3]"
(string-rest intro) โ "ongtemps je me suis couchรฉ"
(string-upcase intro) โ "LONGTEMPS JE ME SUIS COUCHร"
(string-randcase intro) โ "longtEMpS Je Me SuIs couchร"
(string-randcase intro) โ "lonGTEMps jE me Suis cOUchรฉ"
(string-replace intro "couchรฉ" "levรฉ") โ "Longtemps je me suis levรฉ"
(string=? "Long" "long") โ #f
(string-ci=? "Long" "long") โ #t
(substring intro 4) โ "temps je me suis couchรฉ"
(substring intro 4 10) โ "temps "
(substring intro -6) โ "couchรฉ"
(string-append intro " " (unicode->string 0x1F604))
โ "Longtemps je me suis couchรฉ ๐"
(string-delimiter "") โ
(unicode->list 0x2744 0x274E) โ (โ โ
โ โ โ โ โ โ โ โ โ)
(string->list intro) โ (L o n g t e m p s j e m e s u i s c o u c h รฉ)
(string-delimiter "-") โ ---
(string->list 1234566) โ (-1- -2- -3- -4- -5- -6- -6-)
(string->list (iota 5)) โ (-0- -1- -2- -3- -4-)
(number->string 666) โ "666"
(number->string 666 16) โ "0x29a"
(number->string 666 2) โ "|2|1010011010"
;; See also Markov algorithm for strings manipulations.
Regular expressions - regexp - may be used in replace, split or match functions. The syntax and use or regular descriptions are depicted in the Javascript reference.
Regular expressions are objects which may be created using the "/pattern/" syntax, or by the make-regexp function : (make-regexp pattern). Regular expression objects do auto evaluate, and are printed as #regexp:pattern. In the following, regexp is a simple string, a regexp string - "/pattern/" - , or a regexp object. Note: special characters like "\" must be protected by "\" inside a regexp string.
(string-replace intro "/.e/" "โฆe") โ "Longโฆemps je me suis couchรฉ" (string-replace intro "/.e/" "โฆe" "g") โ "Longโฆemps โฆe โฆe suis couchรฉ" (define R (make-regexp "(\\w+)\\s(\\w+)")) ;; word- 1 space - word R โ #regexp:/(\w+)\s(\w+)/ (string-replace "Simon Gallubert" R "$2 $1") โ "Gallubert Simon" (string-match "Simon Gallubert" "/s.*g/" "i") โ #t (string-match "Simon Gallubert" "/s.*g/" ) โ #f (string-split "Simon Gallubert on the moon" "/mo+/") โ ("Si" "n Gallubert on the " "n") (regexp-exec R "Ludwig Wittgenstein") โ ("Ludwig" "Wittgenstein") (regexp-exec R "Elvis") โ #f (define RANGE (make-regexp "^ *(\-?\\d+)\-(\-?\\d+) *$" )) ;; number-number RANGE โ #regexp:/^ *(-?\d+)-(-?\d+) *$/ (regexp-exec RANGE "4--12") โ ("4" "-12")
Milliseconds, seconds, hour, .. are optional, in that order. Month must be in[1-12], day in [1-7], hour in [0-23].
Multiplier is optional - default 1 - , positive or negative.
Unit-name is one of [year, month, week, day, hour, mn, minute, second, sec] or [an, mois, semaine, jour, heure, minute, seconde, longtemps], singular or plural.
Or, without multiplier, [now, today, tomorrow, yesterday, maintenant, demain, hier].
Languages :
fr,en,be, ...
Options names and combinations:
weekday, year, month, day, hour, minute, second
weekday, year, month, day
year, month, day
year, month
month, day
hour, minute, second
hour, minute
hour12 : #t or #f
Options possible values:
"narrow", "short", "long" ,"numeric", "2-digit".
(define std-format '((hour numeric) (minute numeric) (month long) (weekday long) (day numeric)))
(date->string (current-date)) โ "15/4/2015 12:15:05"
(define now (current-date)) โ now
now โ Wed Apr 15 2015 12:15:19 GMT+0200 (CEST)
;; ๐บ pause-cafรฉ โ๏ธ
(define later (current-date)) โ later
(date-diff later now) โ 166 ;; seconds
(- later now)
โ error: sub : expected numeric value
;; default formatting
(string->date "2016 1 1") โ Fri Jan 01 2016 00:00:00 GMT+0100 (CET)
(string->date "2016 Feb 1") โ Mon Feb 01 2016 00:00:00 GMT+0100 (CET)
(date->string (string->date "2016 Feb 31")) โ "2/3/2016 00:00:00"
(define now (current-date)) โ now
now โ Fri Apr 17 2015 13:05:57 GMT+0200 (CEST)
(date-add! now 3600)
now โ Fri Apr 17 2015 14:05:57 GMT+0200 (CEST)
(date->seconds now) โ 1429272357
(date 2 2 2 2 2 2) โ Sun Feb 02 1902 02:02:02 GMT+0100 (PMT)
(date-format (current-date ) "fr" std-format) โ "dimanche 10 mai 14:15"
(date-format (current-date ) "be" std-format) โ "ะฝัะดะทะตะปั, 10 ะผะฐั 14.28"
(date-format (current-date) 'ja std-format) โ "5ๆ10ๆฅๆฅๆๆฅ 14:40"
(define my-format '((second "2-digit" ) (minute numeric) (hour "2-digit") (hour12 #t)))
(date-format (current-date ) "fr" my-format) โ "2:22:22 PM" ;; sans tricher
(date-format (date 3 'mois) 'fr std-format) โ "dimanche 16 aoรปt 2015 11:41"
(date-format (date -1 'week) 'en std-format) โ "Monday, May 11, 2015, 11:42 AM"
(date-format (date 'longtemps) 'fr std-format) โ "mardi 20 avril 2021 12:23"
(date-format (date -100 'longtemps) 'fr std-format) โ "samedi 31 octobre 1125 10:33"
(begin expr1 โฆ. exprn) โ Eval expr1โฆn & return exprn
(begin0 expr1 โฆ. exprn) โ Eval expr1โฆn & return expr1
(when cond expr1 โฆ exprn) โ If cond is #t eval expr1โฆn & return exprn - else return #f
(unless cond expr1 โฆ exprn) โ If cond is not #t eval expr1โฆn & return exprn - else return #t
(if cond t-expr f-expr) โ If cond is #t eval and return t-expr else eval and return f-expr
(cond (test1 expr1 โฆlast1) (test2 expr2 โฆlast2) โฆ) โ If testi is #t, eval expri โฆ & return lasti. Else return #f
(cond (test1 expr1 โฆlast1) (test2 expr2 โฆlast2) โฆ (else else1 .. last_else)) โ If testi is #t, eval expri โฆ & return lasti. If no success, eval else1 โฆ & return last_else.
(case key ((datum11 datum12 โฆ ) expr1 โฆlast1) ((datum21 datum22 โฆ ) expr2 โฆlast2) (else else1 .. last_else)) โ If key matches - eqv? - one of datumij, eval expri โฆ and return lasti. If no success, eval else1 โฆ and return last_else. If no success and no else clause, return #f.
(begin (write 1) (write 2) (+ 3 4) (+ 5 7) 0) โ 0 (if #t 3 4) โ 3 (if #f 5 (* 3 4)) โ 12 (if (string>? "albert" "antoinette") 'albert 'antoinette) โ antoinette ((if #t * +) 7 6) โ 42 ((ฮป (x y) ((if (> x y) * +) x y)) 6 7) โ 13 ((ฮป (x y) ((if (> x y) * +) x y)) 7 6) โ 42 (define (f a b) (cond ((> a b) (write a "gt" b) a) ((< a b) (write a "lt" b) b) (else (write "equal") (+ a b)))) โ f (f 4 5) โ 4 "lt" 5 โ 5 (f 55 4) โ 55 "gt" 4 โ 55 (f -1 -1) โ "equal" โ -2
(for โฆ) iterates over local variables vi, which take values in range expressions, evaluates a body = sequence of expressions expri, and returns the successive values of the last one accumulated in sum, product, vector or list etc. Iterations stops as soon as a range is exhausted, or a #:break is encountered. The for iterations forms are based on Scheme and Racket.
(for* โฆ) nests iterations.
Keywords:
#:break condition : stops the while, for or for* execution if condition is #t.
#:break condition => ret-expression : stops the while, for or for* execution if condition is #t, and returns the value of ret-expression.
#:continue condition : interrupts the body execution - without accumulating -, restarts the next while, for or for* iteration if condition is not #f.
#:when condition : Same as #:continue (not condition).
In the following, expri is [expression | #:when condition | #:break condition | #:continue condition]. start, end, incr are numbers. i, j, k, , vi are the loop formal parameters = any symbol. body is a sequence or expr
An iteration expression (id expr) will assign the consecutive values of expr - which may-be a numerical range, sequence, vector, .. to the local variable id. Multiple assignments are possible: ((id1 id2 ..) expr). When expr returns (v1 v2 ..) vi is assigned to idi. When expr returns pairs - eg. hash table - , use ((id1 . id2) expr) to bind the values.
(for ((n 7)) (write (* n n n))) โ
0 1 8 27 64 125 216
(for ((i (in-range 2 6 3/7))) (write i)) โ
2 17/7 20/7 23/7 26/7 29/7 32/7 5 38/7 41/7
(for ((i 3)(j (in-range 6 10))) (write (list i j))) โ
(0 6) (1 7) (2 8)
(for ((i 1000)(j 1000)) #:break (= (+ i j) 10) (write i j))
โ 0 0 1 1 2 2 3 3 4 4
(define noms '(albert simon ludwig elvis)) โ noms
(define scores '(45 99 34 555)) โ scores
(for ((n noms)(s scores)) (write (list n s))) โ
(albert 45) (simon 99) (ludwig 34)
;; ๐ด Why bother with a recursive factorial ? : 9!
(for/product ((f (in-range 2 10))) f) โ 362880
;; sum(1/n2) = π2/6
(for/sum ((n (in-range 1 100000))) (// 1 (* n n))) โ 1.6449240667982423
(/ (* PI PI) 6) โ 1.6449340668482264 ;; ๐ฒ proof
;; Find x : cos(x) = x
(lib 'math)
(for/fold (x 0.5) ((i 1000000)) #:break (~= x (cos x)) (cos x))
โ 0.7390851332151605
;; Iterate over vector elements
(define V (list->vector (iota 100)))
(for/sum [(vi V)] vi) โ 4950
;; Iterate over hash table
(lib 'hash)
(define H (list->hash '((a . 1) (b . 2)(c . 3)) (make-hash)))
(for [ ((k . v) H)] (writeln 'key k 'value v))
;; Nested loops
(for* ((i 3)(j (in-range 6 10))) (write (list i j)))
โ (0 6) (0 7) (0 8) (0 9) (1 6) (1 7) (1 8) (1 9) (2 6) (2 7) (2 8) (2 9)
(for*/sum ((i 1000)(j 1000)) 1) โ 1000000 ;; count nested loops
;; Σ Σ (i + j - 1) = n3
(for*/sum ((i (in-range 1 1001)) (j (in-range 1 1001))) (+ i j -1)) โ 1000000000
;;Break and continue
(for*/list ((i 4)(j 5)) #:continue (even? (+ i j)) (list i j))
โ ((0 1) (0 3) (1 0) (1 2) (1 4) (2 1) (2 3) (3 0) (3 2) (3 4))
(for*/list ((i 4)(j 5)) #:break (> (+ i j) 4) (list i j))
โ ((0 0) (0 1) (0 2) (0 3) (0 4) (1 0) (1 1) (1 2) (1 3))
;; Local bindings may be used to initialize range expressions
(for* ((i 5) ( j (1+ i))) (when (zero? j) (writeln)) (write (list i j)))
(0 0)
(1 0) (1 1)
(2 0) (2 1) (2 2)
(3 0) (3 1) (3 2) (3 3)
(4 0) (4 1) (4 2) (4 3) (4 4)
;; Break and return value
(define i 0)
(while #t
(set! i (1+ i))
#:break (> i 10) => 'NO_MORE
(write i))
โ 1 2 3 4 5 6 7 8 9 10
NO_MORE
(do ((variable1 init1 step1) โฆ) (test final1 โฆ) expr1 โฆ)
Not very often used. See the Scheme report, expressions, 4.2.4.
The amb library implements the non-deterministic amb operator as defined by John McCarthy : selection of choices among lists of values, and backtracking until all required conditions - constraints - are met.
(lib 'amb) (define (sum13 nums) (= 13 (apply + nums))) ;; sum of numbers must be 13 ;; first number in [0..6], second in [0..4], third in [0..7] (amb-select sum13 (list (iota 7) (iota 5) (iota 8))) โ (2 4 7) (amb-select/random sum13 (list (iota 7) (iota 5) (iota 8))) โ (3 4 6) (amb-select/random sum13 (list (iota 7) (iota 5) (iota 8))) โ (5 3 5) (amb-select/all sum13 (list (iota 7) (iota 5) (iota 8))) โ ((2 4 7) (3 3 7) (3 4 6) (4 2 7) (4 3 6) (4 4 5) (5 1 7) (5 2 6) (5 3 5) (5 4 4) (6 0 7) (6 1 6) (6 2 5) (6 3 4) (6 4 3))
(lib 'amb)
;; find numbers a,b such as a3 + b3 is a square
(define (square-sum context)
(define a (amb context (range 1 100)))
(define b (amb context (range 1 100)))
(amb-require (< a b))
(amb-require (square? (+ (* a a a ) (* b b b ))))
(writeln 'square-sum-of-cubes a b)
(amb-fail)) ;; show all solutions
(amb-run square-sum (amb-make-context)) โ
square-sum-of-cubes 1 2
square-sum-of-cubes 2 46
...
square-sum-of-cubes 10 65
square-sum-of-cubes 11 37
...
Near the same construct as in javascript. Note that the catch procedure has two parameters. An error-id is a symbol. The body of a try or catch expression is a sequence of expressions. Its value is the value of the last evaluated expression
See or load calc.glisp for use of (catch) and (throw)
Stacks may be used when appropriate in place of lists, for performance or simplicity reasons. Stacks have identifiers - stack-id , are global objects, are not bound to a variable with the same name. Stacks pop values LIFO style. Use (stack (gensym)) to get a safe, anonymous stack. Stack values may be any EchoLisp object. See html example.
(push 'my-stack (+ 2000 15)) โ 2015 (push 'my-stack 'simon) โ simon (pop 'my-stack) โ simon my-stack โ error: |user| : unbound variable : my-stack (pop 'my-stack) โ 2015 (pop 'my-stack) โ #f (define (list->html item) (if (list? item) (begin (push 'html "<ul>\n") (for-each list->html item) (push 'html "</ul>\n")) (begin (push 'html "<li>") (push 'html item) (push 'html "</li>\n")))) (stack 'html) (list->html '(people (gallubert simon) ( wittgenstein ludwig ) (presley (elvis aaron) ))) string-join (stack->list 'html) " ") โ
Boxes are 1-dimension object, which serve as containers for a value, and allow to pass objects by reference.
(box 42) โ #[box 42] (define schrรถdinger (box "cat")) โ schrรถdinger schrรถdinger โ #[box "cat"] (box? schrรถdinger) โ #t (box? "cat") โ #f ;; ๐ "cat" is a string is not a box (set-box! schrรถdinger "dog") โ #[box "dog"] schrรถdinger โ #[box "dog"] (unbox schrรถdinger) โ "dog" ;; passing objects by reference (define (fill-box b) (set-box! b "chinchard")) โ fill-box (fill-box schrรถdinger ) (unbox schrรถdinger ) โ "chinchard"
Delay and force implement lazy evaluation by means of promises objects.
Promises are displayed as 'promise:' - waiting to be forced - or 'promise!' - forced and cached -
(define aard-work (delay (+ 21 21))) aard-work โ #[promise: (#+ 21 21)] (force aard-work) โ 42 aard-work โ #[promise! 42] (promise? aard-work) โ #t (promise? 42) โ #f (define (prom m) (delay (begin (write "computing next prime " m) (next-prime m)))) โ prom (define next1000 (prom 1000)) next1000 โ #[promise: (#begin (#write "computing next prime " m) (#next-prime m))] (force next1000) โ "computing next prime " 1000 1009 next1000 โ #[promise! 1009] ;; cached value (force next1000) โ 1009
Lists are pairs of values (first-value . rest-value) : rest-value is either a list or the empty null list. Values can be extracted by the first (synonym car) and rest (synonym cdr) procedures.
Streams can be seen as pairs (first-value . rest-value) which can be extracted by the stream-first and stream-rest procedures. The difference with a list is that rest-value is either a stream, or a procedure which returns a stream. The computation of rest-value is delayed, and forced only if needed. This allow to - recursively - construct infinite streams.
Like for lists, a constructor - stream-cons - is provided, and various operations such as map, filter, .. can be performed on (infinite) streams.
make-stream is used to build a stream from a function which takes a state in input and returns a pair (value . new state).
empty-stream is a pre-defined object, which evaluates to itself, the equivalent of null for lists.
See for constructs, for usage of sequences/streams as iterators.
;; using make-stream
(define odds (make-stream
(lambda (state) (cons state (+ state 2)))
1)) โ odds
(stream-first odds) โ 1
(stream-first (stream-rest odds)) โ 3
odds โ #stream:id:2 first: 1
(for ((i 9)) (write (stream-iterate odds)))
1 3 5 7 9 11 13 15 17
odds โ #stream:id:2 first: 19 ;; modified stream
;; using stream-cons
(define (integers-starting-from n)
(stream-cons n
(integers-starting-from (+ n 1)))) โ integers-starting-from
(define n666 (integers-starting-from 666))
n666 โ #stream:id:12 first: 666
(stream->list n666 10) โ (666 667 668 669 670 671 672 673 674 675)
n666 โ #stream:id:12 first: 666
(define fibs
(stream-cons 0
(stream-cons 1
(stream-add (stream-rest fibs) fibs)))) โ fibs
(stream->list fibs 10) โ (0 1 1 2 3 5 8 13 21 34)
;; built-in numerical streams
(define a (in-range 5 9 1/3))
(stream->list a 7) โ (5 16/3 17/3 6 19/3 20/3 7)
;; sequence
(define inf (in-cycle '( a b c)))
(take inf 10) โ (a b c a b c a b c a)
;; usage in a (for ...) loop
(for/list ((i (in-range+ 2 12 2))) i) โ (2 4 6 8 10 12)
A property list (plist for short) is a hash table of (key value) pairs associated with a symbol. A key is either a symbol or a string. There are no duplications among the keys; a property list may only have one property at a time with a given key. Plists are slightly deprecated and may be remplaced by hash tables.
(putprop 'simon 66 'age) โ 66
(putprop 'simon '(my-life me-and-Sigmund) 'books) โ (my-life me-and-Sigmund)
(get 'simon 'age) โ 66
(get 'simon "age") โ 66
(get 'simon 'books) โ (my-life me-and-Sigmund)
(putprop 'simon 'antoinette 'wife) โ antoinette
(symbol-plist 'simon)
โ (("age" 66) ("books" (my-life me-and-Sigmund)) ("wife" antoinette))
(plist-keys 'simon) โ ("age" "books" "wife")
(for ((k (plist-keys 'simon))) (writeln k (get 'simon k)))
"age" 66
"books" (my-life me-and-Sigmund)
"wife" antoinette
(remprop 'simon 'wife) โ #t ;; ๐ก divorce
(get 'simon 'wife) โ #f
Hash tables - hash for short - extend property lists. A hash object is a set of unordered (key . value) pairs. A key is either a symbol, a number, or a string or a list of [symbol|number|string]. There are no duplications among the keys; a hash may only have one value at a time with a given key.
Keys are tested with equal? predicate, i.e '(a b c) and (cons a '( b c)) are the same key, although not the same object in memory.
(lib 'hash) (doc #t) โ #t (define H (make-hash)) โ H (list->hash '((simon . antoinette) (georges . ludwig) ((antoinette simon) . (jeremy kevin)) (2015 . wedding)) H) โ #hash:5 ;; 5 elements in H (hash-ref H 'simon) โ antoinette (hash-ref H '(antoinette simon)) โ (jeremy kevin) ;; keys and values may be lists (hash-set H 'elvis "the king") (hash-ref H 'elvis) โ "the king" (hash->list H) โ ((simon . antoinette) (georges . ludwig) ((antoinette simon) jeremy kevin) (2015 . wedding) (elvis . "the king")) H โ #hash:5 ;; Using hash to cache (remember) a function values (define DISTANCES (make-hash)) (define (dist x y) (writeln 'compute:dist x y) (sqrt (+ (* x x) (* y y)))) (hash-ref! DISTANCES '(3 4) dist) compute:dist 3 4 ;; value is computed โ 5 (hash-ref! DISTANCES '(3 4) dist) โ 5 ;; value is cached ;; retrieving keys (hash-get-key H '(jeremy kevin)) โ (antoinette simon) (hash-get-key H 'wedding) โ 2015 ;; indexing (hash-make-index H) โ 5 (hash-index-key H 3) โ 2015 (hash-index-value H 3) โ wedding (hash-index-value H 333) ๐ก error: hash-index-value : index out of range : 333 ;; iterating with (for ..) ;; (first element) is key ;; (rest element) is value (for ((element H)) (write (first element))) โ simon georges (antoinette simon) 2015 elvis ;; hash values (hash 'Simon) โ 4297711 (hash "Simon") โ 1598507
Tables are ordered collections of rows - records - , the contents of which are array-like values of consecutive fields - slots, columns - inside a row. Table may be filled with instances of structures or list of values. A table is associated with a structure, which give names to the fields.
Tables may be indexed - sorted - and searched by row-number, or contents of fields. The select SQL statement allows elaborate searchs, selections, and grouping.
Example in Rosetta code
(sql-select [distinct] fields from table [where-clause] [order-clause] [group-clause] [into-clause] [limit num-records]) fields := field-name [ field-name ..] | * | (aggregate-function field-name) ... field-name := field-number | structure-name.slot-name aggregate-function := min|max|sum|count where-clause := where (where-proc:1) | where (where-proc:2 arg2) order-clause := order-by field-name [asc|desc] ... group-clause := group-by field-name ... into-clause := into table where-proc := a procedure which will be given a record - instance of structure - as first argument, and must return #t or #f. Inside a where-proc, the (row-num) function returns the current record row number. (sql-select ..) returns a list of records or a list of groups , each group being a list of records. If the into option is used, sql-select stores the results - append mode - in the output table. (sql-delete from table [where-clause]) deletes all records for which (where-proc record [arg2]) is #t. Delete all records if no where-clause. Returns table.
Example in Rosetta code
An association list (alist for short) ia a list of (key value) pairs. Keys need not to be unique. The look-up procedure return #f or the first found pair matching a key.
(define echolalie '((ceo simon) (engineer antoinette) (programmer jean-albert))) โ echolalie
(alist? echolalie) โ #t
(assoc 'ceo echolalie) โ (ceo simon)
(assoc 'engineer echolalie) โ (engineer antoinette)
(assoc 'ludwig echolalie) โ #f
(set! echolalie (cons '(ceo antoinette) echolalie)) โ echolalie
echolalie
โ ((ceo antoinette) (ceo simon) (engineer antoinette) (programmer jean-albert))
(assoc 'ceo echolalie) โ (ceo antoinette)
;; use second item (= cadr) as key
(define by-value (association-procedure equal? cadr)) โ by-value
(by-value 'simon echolalie) โ (ceo simon)
CSS styles may be applied to classes of objects (error, string, ..) or particular symbols. Use the function style to specify a style.
;;; CLASSES and DEFAULT STYLES
(style) ->
(("echo" "color:gray")
("error" "color:red")
("jserror" "color:magenta")
("warning" "color:orangered")
("trace" "color:gray")
("store" "color:green")
("string" "color:darkslategray")
("function" "color:blue")
("mark" "color:red")
("complex" "color:brown")
("bigint" "color:green")
("javascript" "color:black")
("lambda" "color:blue;font-weight:bold")
("ฮป" "color:blue;font-weight:bold"))
I
โ 0+i
(style "complex" "color:red")
โ "complex"
I
โ 0+i
(style "string" "text-transform: capitalize")
โ "string"
'("albert" "ludwig" "elvis")
โ ("albert" "ludwig" "elvis")
(style 'elvis "font-size:24px;color:red")
'(albert elvis antoinette)
โ (Albert elvis Antoinette)
Errors, either EchoLisp or user generated, are displayed in red color and stop program execution, i.e return to top-level. Javascript detected error are displayed in magenta color and stop execution. ๐ซ Please, be so kind to report these magenta errors. Warnings are displayed in orange color and do not stop program execution.
Results of input/output operations, either successful or not, are displayed in green color and generally do not stop program excecution.
(+ 8 9)))) ๐ warning: reader : too many right parenthesis: ')' โ 17 (for ((i 99999999)) (if (= i 666) (error "bad number:" i))) ๐ฌ error: bad number: 666
(define (f n) (if (<= n 0) 2 (* n (f (- n 2))))) โ f (trace 'f) โ #t ๐ก [0] --> f _n 9 ๐ก [1] --> f _n 7 ๐ก [2] --> f _n 5 ๐ก [3] --> f _n 3 ๐ก [4] --> f _n 1 ๐ก [5] --> f _n -1 ๐ก [5] f <-- 2 ๐ก [4] f <-- 2 ๐ก [3] f <-- 6 ๐ก [2] f <-- 30 ๐ก [1] f <-- 210 ๐ก [0] f <-- 1890 (f 9) โ 1890 (untrace 'f) โ #f (console-log "here" 333) javascript console : EchoLisp[0] here 333 sysfun.js (ligne 1037) (js-eval "window.location.href") โ "file:///Users/echolalie/www/glisp/index.html" (define (f n) (for/sum ((i n)) i)) โ f (f 10) โ 45 (time (f 1000000)) โ 499999500000 773 ;; milli seconds (debug 1) (define (f u) (lambda(x) (+ u x))) ;; ๐ f is closing the free variable u compiled :: (๐ ฮป (_u) (ฮป (_x) (#+ u _x))) (f 444) compiled :: (f 444) โ (๐ ฮป (_x) (#+ u _x)) ;; ๐ and returns a closure (define (f x) (abs (sin( * x PI)))) ;; โญ๏ธ = compiled function composition compiled :: (ฮป (_x) (โญ๏ธ #abs (#sin (#* _x 3.141592653589793)))) (debug 0) ;; finished
(define (i-adder list) (cons + list))
(input-expr i-adder "Please, enter a list of numbers")
8 9 6
โ 23
(define (input-number num)
(if (number? num)
(do-something num)
(input-expr input-number "number ???")) (void))
(input-expr input-number "Please, enter a number")
(read-from-string input-string) parses input-string and return a symbolic expression. The top level loop may be described as :
(writeln (eval (read-from-string user-input-line))).
(read-from-string "(+ 1 2)") โ (+ 1 2) (eval (read-from-string "(+ 1 2)")) โ 3
(read), (read-string) (read-number) and (read-list) use the browser prompt mechanism. They return #f if the user cancels the operation.
(let ((age (read 32 "Elvis age?")))
(if (number? age) age
(error "not a number" age))) โ โฆ
(read-string "gallubert" "your name?") โ user string
(read-list "42 666" "Please, enter two numbers") โ a list
The write/display operations write to stdout. They all return (void).
(for ((i 5)) (write i)) โ 0 1 2 3 4
(display 2015 "color:blue;font-size:24px") โ
2015
(write "Longtemps je me suis couchรฉ") โ "Longtemps je me suis couchรฉ"
(display "de bonne heure.") โ de bonne heure.
The format-string contains a text - pattern- to be filled with arguments values.
It can optionally contain embedded format specifiers that are replaced by vali arguments values and formatted as requested. A format specifier follows this prototype:
The specifiers are the following :
(printf "percents : %.2d %%" 12.45678) โ percents : 12.46 %
(printf "hexa: %x" PI) โ hexa: 0x3.243f6a8885a3
(printf "~20a ~20a%n~20a ~20a" "simon" "gallubert" "elvis" "presley") โ
simon gallubert
elvis presley
;; tab width 12. (default is 16)
(printf "digits: %12t%d %t%d %t%d" 5 6 7) โ digits: 5 6 7
(html-print "<img src='http://www.quotehd.com/imagequotes/authors5/ludwig-wittgenstein-quote-the-limits-of-my-language-mean-the-limits.jpg' height = 400>")(lib 'sql) (html-print (table->html my-table))
Requires the print library. Remember that also exist array-print and table-print in matrix.lib and sql.lib.
(lib 'print)
(define V (make-vector 3 (make-vector 2 (iota 8))))
(pp V 80)
#( #( { 0 1 2 3 4 5 6 7 } { 0 1 2 3 4 5 6 7 })
#( { 0 1 2 3 4 5 6 7 } { 0 1 2 3 4 5 6 7 })
#( { 0 1 2 3 4 5 6 7 } { 0 1 2 3 4 5 6 7 }))
(define (add-level node chain target nums (new))
"add nodes in Knuth's power tree"
(vector-push chain (node-datum node))
(cond [(node-leaf? node)(for [(prev chain)] (set! new (+ prev (node-datum node)))(when (= new target) (power-hit target chain ))#:continue (vector-search* new nums)(node-add-leaf node new)(vector-insert* nums new))][else (for [(son (node-sons node))](add-level son chain target nums )) ])(vector-pop chain))
(pp add-level)
( add-level (_node _chain _target _nums _new)
"add nodes in Knuth's power tree"
(#vector-push _chain (node-datum _node))
( #cond
( (node-leaf? _node)
( #for ((prev _chain))
(#set! _new (#+ prev (node-datum _node)))
(#when (#= _new _target) (power-hit _target _chain))
#:continue (#vector-search* _new _nums)
(node-add-leaf _node _new)
(#vector-insert* _nums _new)) )
(else (#for ((son (node-sons _node))) (add-level son _chain _target _nums))))
(#vector-pop _chain))
The use of meta keys allows to map a key-press: modifier+letter or modifier+digit to a string which will be inserted at the cursor position.
The modifier is one of ["alt"|"ctrl"|"cmd"], as known by the browser. Use "alt" for "option".
;; shows the default mapping : GREEK ALPHABET
(meta-keys) โ
Modifier: null
(("0" "โ") ("1" "โ๏ธ") ("2" "โ") ("3" "โ๏ธ") ("4" "โ๏ธ") ("5" "โ
") ("6" "๐ฉ") ("7" "โ๏ธ") ("8" "๐") ("9" "๐") ("a" "ฮฑ") ("b" "ฮฒ") ("g" "ฮณ") ("d" "ฮด") ("e" "ฮต") ("z" "ฮถ") ("h" "ฮท") ("t" "ฯ") ("i" "ฮน") ("k" "ฮบ") ("l" "ฮป") ("m" "ฮผ") ("n" "ฮฝ") ("x" "ฮพ") ("q" "ฮฟ") ("p" "ฯ") ("r" "ฯ") ("w" "ฯ") ("s" "ฯ") ("u" "ฯ
") ("f" "ฯ") ("c" "ฯ") ("y" "ฯ") ("o" "ฯ") ("A" "ฮ") ("B" "ฮ") ("G" "ฮ") ("D" "ฮ") ("E" "ฮ") ("Z" "ฮ") ("H" "ฮ") ("T" "ฮค") ("I" "ฮ") ("K" "ฮ") ("L" "ฮ") ("M" "ฮ") ("N" "ฮ") ("X" "ฮ") ("Q" "ฮ") ("P" "ฮ ") ("R" "ฮก") ("S" "ฮฃ") ("U" "ฮฅ") ("F" "ฮฆ") ("C" "ฮง") ("Y" "ฮจ") ("O" "ฮฉ"))
;; use the Control key as modifier
(define-modifier-key "ctrl")
;; typed: ctrl-P,ctrl-A, etc...
โ ฮฆฮฮกฮฉฮฃ
(meta-key "A" "Antoinette")
(meta-key "d" "(define "))
;; typed: ctrl-d, ctrl-A , 0 , ")"
โ (define Antoinette 0)
(meta-key "d" "(date->date-string (current-date))")
;; typed : ctrl-d + Enter
โ "26/8/2015"
(stdin-color "magenta") (stdout-color "#8866dd") (stdout-font) โ "Lucida Sans Typewriter,Verdana,Arial,Helvetica,sans-serif" (stdout-font "Monospace") ;; useful for tabulated output (stdout-font-size 18) (define (preferences) (stdout-font "Monospace") (stdin-font-size 16))
Files are loaded asynchronously. Server default location : the source file names located on the server are in the ".lib" directory, suffixed by ".glisp". For local file loading - use full path - or the Load button.
The default file path may be changed using the *home* global variable. E.g. (set! *home* "file:///Users/echolalie/www/glisp/lib/")
(load 'combinations) Loaded : ./lib/combinations.glisp usage: (define mylist ... ) (comb-next mylist p) (load "foo.txt") [404] Cannot load : ./lib/foo.txt (load 'curves) (load 'todo) The following will work if EchoLisp is locally installed. (load "file:///Users/echolalie/www/glisp/lib/calc.glisp") You can load cross-domains files by disabling the browser security. For Chrome/Mac OS, run the following command : /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --disable-web-security The cors-everywhere Mozilla add-on allows to bypass cross-domain checking under Firefox.
Converts a local file or URL to a string. The file contents is displayed in a new cell.
(define (success file-name text) (writeln 'OK file-name text ))
(file->string success) โ #t ;; browser file selection dialog
T1.txt -> string
OK "T1.txt" "What is it?"
;; with cors-everywhere active
(file->string success "http://www.google.com")
save-as uses the browser download mechanism to save the printed - text - representation of an object into a file located in the browser download disrectory. Filename must have the extensions .txt (default) or .htm, .html. According to the browser, successive occurences ot the same file will be labelled filename(1), filename(2), etc.
The local database persistently store and retrieve values (lisp objects) or functions definitions (strings) inside the browser's local storage.
The local data base is organized into named stores, each store remembering pairs of (symbol value). The starting stores are 'user' - which is the default - , 'system', 'noteboook, 'reader' and 'words'. The user can add/delete stores and their contents.
A qualified symbol/function name store-name.symbol-name denotes a symbol in store store-name. The default store is "user".
(local-stores) โ ("system" "user" "words" "reader" "test" "foo" "gee" "books")
(local-stores "o") โ ("words" "books" "foo")
(local-delete-store! 'foo) โ "foo"
(local-delete-store! 'user) โ #f
๐ local-db: Cannot delete: user
(local-make-store 'french) โ "french"
Symbols bindings and procedure definitions - strings - may be stored/retrieved into/from a local store. In the following, symbol is the name of a bound symbol, or of a prodedure.
;; working in "user" store
(define friends '( elvis ludwig broderick)) โ friends
(local-put 'friends) โ friends
(define friends null)
(local-get 'friends) โ (elvis ludwig broderick)
friends โ (elvis ludwig broderick) ;; new binding
(local-keys ) โ ( "*meteo*" "*todo*" "aalert" "alert" "friends" "pi" "preferences" "xalert")
(local-symbol? 'friends) โ #t
;; working in "french" store
(define french.friends '(albert (antoinette ornella) simon)) โ french.friends
(local-put 'french.friends) โ french.friends
(local-keys 'french) โ ("friends")
(define french.friends 333)
(local-get 'french.friends) โ (albert (antoinette ornella) simon)
french.friends โ (albert (antoinette ornella) simon) ;; new binding
(local-get 'foo) โ null
๐ local-db: Undefined key : "user.foo"
Local stores may be used for (key value) access. Keys are either user defined or are integer numbers automatically generated and incremented.
In the following, key is either a symbol name, string, number - user key -, or one of 0, 'auto, #:auto which all mean auto-increment.
;; The books data base
;; First, we need to create the books store
(local-make-store 'books) โ "books"
;; Book structure definition
;; Store it, with key "book-record"
(define book-record (struct book (name title date))) โ book-record
(local-put-value 'book-record book-record 'books) โ "book-record"
;; Add a few books. Use auto-increment keys
(local-put-value #:auto (book 'ludwig 'tractatus 1918) 'books) โ 1
(local-delete 1 'books) โ #t
(local-put-value #:auto (book 'Wittgenstein 'Tractatus 1918) 'books) โ 2
(local-put-value #:auto (book 'McCarthy 'Lisp 1960) 'books) โ 3
;; inspect all keys in store
(local-keys 'books) โ (2 3 "book-record")
;;; A few days later ...
;; Important to get the structure back
(local-get-value 'book-record 'books) โ #struct:book [name title date]
(book-name (local-get-value 2 'books)) โ Wittgenstein
(book-title (local-get-value 3 'books)) โ Lisp
(local-verbose #t) โ #t
(local-get-value 42 'books)
๐ local-db: Undefined key : "books.42" โ null
The user defined preferences function is automatically evaluated at boot time, and automatically saved in the 'user' package.
(*)store may not be one of : system, user, reader, or words.
(define (preferences) (stdout-font-size 14) (lib 'struct) (lib 'plot)) ;; a preferences function ;; our package for f(x) = ax2 + bx + c polynomials (define (quad.roots a b c) ;; returns 2 roots (let* [(a (* 2 a)) (delta (/ (sqrt (- (* b b) (* 2 a c))) a)) (b (- (/ b a)))] (list (+ b delta ) (- b delta)))) โ quad.roots (quad.roots 1 0 1) โ (0+i 0-i) (quad.roots 1 0 -1) โ (1 -1) (define (quad.value x a b c) (+ (* a x x) (* b x) c)) โ value at x (define (quad.plot a b c xmin) ;; plot ax2 + bx + c (let ((f (lambda(x) (+ ( * a x x) ( * b x) c )))) (plot f xmin ) (plot-grid 1 1) (plot-axis 0 0 'red))) (define quad.errmess "not quadratic (a = 0)") ;;Look for definitions in memory (definitions) preferences : (define (preferences) (lib 'timer) (lib 'struct)) quad.roots : (define (quad.roots a b c) ;; returns 2 roots [...]) quad.value : (define (quad.value x a b c) (+ (* a x x) (* b x) c)) quad.plot : (define (quad.plot a b c xmin) ;; plot ax2 + bx + c [...]) ;; saving the quad.* symbols and functions (save-package 'quad) โ (quad.roots quad.value quad.plot quad.errmess) ;; loading and using the package (load-package 'quad) โ (quad.plot quad.errmess quad.value quad.roots) (quad.roots 3 -2 -1) โ (1 -1/3) (quad.plot 3 -2 -1 -2) โ;; Editing a function (edit 'quad.roots) (define (quad.roots a b c) (when (= a 0) (error quad.errmess 0)) ;; added (let* โฆ))) (save-package 'quad)
A reader-procedure pre-processes the raw list of symbols, strings, lists ... emitted by the lisp reader, before any evaluation. If takes in input a list of one or more tokens, and must return a list of one or more expressions to be evaluated. The reader-procedure is removed when it returns (#f) .
See, or load calc.glisp for an example of use : a calculator in infix notation.
The reader translation table allows to translate characters or strings at read time. Use (reader-translate old-string null) to reset an entry in the table.
(reader-translate "," " ") ;; ignore commas '[ a, b, c] โ (a b c) (reader-translate "," null) ;; revert to normal processing
The reader dictionary, an associative list of (key value), allows to translate symbols names at read time. Keys and values must be strings.
(load 'calc)
(calc) โ #t ;; installs the reader proc to eval infix notation
The new prompt : Calc expression here - $ to quit -
1 + cos(PI) โ 0
prime? (101) โ 1 ;; YES
$ โ calc:quit ;; un-installs
;; changing the prompt
(reader-set-prompt! "My own personal prompt")
;; ๐ฃ Careful here ๐ฃ
(reader-dict-new ' (("PERFORM" "apply")))
(PERFORM + (iota 11)) โ 55
Text can be parsed - exploded into a list of strings - either using the default separators : ()+-.;;,?!'" , or by providing a string of separators. Spaces,tab and newline are always separators.
(define mytext "Longtemps, je me suis couchรฉ de bonn'heur; A peine ma bougie รฉteinte, je m'endormais!!.")
(text-parse mytext)
โ ("Longtemps" "," "je" "me" "suis" "couchรฉ" "de" "bonn" "'" "heur" ";" "A" "peine" "ma" "bougie" "รฉteinte" "," "je" "m" "'" "endormais" "!" "!" ".")
(text-parse mytext ";,")
โ ("Longtemps" "," "je" "me" "suis" "couchรฉ" "de" "bonn'heur" ";" "A" "peine" "ma" "bougie" "รฉteinte" "," "je" "m'endormais!!.")
โBackquoteโ or โquasiquoteโ expressions are useful for constructing a list structure when most but not all of the desired structure is known in advance.
(define boys '(elvis simon albert)) โ boys (define girls '(antoinette ornella)) โ girls (quote boys) โ boys (quasiquote girls) โ girls (quasiquote ( boys girls)) โ (boys girls) (quasiquote ( family boys (unquote girls))) โ (family boys (antoinette ornella)) (quasiquote (family boys (unquote-splicing girls))) โ (family boys antoinette ornella)
''ludwig โ 'ludwig
`(list ,(+ 1 2) 4) โ (list 3 4)
'(boys girls) โ (boys girls)
`(boys girls) โ (boys girls)
`( boys ,@boys girls girls (+ 2 2)) โ
๐ก expands: (#quasiquote (boys (#unquote-splicing boys) girls girls (+ 2 2)))
โ (boys elvis simon albert girls girls (+ 2 2))
`( boys ,boys girls ,girls ,(+ 2 2)) โ (boys (elvis simon albert) girls (antoinette ornella) 4)
`( boys ,@boys girls ,@girls ,(+ 2 2)) โ (boys elvis simon albert girls antoinette ornella 4)
(let ((name 'elvis)) `(list ,name ',name)) โ (list elvis 'elvis)
(list 1 2 ,3 4)
๐๏ธ error: unquote : misplaced ',' : 3
The syntax rules allow macro transformations from patterns to templates, before top-level evaluation. The syntax rules apply only to function calls. They perform hygienic transformations, i.e. local - let - variables are internally renamed, in order to prevent names clashes.
A clause is a couple (pattern template), pattern is a list which begins by an identifier. A pattern may only match lists which begin with the same identifier.
;; We miss the ++ operator
(define-syntax-rule (++ n) (set! n (1+ n))) โ ++
;; this rule will match expressions beginning with ++
;; n, inside template, will be replaced by the corresponding symbol inside the matching expression.
(define my-number 665)
(++ my-number)
my-number โ 666
(debug 2) ;; to see the expansion
(++ my-number)
syntax :: ( set! my-number (1+ my-number))
my-number โ 667
(debug 0) ;; stops seeing
(define-syntax-rule (swap x y)
(let ([tmp x]) (set! x y) (set! y tmp)))
(define simon 'gallubert)
(define antoinette 'de-gabolde)
(swap simon antoinette)
simon โ de-gabolde
antoinette โ gallubert
;; hygienic macro
;; tmp inside the swap macro is replaced by the anonymous #:tmp_1
(let ([tmp 42] [other 666]) (swap tmp other) (list tmp other))
;; syntax expansion ::
(let ((tmp 42) (other 666))
(๐ let ((#:tmp_1 tmp)) (set! tmp other) (set! other #:tmp_1))
(list tmp other))
;; result
โ (666 42)
;; We miss the Common Lisp defun
(define-syntax-rule
(defun foo (params ...) expr ...)
(define ( foo params ... ) expr ...))
(defun gee ( a b) (+ a b) (* a b))
syntax expansion :: (๐ define (gee a b) (+ a b) (* a b))
(gee 6 7) โ 42
;; let's improve the ++ operator : 0 ,1 or n increments
(define-syntax ++
(syntax-rules ()
((++ a)(set! a (1+ a)))
((++ a n)(set! a (+ a n)))
((++ a n ...)(set! a (+ a n ... )))))
(++ my-number 100 200 300) โ 1267
(++) โ ๐ฅ error: syntax-rules : no match pattern : (++)
Syntax rules allow to transform lists into lists. Syntax-id rules allow to transform identifiers - symbols - into lists.
Dot notation : pattern matching and replacement occur when the pattern id is _.suffix or prefix._
(define-syntax-id a.bump (begin (set! a (1+ a)) a))
(define a 42)
a.bump โ 43
(+ a.bump a.bump) โ 89
a โ 45
;; more general
(define-syntax-id _.bump (begin (set! _ (1+ _)) _))
(define beast 666)
beast.bump
beast โ 667
๐ก๐ก๐ก ' somethig.bump ;; quoted, to see the expansion
โ (begin (set! somethig (1+ somethig)) somethig)
(define-syntax-id show._ (writeln '_ 'is _))
show.beast
beast is 667
;; with structures
(lib 'struct)
(struct singer (name hit))
(define dalida (singer 'Dalida "Mourir sur scรจne"))
(define-syntax-id _.hit (struct-get _ #:singer.hit)) ;; or (struct-get _ 1)
dalida.hit
โ Mourir sur scรจne
A library - located on the server - is a javascript extension, bringing new native functions. The following describes all functions in each library. Libraries names may be written without the ".lib" suffix. Is is good practice to load the needed libraries at the beginning of the session, may be in the (preferences) function.
(require 'math) ๐ฅ error: require : missing lib : math.lib (lib 'math.lib) Lib: math.lib loaded. (lib 'math) Lib: math.lib already here. (lib-functions 'math) โ #(cpoly croot cserie deriv fractal g-iterate integrate math-precision normal nth-prime poly poly->string poly-add poly-mul poly-mul-k poly-pow primes-pi root serie standard-normal )
Structures objects generate instances of structures, which are vector-like objects with named fields or slots. Structures can inherit fields from super structures. Access functions are generated for each field; the field values may be any lisp object. A list of structures instances may be saved/restored into/from local storage. See todo.glisp for an example of use. See Rosetta code for saving/restoring self-referencing structures.
In the following, <struct> is to be replaced by the name of a newly defined structure.
Fields have a name, an optional initial value - 0 is the default - and may have options. A field descriptor may be :
change-proc is a user defined procedure which must return a new value for a field. It may be used to check and/or change the targeted field value. It is triggered by a call to a set- โ๏ธ (define (change-proc instance old-value tentative-new-value) body)
(<struct> field-value โฆ) constructor โ new instance of <struct>. If the structure has n fields, one can provide only the first m < n first values.
(list-><struct> list-of-field-values) โ new instance of <struct>
(<struct>? obj) โ Is obj an instance of <struct> ? #t or #f
(<struct>-field-name instance) โ getters for each field are generated.
(set-<struct>-field-name! instance value) โ setters for each field are generated.
Options :
init-proc is a user defined procedure which will be called by the constructor at the end of the instance creation.. It may be used to check and/or sets fields values. It has the following signature :
string-proc is a user defined procedure which overrides the default structure.tostring procedure. It returns an expression which will be converted to string by the output writer. Signature:
;; simple structure definition
(struct animal (legs eyes))
struct:animal
โ #struct:animal [legs eyes]
(define fifi (animal)) โ fifi ;; constructor
fifi โ #<animal> (0 0)
(animal-legs fifi) โ 0 ;; getter
(set-animal-legs! fifi 4) โ 4 ;; setter
fifi โ #<animal> (4 0)
;; initialize an instance
(animal 8 12) โ #<animal> (8 12)
;; struct initializer
(struct animal ((legs 0) (eyes 0)) #:initialize animal-init)
(define (animal-init a) (writeln 'animal-init) (set-animal-legs! a 4))
;; super-structure
(struct cat animal ((tails 9)) #:initialize cat-init #:tostring cat-show)
(define (cat-show cat:c) (format "๐ฑ %d %d %d" c.legs c.eyes c.tails))
(define (cat-init cat:c) (writeln 'cat-init) (set-cat-eyes! c 3/2))
(define felix (cat)) โ felix
โ animal-init ;; super initializer called
โ cat-init ;; initializer called
felix โ ๐ฑ 4 3/2 9
;; See polymorphic copy
A structure defines a type. Methods can be defined which use a struture type. Note that you can use the dot notation - name.slot-name - inside a method using structure type(s).
(lib 'types)
(struct dog animal ((tails 1)))
(define-method (run animal:a ) (writeln 'animal a 'running))
(define-method (run cat:c) (writeln 'cat c 'running 'with c.tails 'tails ))
(define-method (run cat:c number:speed) (writeln 'cat c 'running-at speed))
(define-method (run dog:d)
(call-super run d)
(writeln 'dog d 'running))
(define milou (dog))
(define felix (cat))
;; (run milou) method call with a dog type argument
;; (run felix 333) method call with a cat type argument and number argument
(run milou)
animal # (4 0 1) running
dog # (4 0 1) running
(run felix)
cat ๐ฑ 4 3/2 9 running with 9 tails
(run felix 333)
cat ๐ฑ 4 3/2 9 running-at 333
A struct declaration generates the constant keywords #:<struct>.<slot-name> which are bound to the corresponding slots numbers.
(struct writer (name age books)) (define simon (writer "Gallubert" 66 '(my-life me-and-Wittgenstein))) (struct-get simon #:writer.name) โ "gallubert" (struct-get simon 1) โ 66 #:writer.books โ 2 ;; slot number
A clause is a couple (pattern body) , where body in a sequence of expressions. The value of a clause is the evaluation of the body, in the pattern environment bindings.
A pattern is a matcher or a list of patterns. Identifiers in a pattern are bound to the matched value. All bindings of an identifier must be the same inside the same pattern. Identifiers must begin with a letter.
A matcher matches a value - which may be any lisp object - according to the following rules :
| id | matches anything and binds id to matched value |
| _ | matches anything |
| (m1 m2 ...) | matches list (v1 v2 ..) iff mi matches vi |
| (S m1 m2 ...) | matches an instance of structure S iff mi matches sloti |
| 'm-value | matches iff (eq? m-value value) |
| (? proc:1) | matches if (proc value) is #t |
| (? proc:1 id) | matches if (proc value) is #t and binds id to matched value |
| (? "/regexp/" [id]) | regexp matches and binds id to matched value |
| id ... | matches 1 or more consecutive values and binds id to the matched sub-list |
| other | matches (eq? other value) |
(lib 'match)
;; matching lists
(match '( 11 22 33) [( a b c) (list c a b)]) โ (33 11 22)
(match '(B C D E F)
[('A a ...) a]
[('B b ...) b]) โ (C D E F)
;; predicates
(match "42"
[(? string? a) (list 'STRING a)]
[(? number? a) (list 'NUMBER a)]
[else 'OTHER]) โ (STRING "42")
;; matching structures
;; see pattern matching at rosetta.org
;; matching formal expressions
;; see Machin formulas at rosetta.org
Reader macros replace patterns by templates - using the match mechanism : variable replacement, etc. - inside an input expression, before any evaluation.
(lib 'match)
(define-macro m-or (a || b) (or a b)) โ m-or
(define-macro m-and (a && b) (and a b)) โ m-and
(reader-macros) โ (("m-and" (a && b) (and a b)) ("m-or" (a || b) (or a b)))
(macro? 'm-and) โ ((a && b) (and a b))
(3 && 9) โ 9
(3 || 9) โ 3
Infix - standard math notation - expressions may be used in functions bodies using infix blocks, or directly read by the top-level read-eval-print loop.
Syntax :
(lib 'infix)
(define (f x y)
(define r 0) (define alpha 0) (define beta 0)
[#:infix
r:= sqrt(x*x + y*y) ;
alpha := acos (x / r) ;
beta := asin(y / r) ; ]
(writeln 'rho r 'alpha alpha 'beta beta))
(f 2 2)
โ ฯ 2.8284 ฮฑ 0.7854 ฮฒ 0.7854
(f 4 4)
โ ฯ 5.6569 ฮฑ 0.7854 ฮฒ 0.7854
(lib 'infix) (define-values (a b x ) '(0 0 0)) (use-infix #t) โ #t a:= 1 + 10*10 โ 101 prime? (a) โ #t if (a > 10) 'vrai else 'faux โ vrai while (a-- > 90) write(a) โ #f 100 99 98 97 96 95 94 93 92 91 90 x:= cos(PI) โ -1 a*x*x + b*x + 42 โ 131 a:=2 ; b := 20; a^b [2] โ 1048576 ;; use of &i variables &2 + &2 [3] โ 2097152 use-infix(#f)
Gloops stands for "Gloops library for object oriented programming, s at end".
Example : classes, instanciation and methods. Example : a class of large Rational numbers.
Plot controls - sliders - are used to modify the appearance of a bit-map. Description, in order of appearance:
(*) โณ Time warning : The curve is re-computed. โ๏ธ
In the following, fx is a function of x (real), fxy is a real function of (x,y) , fn is a function of the integer n, fxu is a function of the parameter u which returns a value for x, anf fz is a function of the complex z, which returns a complex value.
A range defines an interval for drawing. A range may be an interval : (-5 +10), or a short-cut : -3 means (-3 3), and 6 means (0 6).
A color is a string : CSS name ("lightgreen", "white", โฆ) or CSS color hexa value : "#rrggbb".
๐ Points Pi(xi,yi) are defined in the grid x/y-minmax coordinates (not pixels).
(lib 'plot) (define g (make-circular-gradient 0 0 20 0 0 400)) (gradient-add-stop g 0 "yellow") (gradient-add-stop g 1 "red") (plot-rect -1 -1 1 1) ;; [-1 1] is the default plotting values interval (plot-text "(make-circular-gradient 0 0 20 0 0 400)" -0.9 -0.9 "black")![]()
(lib 'plot.lib)
(plot-size 600) ;; โ 600x600px canvas
(plot sin -PI) โ (("x:auto" -3.14 3.14) ("y:auto" -1.1 1.1))
(plot-axis 0 0 "red") โ (204 204)
(plot-grid 0.5 0.5) โ #t
;; Collatz sequence
(define (collatz n)
(if (zero? n) *seed*
(let [(prec (collatz (1- n)))]
(if (even? prec)
(/ prec 2)
(1+ (* 3 prec)))))) โ collatz
(define *seed* 101) โ *seed*
(plot-sequence collatz 100) โ (("x:auto" 0 100) ("y" 0 100))
(plot-grid 20 10)
;; Ellie : a nice elliptic curve
(define (Ellie x y t) (- (* x x x) (* y y) x t)) ;; x3 - y2 - x - t
(plot-xy Ellie -3 -3)
(plot-animate 10);; do vary t in [0...1]
See elliptic curve aritmetic in Rosetta code.
See or load plot-xy.glisp for other nice f(x,y) functions.
(plot-clear) โ #t
(define (fx u) (sin (* 11 u))) (define (fy u) (cos (* 19 u))) โ fx fy
(plot-param fx fy 10) โ (("x:auto" -1.1 1.1) ("y:auto" -1.1 1.1))
(define (rho u) (- (* u u) u 1)) โ rho
(define (theta u) (+ 1 (* u u))) โ theta
(plot-line-width 4) โ 4
(plot-polar rho theta 3) โ (("x:auto" -5.06 2.34) ("y:auto" -2.99 3.67))
(plot-font "64px Helvetica") โ "64px Helvetica"
(plot-text "EchoLisp" 0 0 "red") โ #t
(plot-undo) ;; bad position - undo and try another one
(plot-text "EchoLisp" -5 0 "red") โ #t
Animation can be performed by adding a time parameter to the plotted function(s). t will be set in the [0..1] range by the plot-animate function, or manually, using the time slider.
(plot-line-width 3) โ 3
(define (f x t) (sin (+ x t))) โ f
(plot f -PI) ;; plot before animating
(plot-animate 6) ;; 6 seconds
(define (fx u t) (* t (sin u))) โ fx
(define (fy u t) (* (1- t) (cos u))) โ fy
(plot-x-minmax -1) โ (("x" -1 1) ("y:auto" 0 0))
(plot-y-minmax -1) โ (("x" -1 1) ("y" -1 1)) ;; set grid size for animation
(plot-param fx fy 2PI)
(plot-animate 5) โ ((-1 1) (-1 1))
Domain coloring of complex values is performed using the plot-z functions.
(plot-z-arg identity -2 -2) ;; complex plane. hue = function (arg)(plot-z-mod identity -2 -2) ;; complex plane. hue = function (modulus) (plot-grid 1 1)
g : (define (g n) (/ (1+ (* n I)))) f : (define (f z) (cserie g z 100)) (plot-z-mod f -1.5 -1.5)
![]()
(plot smoothstep '(0 1)) (plot-axis 0.5 0.5) (plot (lambda(x) (s-curve x 3)) '(0 1))![]()
(fminmax sin -PI) โ (-1 1)
Color components (r=red,g=green,b=blue,a=alpha) , g=gray or (h=hue,s=saturation,v=value) must be float numbers in range [0..1]. The (rgb ..) and (hsv ..) functions return a color which can be drawn on screen, at (x,y) by the (plot-rgb ..) function.
Notation: rgb-funxy is a function of (x,y) which returns an rgb-color, i.e. the color pixel at (x,y).
(rgba 1 0 0 0) โ 255 ;; red (rgb 1 1 1) โ -1 ;; white (hsv->rgb 0 0 1) โ -1 ;; white (rgba 0.5 0.8 0.5 1.0) โ -8401793 (define (pixel x y) (rgba-abs (atan x) (atan y) 0 (+ (sin x) (sin y)))) (plot-rgb pixel -2 -2);; the hue color circle ;; angle [-PI ... PI] is mapped onto hue [0 ... 1] (define (colors x y) (let [(z (complex x y))] (if ( <= (magnitude z) 1 ) ;; inside circle ? (hsv->rgb (linear (angle z) -PI PI) 1 1) 0 ))) (plot-rgb colors -1 -1)
![]()
Notation: rgb-funn is a function of n which returns an rgb-color, i.e. the color pixel at (ix,iy), where (ix,iy) are the integer values mapped to n. rgb-funn has the following signature :
โ๏ธ (define (my-pixel-color-at-n n [nmax [ time]]) body )
The parameters nmax and time are optional. Use time in [0...1] to animate the picture.
;; 64 shades of gray - Hilbert curve (define (pixel n) (gray (// (% n 64) 63))) (plot-hilbert pixel 4096);; Ulam spiral (define *red* (rgb 1 0 0)) (define (ulam n nmax) (if ( prime? n) *red* (gray (// n nmax)))) (plot-spiral ulam 1000) ;; range [0...1000]
(plot-spiral ulam '(100000 110000)) ;; other n-range
Data series are lists or vectors of couples of values (xi yi). Time series are lists or vectors of couples (datei yi). Couples may be lists: ( x y), vectors of dimension 2: #(x y) or pairs: ( x . y).Series can be home made or imported using the JSON library.
The canonical - most compact - form is a vector of pairs :
#((x0 . y0 )(x1 . y1) ...)
In a time serie, the datei are date objects, or strings convertible to dates - "2021-11-28" - or numbers : dates in seconds. All data-serie functions applies to time series. A date-range is either a list (date-from date-to) , or a simple date : date-from, meaning [date-from .. now] .
(lib 'plot) (define (r-dots n) (for/list ((i n)) (list (random 100) (random 100)))) ;; n random dots (plot-dots (r-dots 10) "๐") (plot-dots (r-dots 10) "๐") ...![]()
The following allow to map a typed vector onto a bit-map - canvas - retrieve/modify pixels, and (re)draw the canvas. Requires the vlib.lib library.
(lib 'plot) (lib 'vlib) (define (plot-pix (blue 0)) (define width (first (plot-size))) ;; get canvas dimensions (define height (rest (plot-size))) (define PIX (pixels->int32-vector)) ;; get canvas image (define (pcolor x y) ;; color at (x,y) (rgb (sin (// x width)) (sin (// y height)) blue)) (pixels-map pcolor PIX) (vector->pixels PIX)) ;; draw canvas image (plot-pix) โ 672400 ;; no blue (plot-pix 0.6) โ 672400 ;; shade of blue (plot-pix 1.0)
See also percolation in Rosetta code. See also munching squares in Rosetta code.
The plot-3d library uses the Three.js library for rendering 3D surfaces. Surfaces can be defined as z = f(x,y) functions, parametric equations, implicit equations f(x,y,z) = 0 , or complex functions.
(define (f x y) x ) ;; define the plane z = x (scene-3d xminmax 20 yminmax -12) ;; set these parameters (scene-3d material phong segments 60) ;; and these parameters (scene-3d axis #t) ;; and this one (plot-3d f ) ;; then draw
All these functions return the bounding box used for drawing.
A color may be a string : "yellow" or an hexa number : 0x808080 , medium gray. Default colors are 0x666666 : dark gray. Phong or lambert or textured material may need an ambient color and/or lights. Textures are defined by textures names : water, metal-i, stone-i, rain-i, wood-i, floral-i, vichy-i, mosaic-i, brick-i, 1 <= i <= 6 .
The following are used to add objects to the surface being drawn : To Be Completed Later
Custom functions may be defined for surface coloring, or surface transformation. All these functions are inline functions
(lib 'math.lib) Lib: math.lib loaded. (egcd 42 666) โ (6 16 -1) ;; 42*16 - 666 = 6 (crt-solve '(2 3 2) '(3 5 7)) โ 23 (crt-solve '(2 3 2) '(5555 5 7)) โ error: mod[i] must be co-primes : assertion failed : 5555 (nth-prime 10000) โ 104729 (primes-pi 104729) โ 10000 (lib 'bigint) (for ((p (in-primes 1000000000))) (write p) #:break (> p 1000000099)) โ 1000000007 1000000009 1000000021 1000000033 1000000087 1000000093 1000000097 1000000103 See also Faulhaber formula and Bernoulli numbers in Rosetta code.
A continued fraction is a list - finite or infinite - of coefficients (a0 a1 a2 ...) which compute the following :
In Lisp form :
a0 is the integer part of the continued fraction. The rest evaluates to the fractional part. The fraction is periodic iff its value is a quadratic irrational number : โ2, โ5, โ2015, ...
(number->contfract 22/7) โ (3 7) ;; 22/7 = 3 + 1/7
(number->contfract 7/111) โ (0 15 1 6)
;; checking the result :
(+ 0 ( / ( + 15 (/ ( + 1 ( / ( + 6 0))))))) โ 7/111
(define ones (circular-list 1)) โ ( 1 1 1 โฆ โ)
(contfract->number ones) โ 1.61803398875 ;; 1 + 1 / (1 + 1 / (1 + 1 / ( ...)))
(/ (1+ (sqrt 5)) 2) โ 1.61803398875 ;; = (1 + โ5)/2 = Φ = Golden ratio
(number->contfract (sqrt 2015)) โ ( 44 1 7 1 88 1 7 1 88 โฆ โ)
(number->contfract (sqrt 2)) โ ( 1 2 2 2 2 โฆ โ)
(number->contfract (sqrt 3)) โ ( 1 1 2 1 2 1 2 โฆ โ)
(number->contfract PI 20) โ (3 7 15 1 292 1 1 1 2 1 3 1 14 3 3 23 1 1 7 4 35) ;; PI is transcendant : no periodicity
(convergents (number->contfract PI 20) 10) โ (3 22/7 333/106 355/113 103993/33102 104348/33215 208341/66317 312689/99532 833719/265381) ;; better and better approximations of PI by rationals.
(number->contfract E 16) โ (2 1 2 1 1 4 1 1 6 1 1 8 1 1 10 1 1) ;; ๐ฉ Euler
A polynomial P is a list of coefficients from a0 - lowest term - to an, the value of which at x is Σ aixi. Polynomials can be combined with add, mul and power operations - See Rosetta code for an example.
Use (poly x P) to compute the value of a real polynomial at x (real). Use (cpoly z P) to compute the value of a real or complex polynomial at z (complex).
Computation of polynomial is a quick operation, so it is good practice to use them in plotting or other time-consuming functions.
For example (poly x '(1 2 3 4)) is far better - and shorter - than (+ (* 4 x x x ) (* 3 x x) (* 2 x ) 1) .
(define P '(1 -3 4 -2)) โ P (poly->string 'x P) โ "-2x^3 +4x^2 -3x +1 " (poly->string 'Y P) โ "-2Y^3 +4Y^2 -3Y +1 " (poly 1 P) โ 0 (poly -1 P) โ 10 (cpoly I P) โ -3-i (define Q '(3 -3 2)) โ Q (poly->string 'x P Q) โ "-2x^3 +4x^2 -3x +1 / 2x^2 -3x +3 " (poly 4 P Q) โ -3.260869565217391 (cpoly 0+2i P Q) โ 0.2459016393442623-2.2950819672131146i (define P '( 1 2 3 4)) โ P (define Q '(-1 -2 5 -3)) โ Q (poly->string 'x P) โ 4x^3 +3x^2 +2x +1 (poly->string 'x Q) โ -3x^3 +5x^2 -2x -1 (poly->string 'x (poly-add P Q)) โ x^3 +8x^2 (poly->string 'x (poly-mul P Q)) โ -12x^6 +11x^5 +x^4 -3x^3 -2x^2 -4x -1 (poly->string 'x (poly-mul-k P 1.5)) โ 6x^3 +4.5x^2 +3x +1.5 (poly->html 'x (poly-pow Q 7)) โ -2187x21 +25515x20 -137781x19 +451332x18 -985257x17 +1472688x16 -1461558x15 +812705x14 +7420x13 -389200x12 +252497x11 -245x10 -73759x9 +23898x8 +9987x7 -5922x6 -952x5 +763x4 +119x3 -49x2 -14x -1 ;;; timing (define (f x) (poly x ' (1 2 3 4))) (define (g x) (+ (* 4 x x x) (* 3 x x ) (* 2 x ) 1)) (time (for ((i 1000000)) (f i))) โ 1276 millisec (time (for ((i 1000000)) (g i))) โ 2159 millisec
(math-precision) โ 0.000001 (~= 1/3 0.333333) โ #t (~= 1/3 0.333) โ #f (define (f x) (- x (cos x))) โ f (root f 0 1) โ 0.7390851295647751 ;; cos(x) = x (define (f z) (- (* z z z) 1)) (croots f -2-2i 2+2i) โ (-0.499999+0.866023i -0.499999-0.866023i 1-0.000003i) (integrate sin 0 PI/2) โ 0.9999999980954222 (integrate identity 0 10) โ 50 (deriv sin 0) โ 1.000000000;; sin'(0) = cos(0) (deriv identity 42) โ 0.999999993 ;; f'(x) = 1 (define (f n) (// (factorial n))) โ f ;; f(n) = 1/n! (serie f 0.5 100) โ 1.6487212650 ;; e0.5 (math-precision 1e-12) โ 1e-12 (serie f 0.5 100) โ 1.6487212707 (sqrt E) โ 1.6487212707 (cserie f I 100) โ 0.54030230586+0.841470984807i ;; ei (exp I) โ 0.540302305868+0.84147098480i ;; check that โซ0,1x-x dx = โ1,โ m-m (define (f x) (// (expt x x))) โ f ;; x-x (- (integrate f 0 1) (sigma f 1 1000)) โ -0.00000000000000002
(math-precision 1.e-9) โ 1e-9 (integrate standard-normal -10 10) โ 1.0000000000228986 (gamma 0.5) โ 1.7724538509055159 ; Γ(1/2) = โΠ (sqrt PI) โ 1.7724538509055159 (gamma 10) โ 362880.0000000015 (factorial 9) โ 362880
;;A nice Julia set (lib 'math) (lib 'plot) (define zc 0.3+0.5i) (define (Julie z) (fractal z zc 50)) (plot-z-mod Julie -2 -2) ;; Mandelbrot (define (mset z) (if (= Infinity (fractal 0 z 200)) Infinity z)) (plot-z-arg mset '(-2.5 1) -1.5)
See Vector for creating and manipulating vectors. The arguments of dot-product, cdot-product, cross-product must be two vectors. Vector-a,-b are vectors of real numbers. Vector-za, -zb are vectors of real or complex numbers.
(lib 'math) (dot-product #( 1 2) #(3 4)) โ 11 ;; Let ๐-length (a) = (Σ ai*ai) 1/2 (define-syntax-rule (๐-length a) (sqrt (dot-product a a))) ( ๐-length #( 3 4)) โ 5 (define x #(+i -i 1)) (cross-product x x) โ #( 0+0i 0+0i 0+0i)
vector-a, vector-b are vectors of real numbers. a,b,p are real numbers, p > 0 . The triangle inequality holds for norms-1,-2,-inf , and -p if p > 1.
(pythagore 216 630) โ 666 ;; ๐ฉ ;; Let's work in a 100 dimensions space. (define a (vector-map random (make-vector 100 10))) (define b (vector-map random (make-vector 100 100))) (define c (vector-map random (make-vector 100 1000))) (norm-1 a b)(norm-1 b c)(norm-1 a c) โ 4486 47780 51878 (norm-p a b 1.33)(norm-p b c 1.33)(norm-p a c 1.33) โ 1536.6049 16197.2366 17459.6099 (norm-2 a b)(norm-2 b c)(norm-2 a c) โ 533.5635 5563.5401 5938.744 (norm-inf a b) (norm-inf b c) (norm-inf a c) โ 93 954 988 ;; Chess - How many moves for a King to go from a1 to h5 ? (norm-inf #(1 1) #(8 5)) โ 7 ;; Geometry : see Circles area.
An array A (n p) is a 2D-table of n rows and p columns. Arrays indices start at 0; A[i,j] is the element - any lisp object - located in i-th row, j-th column. Matrices are arrays of real numbers. Arrays operations also apply to matrices. Arrays are implemented as vectors of vectors (rows). See also typed arrays for fast arrays.
| a 0 0 | a 0 1 | a 0 2 | a ... | a 0 j | a ... | a 0 p-1 |
| a 1 0 | a 1 1 | a 1 2 | a ... | a 1 j | a ... | a 1 p-1 |
| a ... 0 | a ... 1 | a ... 2 | a ... | a ... j | a ... | a ... p-1 |
| a i 0 | a i 1 | a i 2 | a ... | a i j | a ... | a i p-1 |
| a ... 0 | a ... 1 | a ... 2 | a ... | a ... j | a ... | a ... p-1 |
| a n-1 0 | a n-1 1 | a n-1 2 | a ... | a n-1 j | a ... | a n-1 p-1 |
(lib 'matrix) ;; See Cramer's rule.
To perform integer operations on "large"integers, > 1.e+9 . โ๏ธ Operations may run in the background โ๏ธ
(lib 'bigint)
Lib: bigint.lib loaded.
(* 123456789123456789 987654321987654321)
โ 121932631356500531347203169112635269
(factorial 1000)
โ 4023872600770937735437024339230039857193748642107โฆ.000000
(next-prime 1.e+20) โ 100000000000000000039
(random-prime 1.e+100)
โ 24094786158894049197303โฆ.6227618797581442571432539758128420365365478139
(prime? (1+ (factorial 115))) โ #f
(prime? (1+ (factorial 116))) โ #t
(prime? 32561123834332170080737147) โ #f
(factor 32561123834332170080737147) โ ;; background operations
โณ factorizing โฆ 3%
โณ factorizing โฆ 7%
โณ factorizing โฆ 11%
(factor 32561123834332170080737147) โ 8404620944833
Procrastinators are lazy objects with an internal state (state procrastinator), which wait for a next call to return a value and change their state. Sub-classes of procrastinators are : iterators, sequences, generators, combinators, ... One may iterate over procrastinators with the usual list iteration functions : map, fold, every, any, for, mean, etc. Procrastinators may generate an infinite set of values. Procrastinators do auto-evaluate.
(take procrastinator n) will be used to get the first n values of a procrastinator. The state of a procrastinator only changes when calling explicitly (next). Other functions (map, append, ...) do not change the state. Procrastinators may be used as iterators in for loops : (for ((g procrastinator) ...).
See Catalan numbers in Rosetta code for examples of use.
;; sum of the 10 first even squares
;; the first operante is the infinite sequence [0 1 2 ...]
;; the pipeline , map, filter, and take operators apply to infinite sequences.
( ->> [0 ..] (map * _ _ ) (filter even?) (take 10) (apply +))
โ 1140
The following functions behave like their list equivalent. They all stop enumerationg when (next ...) return #f. They may not return - endless loop - if the procrastinator has an infinite set of values.
(scanl + 42 (iota 7)) โ (42 42 43 45 48 52 57 63) ;; scanl of a list (take (scanl + 42 [0 .. 1000000000]) 8) โ (42 42 43 45 48 52 57 63) ;; scanl of a lazy sequence
The following functions will take procrastinators (= sequences, maps, filters, ..), or lists or vectors - which are converted into procrastinators - as arguments. They all stop enumerationg when (next ...) returns #f.
Lazy lists are made of a head - first - element, and a tail - rest - expression. The tail expression is delayed, not evaluated until needed, and must evaluate to a list or procrastinator object. The kons operator is the lazy sequences constructor. (kons first rest-expression) is the equivalent of (cons first rest) for lists.
The infix operator : may be used in place of kons. (a : b) is the same as (kons a b).
(define ints (1 : (map 1+ ints))) โ ints
(take ints 10)
โ (1 2 3 4 5 6 7 8 9 10)
(take (drop ints 8) 10)
โ (9 10 11 12 13 14 15 16 17 18)
(length ints) โ Infinity
(define fibs (0 : 1 : (map + fibs (tail fibs)))) โ fibs
(take fibs 12)
โ (0 1 1 2 3 5 8 13 21 34 55 89)
(nth fibs 20)
โ 6765
(define facts (1 : (map * ints facts))) โ facts
(take facts 10)
โ (1 1 2 6 24 120 720 5040 40320 362880)
(factorial 10)
โ 3628800
Sequences are finite or infinite intervals of integer, rational or real numbers. They are defined by their first , second - by default = first +/- 1 - and last terms (which may be Infinity). The last term returned is such as (first + k*step) < last for an increasing sequence, (first + k*step) > last for a decreasing sequence (step < 0).
Sequences are defined by the (sequence ...) function, or by the .. infix operator.
(take [1 3 .. 10] #:all) โ (1 3 5 7 9) (for ((n [ 5 10 .. 60])) (write n)) 5 10 15 20 25 30 35 40 45 50 55 (length [0 0 ..]) โ Infinity (length [1 3 .. 100]) โ 49 (sum [1 2 .. 100]) โ 4950 (take (map * [1 ..] [10 ..]) 12) โ (10 22 36 52 70 90 112 136 162 190 220 252)
(take ["a" .. "z"] 10)
โ ("a" "b" "c" "d" "e" "f" "g" "h" "i" "j")
(define strseq ["ab" .. "xy"]) โ #string-sequence [ab .. xy]
(take strseq #:all)
โ ("ab" "bb" "cb" "db" "eb" "fb" "gb" [ ... ] "rb" "sb" "tb" "[ .. ]" "xx" "ay" "by" "cy" "dy" "ey" "fy" "gy" "hy" "iy" "jy" "ky" "ly" "my" "ny" "oy" "py" "qy" "ry" "sy" "ty" "uy" "vy" "wy" "xy")
Iterators generate (infinite) sequences from a function with one argument. The defining function f of an iterator/n is automatically equipped with a cache, if not already present : see (remember f).
(define (f n) (/ (* n n n n))) ;; 1/ n4
(define seq (iterator/n f 1)) ;; iterator, starts at n=1
(next seq) โ 1
(next seq) โ 1/16
(next seq) โ 1/81
(take seq 8)
โ (1 1/16 1/81 1/256 1/625 1/1296 1/2401 1/4096)
(sum (take seq 1000)) โ 1.082323233378306 ;; sum of 1000 first terms
(// (* PI PI PI PI) 90) โ 1.082323233711138 = π4/90
(scanl + 0 (take seq 10)) ;; intermediate sums
โ (0 1 17/16 1393/1296 22369/20736 14001361/12960000 1.0811235339506173 1.0815400270784807 1.0817841677034807 1.0819365834937567 1.0820365834937566)
;; iterator/f
;; See Collatz sequence.
Given a vector of integer dimensions #(d0 d1 d2 ..), returns all vector indices #(i0 i1 i2 ..) such as 0 <= ik < dk.
(define indy (indices #(3 2 4))) โ indy
indy โ #indices: #( 0 0 0) dims: #( 3 2 4)
(length indy) โ 24
(head indy) โ #( 0 0 0)
(tail indy) โ #indices: #( 0 0 1) dims: #( 3 2 4)
(for [(K indy)] (write K))
โ #( 0 0 0) #( 0 0 1) #( 0 0 2) #( 0 0 3) #( 0 1 0) ... #( 2 1 2) #( 2 1 3)
Combinators require the list library : (lib 'list).
(define pwa (powerset ' ( a b c d e f )))
(length pwa)
โ 64
(take pwa 7)
โ (() (a) (b) (a b) (c) (a c) (b c))
(define pwb (powerset (iota 30)))
(length pwb)
โ 1073741824
(lib 'list)
(lib 'sequences)
(take (combinator (iota 5) 3) #:all)
โ ((0 1 2) (0 1 3) (0 1 4) (0 2 3) (0 2 4) (0 3 4) (1 2 3) (1 2 4) (1 3 4) (2 3 4))
(for ([c (combinator/rep '( a b c) 4] [i 100]) (writeln i c))
0 (a a a a)
1 (a a a b)
2 (a a a c)
3 (a a b b)
[...]
13 (b c c c)
14 (c c c c)
A generator is build upon a state based procedure - gen-proc which takes a state in input, yields one or several values, and returns either #f - no more values - or the next generator state.
(define (dups n) ;; n is current state
(yield n) ;; next value
;; execution stopped here - wait for (next)
(yield n) ;; next value
;; execution stopped here - wait for (next)
(set! n (+ 3 n))
n) ;; set next state and loop
(define gegen (make-generator dups 17)) ;; init state 17
(next gegen) โ 17
(next gegen) โ 17
(next gegen) โ 20
(take gegen 10) โ (17 17 20 20 23 23 26 26 29 29)
(for ((i 5) (g gegen)) (write (cons i g)))
โ (0 . 17) (1 . 17) (2 . 20) (3 . 20) (4 . 23)
Tasks are procedures with a state, which execute in parallel in the background. The task manager endlessly calls the task-procedures, wich return either #f = stop the task, or the next state for the next procedure call. Task-procedures may signal events to other tasks, They are not interruptible, except by (sleep) or (wait) operations. Inside a task-procedure, the symbol _TASK refers to the current task.
Task manager pseudo code :
(define (my-task-proc state) |# do someting #| new-state) ;; return new state (for each-task ;; parallel execution (while (task-state task) ;; stop if #f returned (set-state! task (my-task-proc (task-state task))) (idle task-idle-time)))
(lib 'tasks.lib)
(define (tprime pnext) ;; task-procedure
(set! pnext (next-prime pnext))
(writeln 'next-prime= pnext)
pnext) ;; return next state
(define task-primes (make-task tprime 1000000001))
(task-run task-primes)
โ #task:id:500:running
next-prime= 1000000007
next-prime= 1000000009
next-prime= 1000000021
.... ;; CTRL-C to stop
*stopped*
(task-state task-primes)
โ 1000000093
(define (tprint line ) ;; task-procedure
(writeln _TASK line)
#f ) ;; runs only one time
(for-each task-run
(map (curry make-task tprint)
'(Enjoy EchoLisp tasks )))
#task:id:496:running EchoLisp
#task:id:495:running Enjoy
#task:id:497:running tasks
Tasks use semaphores, as depicted in this book, to synchronize, make mutual exclusions, wait for another task signal, etc. Wait, signal and sleep operations may be called anywhere from the task procedure. NB: and NOT from a procedure called by the task-procedure
A queue (FIFO) of messages may be associated with a semaphore, and accessed witth push/pop operations.
A sound is one of the symbols: ok, ko, tick, tack, woosh, beep, digit .
๐พ Future alerts and delays are saved in local storage, into the system.calendar global variable. Hitting CTRL-C stops any running (at-every โฆ) operation. Alert-proc is a procedure of 0 argument, or a string to display.
(lib 'timer.lib) Lib: timer.lib loaded. (define (metronom) (blink) (play-sound 'tack)) (at-every 1000 'metronom) (list->stack '(ok ko tick tack woosh beep digit) 'sounds) โ sounds (define (play-list n) ;; return #f to stop (writeln n) (when (stack-top 'sounds) (play-sound (pop 'sounds)))) โ play-list (at-every 3000 'play-list) (at (current-date) " ๐ COFFEE TIME") โ "17/4/2015 18:08:24" 17/4/2015 18:08:24 : ๐ COFFEE TIME (at (date 2016 1 1) " ๐ HAPPY NEW YEAR") system.calendar โ ((Fri Jan 01 2016 00:00:00 GMT+0100 (CET) " ๐ HAPPY NEW YEAR")) ;; one hour timer (define (alert) (play-sound 'beep) (display "CALL ELVIS" "color:red")) โ alert (at 1 'hour 'alert) โ "17/4/2015 19:14:23" ;;procrastination (at 'demain "Aller ร la banque") โ "19/5/2015 11:33:50" (at "13/11/2016" "happy birthday") system.calendar โ ((Fri Apr 17 2015 19:14:23 GMT+0200 (CEST) alert) (Fri Jan 01 2016 00:00:00 GMT+0100 (CET) " ๐ HAPPY NEW YEAR"))
(lib 'web) Lib: web.lib loaded. (mail 'georges.brougnard@echolalie.com "my primes" (primes 100)) (open-url (string->url "https://www.google.fr/?gws_rd=ssl#q=echolisp")) โ "https://www.google.fr/?gws_rd=ssl#q=echolisp" (define p2n-pn (map (lambda (n) (- (nth-prime (* n 2)) (nth-prime n))) (range 1 10))) โ p2n-pn p2n-pn โ (1 4 8 12 18 24 26 34 38) (oeis p2n-pn) โ(define X 5.859874482048838 โ X (inverter X)
(lib 'bigint.lib) (lib 'web.lib) (define mynumber 2305843009213693951) โ mynumber (prime? mynumber) โ #t (log2 (1+ mynumber)) โ 61 (1- (expt 2 61)) โ 2305843009213693951 ;; 261-1 (info 'mynumber "Mersenne prime") โ mynumber (info 'mynumber) โ "Mersenne prime" (info 'mynumber "http://www.mersenne.org/primes/") โ mynumber (open-url (info 'mynumber)) โ "http://www.mersenne.org/primes/"
![]()
To import/export data formatted according to the JSON data-interchange language.
The top-level function are export-json - serialize lisp object to JSON string - and json-import from JSON string to lisp object.
;; JSON standard types : strings, numbers, and arrays (vectors)
(export-json #(6 7 8 9)) โ "[6,7,8,9]"
(export-json #("alpha" "beta" "gamma")) โ "["alpha","beta","gamma"]"
(json-import "[6,7,8,9]") โ #( 6 7 8 9)
(json-import #<< ["alpha","beta","gamma"] >>#) โ #( "alpha" "beta" "gamma")
;; EchoLisp types : dates,rational,complex, big int
(export-json 3/4) โ "{"_instanceof":"Rational","a":3,"b":4}"
(json-import #<< {"_instanceof":"Rational","a":666,"b":42} >>#) โ 111/7
;; Symbols
(export-json 'Simon-Gallubert)
โ "{"_instanceof":"Symbol","name":"Simon-Gallubert"}"
(json-import #<< {"_instanceof":"Symbol","name":"Antoinette-de-Gabolde"} >>#)
โ Antoinette-de-Gabolde
;; Lists
(define my-list
(export-json '( 43 4 5 ( 6 7 ( 8 9 )))))
โ "{"_instanceof":"List" ,"array":[43,4,5,{"_instanceof":"List",
"array":[6,7,{"_instanceof":"List",
"array":[8,9],"circular":false}],"circular":false}],"circular":false}"
(json-import my-list) โ (43 4 5 (6 7 (8 9)))
;; Structures
(struct Person (name pict)) โ #struct:Person [name pict]
(define antoinette (Person "antoinette" "๐ฐ"))
โ # (antoinette ๐ฐ)
(export-json antoinette) โ
"{"_instanceof":"Struct", "struct":"Person","id":17,"fields":["antoinette","๐ฐ"]}"
(json-import
#<< {"_instanceof":"Struct","struct":"Person","id":18,"fields":["simon","๐ฉ"]} >>#)
โ # (simon ๐ฉ)
JSON imported data may be stored - string->json - into EchoLisp jsObjects. It is possible to create new jsObjects, to read/write jsObjects attribute values. jsObjects can be imported from strings or files.
JsObjects can be exported to JSON strings or to key-value-lists : lists of (key value) pairs. They can be created from key-value-lists, plists, association lists.
Keys - aka attributes, properties, names, ... - are strings.
Conversion functions are provided to/from basic JSON types: {object}, array, number, string and the more complex EchoLisp types : Rational, List, Struct, Vector, ...
The functions json-get, json-put, supports the dot key notation for composite objects: (json-get somebody "person.adress.number") is the same as (json-get (json-get (json-get somedy "person") "adress" ) "number").
(lib 'struct)
(lib 'json)
(define cities ;; JSON string
#<<
[{"name":"Lagos", "population":21}, {"name":"Cairo", "population":15.2},
{"name":"Abidjan", "population":4.4}, {"name":"Casablanca", "population":3.98}]
>>#)
;; convert JSON string
(define J (json-import cities)) ;; vector of jsObjects
โ #( #[jsObject] #[jsObject] #[jsObject] #[jsObject])
;; inspect
(json-keys (vector-ref J 0))
โ ("name" "population")
;; structure to import
(struct city (name population)) ;; same keys (could be a subset of JSON keys)
;; make a vector of structures
(vector-map (lambda(x) (json->struct x struct:city)) J);
โ #( #<city:0 > (Lagos 21) #<city:1 > (Cairo 15.2) #<city:2 > (Abidjan 4.4) #<city:3 > (Casablanca 3.98))
The EchoLisp idb library provides access to the IndexedDB (indexed data base, or idb for short) implemented in most browsers. Idb is a database of records holding simple values - 3.14 - , EchoLisp objects - lists, instances of structures, vectors, ... - and jsObjects. Each record consists of a key and some value. Moreover, the database maintains indexes over records it stores.
The EchoLisp developer directly uses the following API to locate records either by their key or by using an index.
The main difference with the local-database API is that idb operations are asynchronous. One must provide onsuccess and onerror procedures to retrieve data base request results.
The "ECHOLISP" data base is automatically created when loading the idb.lib. Adding and deleting stores increment the data base version.
(lib 'idb) ๐พ IDB: db-open: ECHOLISP:1 Lib: idb.lib loaded. (db-name) โ "ECHOLISP" (db-version) โ 1 (db-stores) โ ("system" "user" "words") (db-make-store "test") โ #t ๐พ IDB: db-open: ECHOLISP:2 (db-delete-store! "toast") ๐พ IDB: db-delete-store: toast does not exist โ #f (db-delete-store! "test") โ #t ๐พ IDB: db-open: ECHOLISP:3
Asynchronous key-value access require onsuccess and onerror completion routines. They have the following signature:
Symbols bindings and procedure definitions - strings - may be stored/retrieved into/from the idb's stores. In the following, symbol is the name of a bound symbol, or of a prodedure. A name may be prefixed by a store name. 'user' is the default store.
(define (success result) (writeln '๐บ-OK result)) (define (onerror a) (writeln '๐-KO a)) ;; working with the default 'user' store. (define mynumber ( + E PI)) (db-put 'mynumber) โ #t (db-get 'mynumber success onerror) โ #t ๐บ-OK 5.859874482048838 (db-get 'other success onerror) โ #t ๐-KO other ;; working with the 'mail' store. (db-make-store 'mail) โ #t ๐พ IDB: db-make-store: ECHOLISP:mail ๐พ IDB: db-open: ECHOLISP:17 (define mail.gb "georges.brougnard@echolalie.com") โ mail.gb (db-put 'mail.gb) โ #t ;; default success procedure (db-get 'mail.gb) โ #t ๐พ IDB: mail[gb] : georges.brougnard@echolalie.com ;; default error procedure (db-get 'mail.simon) โ #t ๐พ IDB: db-get:unknown symbol: mail.simon
(define (success result) (writeln 'OK result)) โ success
(define (onerror what) (writeln 'KO what)) โ onerror
(db-make-store 'tmp) โ #t
๐พ IDB: db-make-store: ECHOLISP:tmp
๐พ IDB: db-open: ECHOLISP:16
(db-put-value #:auto 33 'tmp success onerror) โ OK 1
(db-put-value 'mynumber 666 'tmp success) โ OK "mynumber"
(db-keys 'tmp success) โ OK (1 "mynumber")
(db-get-value "mynumber" 'tmp success onerror) โ OK 666
(db-get-value 33 'tmp success onerror) โ KO 33
(lib 'words.fr)
(lib 'dico.fr)
Lib: dico.fr loaded.
(define (success result) (writeln 'OK result))
;; add a few entries from the dictionary into the 'tmp' store
;; using auto-increment
(db-put-values 100000 100100 #:auto word-ref 'tmp success) โ #t
OK (103 203) ;; (key-min key-max) are returned
;; get records from key = 193 to last
(db-get-range 193 ... 'tmp success) โ #t
OK ("hospitalisai" "hospitalisaient" "hospitalisais" "hospitalisait" "hospitalisas" "hospitalisation" "hospitalisations" "hospitalise" "hospitalisent" "hospitaliser" "hospitalisera" )
;; select all records which contain 'hors'
(define (success result) (writeln 'found: result))
(define (selector key value) ;; selector return #f if substring not found
(when (string-index value 'hors) (writeln 'selected key value)))
(db-select selector 'tmp success) โ #t
selected 152 "hors"
selected 153 "horsain"
...
selected 166 "horst"
selected 167 "horstexte"
found: ("hors" "horsain" "horsbord" "horsconcours" "horscote" "horsdoeuvre" "horseguard" "horsepower" "horsepox" "horsin" "horsjeu" "horslaloi" "horsligne" "horspiste" "horst" "horstexte")
EchoLisp may access several idb's. Only one is current at a time. The following allow to create, open, close, delete indexed data bases.
A tree is defined by its root node. Each node in a tree may have node sons - which are also nodes - or may have no sons if it is a leaf node.
A datum - any lisp object, except null - is associated with each node. Procedures are provided to create trees, nodes, add/change nodes, add subtrees, search trees, an apply (fold, for-each) functions to each node.
The external representation of a node is (datum son1 son2< ...) . The internal representation is a list of lists, and it probably never change in the future.
(tree-for-each ..) and (tree-fold ..) make a pre-order traversal of the tree.
(make-tree 'albert) โ (๐ด albert) ;; root node with datum albert
See Knuth's power tree
Binary search trees are also trees, so the above functions (for-each, count, etc.) apply also to binary trees.
The datum at each node is a pair (key . value). Keys are unique. Each node has at most two sons, named left and right. The tree insertion/deletion ensures that left.key < right.key, and each left subtree has keys < any right subtree keys. The tree is automatically reorganized - balanced - when the tree-depth is too high, namely when tree-depth > ceil(log2 (node-count)).
(tree-for-each ..) and (tree-fold ..) visit the tree in symmetric order (in-order traversal) from smallest key to greatest key.
Queues may be used when appropriate in place of lists, for performance or simplicity reasons. Queues have identifiers - queue-id , are global objects, are not bound to a variable with the same name. Queues pop values FIFO style. Use a heap or a binary tree to implement a priority queue. Use (queue (gensym)) to get an anonymous queue, with unique name.
See Moving average
Heaps are collections of elements ordered by a comparison function, compare-proc(elementi elementj) which returns #t iff elementi is 'before' elementj, else #f. Elements may be any EchoLisp object and must not be unique.
For example, if compare-proc is '<', the ordering is element0 <= element1 <= ...
Functions are provided to quickly - ฮ(1) - retrieve or pop the element0 = top of heap, or insert (push) new elements - ฮ(log(n)) - .
Example : taxicab numbers
Notations & definitions
Hint : to mark/unmark vertices, use (mark u value) (mark? u) (unmark u)
Complete sample code in Rosetta code.

An user interface (UI) is a set of HTML DOM Nodes (buttons, sliders, text input, links, ..) which are programmatically added to a given cell, in order to build an application requiring user interaction. Elements are created using ui-create-element, and added to the UI with ui-add. UI functions closely mimic the javascript DOM Nodes functions.
In the following attribute is a string or symbol denoting a Node attribue or property name. Reference : Element Objects and style Object properties. Note that attributes/properties names use the JavaScript syntax : fontSize, backgroundColor, and not the CSS syntax : font-size, background-color.
;; The above panel
(define (ds elem value) (stdout-clear) (writeln elem value) value) ; slider action
(define (db elem) (stdout-clear) (writeln elem "clicked")) ;; button action
;; returns a slider which displays its value
(define (ui-add-active-range (rmin 0)(rmax 1))
(define t (ui-create-element "span" '((style "font-weight:bold"))))
(define s (ui-create-element "input" '((type range))))
(define (lnk elem value) (ui-set-html t value))
(ui-set-attribute s 'min rmin)
(ui-set-attribute s 'max rmax)
(ui-set-attribute s 'step 0.01)
(ui-set-style s 'width "300px")
(ui-on-change s lnk)
(ui-add t)
(ui-add s))
;; returns a button with text
(define (ui-add-button text)
(define b (ui-create-element "button" '((type "button"))))
(ui-set-html b text)
(ui-add b))
;;main panel function
(define (panel )
(ui-clear) ;; remove all elements (if any)
(stdout-clear)
;; input field which checks its content type
(define innum (ui-create-element "input" '((type number) (placeholder "a number") (value "666"))))
(ui-add innum)
(ui-on-change innum ds)
(define intext (ui-create-element "input" '((type text) (style "color:red") (value "Your text here please SVP"))))
(ui-add intext)
(ui-on-change intext ds)
(define br (ui-create-element "br" null))
(ui-add br)
(define t (ui-create-element "span" '((style "font-weight:bold"))))
(ui-add t)
(ui-set-html t " temperature [๐
0 .. 100 ๐]")
(define s (ui-create-element "input" '((type range) ("style" "border :1px solid red"))))
(ui-set-style s "margin-bottom" "-6px")
(ui-on-change s ds)
(ui-add s)
(ui-on-click (ui-add-button "myButton") db)
(define t (ui-create-element "div" null))
(ui-add t)
(ui-set-style t 'backgroundColor "lightgreen")
(ui-set-html t "Division")
(ui-set-style t "marginTop" "10px")
(define ar (ui-add-active-range))
(ui-on-change ar ds)
(define hr (ui-create-element "hr" null)) ;; horizontal line
(ui-add hr)
(define lnk (ui-create-element "a" null)) ;; an html link
(ui-set-html lnk "Echolalie")
(ui-set-attribute lnk "href" "http://www.echolalie.com")
(ui-add lnk)
(stdin-hide #t)) ;; end panel
(panel) ;; show panel
(ui-set-style (ui) ' backgroundColor "orange")
Uses a Table to implements a data base of words (strings) which may be tagged. One can create tags, words, add tags to words, search - select - words. The words tables may be loaded as a library - dico.lib - .
The words and tag tables are referenced by the symbols *words* and *tags* .
(lib 'struct) (lib 'sql) (lib 'words) Lib: words.lib loaded. ;;a data base of 209315 french words. Tags are lexical types (noun, verb, โฆ), genre (sing, plural), etc. (lib 'dico.fr) ;; alternate is (lib 'dico.fr.no-accent) : no accentued characters *words* โ #table:#struct:word [name tags]:[209315] *tags* โ #table:#struct:tag [name]:[26] (table->list *tags*) โ ((#TAGS) (nom) (verbe) (adj) (masc) (fem) (sing) (pluriel) (p3) (det) (pat) (adv) (prep) (pronom) (conj) (int!) (vpronom) (vintran) (inf) (ppas) (imp) (futur) (present) (psimple) (p1) (p2)) (word? 'gallubert) โ #f (word-index 'zythum) โ 201856 (word? 'zythum) โ (zythum nom masc sing) (word-ref 205000) โ รฉliminรขmes (word-random "chinch" null) โ cochinchinoise (word? 'chinchard) โ (chinchard nom masc sing) (word? 'brougnard) โ (brougnard masc pat) (words-select "zoo" null) โ (zoo zoogamรจte zooglรฉe zoogรฉographie zoolite zoolithe zoologie zoologique zoologiquement ... zootechniciennes zootechnie zoothรฉrapeutique zoothรฉrapie zooรฏde) (words-select "/.*zoo.*/" null 40) โ (azoospermie bazooka bazookas enzootie zoo zoogamรจte zooglรฉe zoogรฉographie zoolite zoolithe zoologie zoologique zoologiquement zoologiques zoologiste zoologistes ... รฉpizootiques) (words-select "chinch" '(nom masc sing) 10) โ (chinchard chinchilla) (define (a-bon-chat-bon-rat) (let [ (bon (word-random ".*on$" '(adj))) (chat (word-random ".*at$" '(nom masc -verbe))) (rat (word-random ".*at$" '(nom masc -verbe)))] (printf "ร %s %s %s %s." bon chat bon rat))) (for ((i 100)) (a-bon-chat-bon-rat)) โ ร tatillon goujat tatillon doctorat. ร mignon homรฉostat mignon รฉconomat. ร bon entrechat bon sรฉnat. ร ronchon avocat ronchon gyrostat. ร con corbillat con mรฉcรฉnat. ร fanfaron รฉphorat fanfaron mรฉat. ร laideron alcoolat laideron crachat. ร ronchon exsudat ronchon internat. ร glouton commissariat glouton quinquennat. ร tatillon khalifat tatillon combinat. ร ronchon crouillat ronchon sousdiaconat. ร folichon format folichon anastigmat.
;; a data base of about 235000 english words (no tags) (lib 'dico.en) *words* โ #table:#struct:word [name tags]:[235886] (words-select "zoo" null 30) โ (zoo zoobenthos zooblast... zooecia zooecial zooecium zooerastia zooerythrin zoofulvin zoogamete zoogamous zoogamy zoogene) (words-select "/.*zoo.*/" null 30) โ (actinozoon adzooks Aizoon bazoo bazooka blastozooid bryozoon calycozoon cenozoology cyathozooid cytozoon dactylozooid dermatozoon dermatozoonosis deuterozooid diphyozooid ... entozoologically entozoologist entozoology) (word-random "chinch" null) โ "chinching" (word? 'chinchard) โ #f
Uses an audio control to play .mp3 files, either from the ./sounds library or any accessible URL. The provided audios are : "ring0", "ring1", "ring2" - default -, and "dalida".
(lib 'audio) (audio-src "./sounds/dalida") (audio-play) (audio-volume 0.8) (audio-show)
The following give all native symbols and functions names with min:max arity, libraries excluded. Special forms do not necessarily evaluate all their arguments.
Notations :
๐ Usage in this document: Click onto the α -alpha- letter in the left margin, or hit (keyboard) the first letter you want to go to.
Usage in EchoLisp : (help function-id) to get help about a function.
#
#f
#t
#| comment |#
#:all keyword
#:any keyword
#:auto keyword
#:break keyword
#:continue keyword
#:infix keyword
#:onchange keyword
#:package keyword
#( a b c ...) vector
#{ a b c ...} set
#:tostring keyword
#:when keyword
#' .... '# string input
#<< .... >># here-string input
Printed forms : not readable
#|environment-id| : environment
#function-id : internal function
#:g1001 : internal symbol
Operators
* :0:n
+ :0:n
- :1:n
+= :2
-= :2
++ :1
-- :1
*= :2
/= :2
%= :2
//= :2
// :1:n
/ :1:n
1+ :1
1- :1
< :2
<= :2
= :2
> :2
>= :2
= :2
^ :2
! :1
~= :2
-> :1:n
->> :1:n
Constants
-PI
E
I
PI
PI/2
LOG2
DAY
JOUR
โ
!
!=:1
!eq?:1
!equal?:1
!null?:1
!empty?:1
!zero?:1
A
๐ amb operator
Anp:2
abs:1
acos:1
add1:1
alert:1
alist?:1
angle:1
๐ and:1:n
any:2:3
๐ ap:1 ๐
๐ apropos:1
append:1:n
apply-compose:2
apply-iterate:2
apply:2
๐ arithmetic functions
arithmetic-shift:2
๐ array
asin:1
๐ assert:1:2
assoc-proc-call:4
assoc:2
association-procedure:2
assq:2
assv:2
๐ at (timer.lib)
atan2:2
atan:1
๐ audio functions ๐ ๐ถ ๐ผ
autocomplete-delay:0:1
B
๐ begin:1:n
๐ begin0:1:n
๐ bigint.lib
๐ binary tree
๐ bit-map
๐ bit vectors
bit-count:1
bit-right:1
bitwise-and:2
bitwise-ior:2
bitwise-bit-set?:2
bitwise-not:2
bitwise-xor:2
boolean?:1
bound?:1
box:1
box?:1
#:break
build-vector:2
C
cache:1
cache-size:0:1
*calendar*
๐ call-with-current-continuation:0:n
๐ call/cc:0:n
caaar:1
caadr:1
caar:1
cadar:1
caddr:1
cadr:1
car:1 aka first
cdaar:1
cdadr:1
cdar:1
cddar:1
cdddr:1
cddr:1
cdr:1 aka rest
๐ case:2:n
๐ catch:2
cbrt:1 โ
๐ cdot-product:2
๐ check-expect:2
ceil:1
๐ crt-solve:2 chinese remainder theorem
circular-list:1:n
circular?:1
๐ closure
Cnp:2
๐ combinations:2
๐ Combinators
#|comment |#
; comment
complex:2
complex?:1
๐ compile1:2
๐ compose:1:n
confirm:1
conjugate:1
๐ cond:1:n
cons:2
console-dir:1
console-log:2
console-trace:2
copy:1
cos:1
๐ continued fraction
current-date:0
current-time-milliseconds:0
current-time:0
๐ curry:2:n
D
๐ data-series:1
๐ Dalida
date:0:7
date?:1:1
date->seconds:1
date->string:1
date->date-string:1
date->time-string:1
date-add!:2
date-diff:2
date-format:3
decimals:0:1
debug:1
๐ define-constant:2
define-modifier-key:1
๐ define-macro:3
๐ define-syntax-rule:2
๐ define-syntax-id:2
๐ define-syntax:2:n
๐ define-values:2
๐ define:2:2 a variable
๐ define:2:n a function
define-global:2:2
๐ definitions
๐ delay:1
den:1
dir:0
display:1:2
๐ distance:4
๐ do:2:n
docstring
๐ dot-product:2 ๐
drop:2
E
edit:1
else keyword
empty-stream
empty?:1
every:2:3
๐ environment-current:0
environment-of:1
environment-bindings:1
environment-new:1
environment-parent:1
environment?:1
Examples
๐พ benchmarking
๐พ curves
๐พ combinations
๐พ f(x,y) curves
๐พ regression
๐พ {sets}
๐พ snippets
๐พ todo list
๐ ε, epsilon
eq?:2
equal?:2
eqv?:2
error:2
eval:1:2
even?:1
๐ every2 (timer.lib)
exact->inexact:1
exact?:1
exp:1
expt:2
F
factor:1
factorial:1
file->string:1:2
file?:1
filter-count:2
filter:2
first:1 aka car
๐ flambda:2:n
flatten:1
floor:1
foldl:3:n
foldr:3:n
for-each:2:n
๐ for*/and:2:n
๐ for*/fold:2:n
๐ for*/list:2:n
๐ for*/product:2:n
๐ for*/sum:2:n
๐ for*/string:2:n
๐ for*/vector:2:n
๐ for*:2:n
๐ for/and:2:n
๐ for/fold:2:n
๐ for/list:2:n
๐ for/max:2:n
๐ for/or:2:n
๐ for/product:2:n
๐ for/sum:2:n
๐ for/string:2:n
๐ for/vector:2:n
๐ for:2:n
force:1
forget:1
format:1:n
fract:1
๐ fractal
function definition
G
๐ Γ(x):1
gcd:2
gcd:3:n
๐ generator
gensym:0
get:2
getprop:2
๐ gloops.lib
๐ graph.lib ๐๐
group:1:2
group*:1:2
H
๐ hash tables
๐ heaps ๐๐
๐ help:1 ๐
๐ ?:1
html-print:1
I
๐ Indexed Data Base ๐
identity:1
๐ if:3
imag-part:1
imag:1
in-cycle:0:1
in-naturals:0:1
in-permutations:1
in-primes:1
in-producer:1:n
in-range:1:3
in-range+:1:3
inexact->exact:1
inexact?:1
๐ infix library
info:1:2
inline:2:2
input-expr:2
input-string:2
integer?:1
๐ interface library
iota:1:3
iterate:2
๐ iterators
J
js-eval:1
jsonify:1
๐ JSON
json?:1
make-json:1
export-json:1
json-get:2
json-import:1
json-keys:1
json-put:3
json-types:1
json->plist:1
json->lisp:1
lisp->json:1
json->string:1
string->json:1
๐ Julia set
K
L
๐ lambda-tail-call:2:n
๐ lambda:2:n
๐ ฮป:2:n
last:1
๐ lazy lists
lcm:2
length:1
๐ let*:2:n
๐ let:2:n
๐ letrec:2:n
lib-functions:1
lib:1
๐ list library
๐ list->number:1
list->stack:2:2
list->string:1
list->vector:1
list-index:2
flatten:1
group:1:2
list-ref:2
list-sort:2
list-sort/fields:2
list-swap!:3
list-swap-ref!:3
list-tail:2
list:1:n
list?:1
load-reader-dict:1
load-package:1
load:0:1
log10:1
log2:1
log:1
logical/bit operations
local-verbose:1
local-stores:0:1
local-make-store:1
local-delete-store!:1
local-symbol?:1
local-add:1
local-put:1
local-get:1
local-add-value:2:3
local-get-value:1:2
local-put-value:2:3
local-delete:2:2
M
๐ macros (reader)
๐ฌ mail:3
magnitude:1
make-initialized-vector:2
make-list:2
make-polar:2
make-rect:2
make-regexp:1
make-set:1
make-stream:2
make-symbol:1
make-vector:1:2
map:2:n
maplist:2
mark:2
mark?:1
mark-filter:1:2
mark-print:0:1
๐ ๐ match:2:n ๐๐๐
๐ math.lib
๐ matrix.lib
max:1:n
max:2
member:2
member*:2
memq:2
memv:2
meta-key:2
meta-keys:0
min:1:n
min:2
modulo:2
๐ mutex
N
nconc:1:n
negative?:1
newline:0
๐ next:1
next-prime:1
not:1
notebook:0
null?:1
!null?:1
num:1
๐ num-divisors:1
number-length:1:2
number->string:1:2
๐ number->list:1
number?:1
O
odd?:1
๐ oeis ๐
#:onchange keyword
๐ or:1:n
๐ or*:2:2
P
pair?:1
๐ pattern
๐ permutations
pipeline operator:1:n
plist-keys:1
๐ plot.lib
๐ plot-3d.lib ๐๐๐
polar:2
๐ polynomial in math.lib
positive?:1
positive*?:1
preferences:0 user defined
๐ pretty-print:1:2
prime-factors:1
prime?:1
primes:1
printf:1:n
procedure?:1
๐ procrastinator
๐ product:3
๐ ฮ :3
promise?:1
property lists, aka plists
๐ polynomials
pop:1
powmod:3
push:2
putprop:3
Q
๐ quasiquote:1
๐ queues (tree.lib)
๐ quote:1
quotient:2
R
random-prime:1
random-seed:1
random:0:1
range:1:3
rational:2
rational?:1
rationalize:1:2
๐ rcurry:2:n
read:0:2
read-from-string:1
read-list:0:2
read-number:0:2
read-string:0:2
lisp reader
reader-dict-new:1
reader-dict-set!:2
reader-dict:0
reader-rem-proc:0
reader-set-proc!:2
reader-set-prompt!:1
reader-translate:2
real-part:1
real:1
๐ recursion
๐ regular expressions
regexp-exec:2
regexp-match:2
regexp-match*:2
remember:1:2
remove-local:1
remprop:2
require:1
rest:1 aka cdr
reverse:1
๐ ๐พ Rosetta Code
round:1
S
{ set operations }
set?:1
set-equal?:2
set-intersect:2
set-intersect?:2
set-product:2
set-subset?:2
set-substract:2
set-sym-diff:2
set-union:2
save-as:2 ๐
save-reader-dict:1
save-package:1
second:1
seconds->date:1
๐ semaphore
๐ sequences ๐ ๐ ๐
set-box!:2
set-car!:2
set-cdr!:2
๐ set!:2
๐ setv!:2
๐ set!-values:2
set-plist!:2
shuffle:1
๐ sigma:3
๐ ฮฃ:3
๐ ฮฃฮฃ:3
sin:1
๐ sound
sqrt:1
square?:1
๐ sql.lib
srange:1:3
stack:1
stack-empty?:1
stack-top:1
stack->list:1
stack-length:1
stack-swap:1
stdin-background:1
stdin-color:1
stdin-font-size:0:1
stdin-font:0:1
stdin-hide:1
stdout-background:1
stdout-clear:0
stdout-color:1
stdout-font-size:0:1
stdout-font:0:1
stdout-hide:1
๐ stream-cons:2
make-stream:2
stream->list:1:2
stream-add:2
stream-empty?:1
stream-iterate:1
stream-filter:2
stream-first:1
stream-map:3
stream-mul:2
stream-ref:2
stream-rest:1
stream?:1
string?:1
string:1
string->date:1
string->html:1
string->list:1
string->number:1
string->unicode:1
string-alphabetic?:1
string-append:1:n
string-ci<=?:2
string-ci<?:2
string-ci=?:2
string-ci>=?:2
string-ci>?:2
string-delimiter:0:1
string-diacritics:1
string-downcase:1
string-empty?:1
string-first:1
string-index:2
string-join:1:2
string-last:1
string-length:1
string-match:2:3
string-pad-left:2
string-pad-right:2
string-prefix?:2
string-randcase:1
string-ref:2
string-remove:2:2
string-replace:3:4
string-rest:1
string-split:1:2
string-suffix?:2
string-titlecase:1
string-trim:1
string-trim-left:1
string-trim-right:1
string-upcase:1
string<=?:2
string<?:2
string=?:2
string>=?:2
string>?:2
๐ struct.lib
๐ struct:2:5
style:0:2
sub1:1
sublist:3
substring:2:3
subvector:2:3
symbol->string:1
symbol-plist:1
symbol?:1
symset!:1
๐ syntax rules
system-global-environment
T
๐ tables - sql.lib
take:2
tan:1
๐ task
text-parse:1:2
third:1
throw:2
๐ time-series:1
๐ time:1
๐ timer.lib
๐ tree.lib
trace:1
๐ try:2:n
tree-fold:3
tree-for-each:2
๐ ๐ฒ typed vectors : vlib
๐ Types
U
๐ User Interface
unbox:1
๐ undefine:1
๐ unless:2:n
unicode->string:1
unmark:1
๐ unquote-splicing:1
๐ unquote:1
untrace:1
๐ usage:1 ๐
use-infix:1
user-initial-environment
V
๐ values:1:n
vector-append:2
vector-dup:1
vector-empty?:1
vector-index:2:3
vector->list:1
vector-fill!:2
vector-filter:2
vector-insert*:2
vector-length:1
vector-map:2:n
vector-permute!:2
vector-pop:1
vector-push:2
vector-ref:2
vector-remove*:2
vector-remove-ref!:2
vector-rotate!:2
vector-search:2:3
vector-search*:2
vector-set!:3
vector+=:3
vector*=:3
vector-shift:1
vector-sort!:2
vector-swap!:3
vector:0:n
vector?:1
๐ math.lib - vector products
version:1
๐ ๐ฒ typed vectors : vlib
void:0
void?:1
W
๐ wait:2
๐ web.lib
๐ when:2:n
๐ while:2:n
Wittgenstein philosopher
๐ words.lib
write:1:n
writeln:0:n
worksheet-open:1
worksheet-remove:1
worksheet-save:1
X
xor:2
Y
๐ yield
Z
zero?:1
!zero?:1
ยซ [...] les parenthรจses sont l'instrument privilรฉgiรฉ de ce lent et difficile รฉclaircissement pour traverser les apparences qui est au cลur de l'esthรฉtique proustienne; elles expliquent, au sens รฉtymologiqueโex-plicare: - dรฉplier, dรฉrouler - ce qui, sans cet effort d'analyse, resterait confus; ce sont autant d'auxiliaires prรฉcieux d'un Narrateur qui se veut avant tout un traducteurยป
Isabelle Serรงa - La parenthรจse chez Proust -