EchoLisp Reference Manual

๐Ÿ“š ๏ธ๐ŸŽจ  ๐Ÿ“ญ 

Table of contents

Introduction

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.

French flag 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.

Offline operations

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.

General

Worksheet

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 :

๐Ÿ“  : console cell : stdin is cleared after each evaluation, and results are appended into stdout. Console cells are the usual place to call and try functions with different parameters values, evaluate one-shot expressions, etc.

๐Ÿ“Œ : standard cell : stdin is not cleared , and stdout is cleared before each result display. Standard cells are the usual place to input things to remember : define functions, edit functions definitions, load files, etc.

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.

Worksheet buttons and functions

(notebook ) โž› list of all known worksheets names

(worksheet-open name-string ) โž› opens a work sheet. Same as  Open  button.

(worksheet-save name-string ) โž› saves a work sheet. Same as  Save  button. Only the input fields contents are saved.

(worksheet-remove name-string ) โž› removes a work sheet from the notebook.


 Eval  Evaluates in sequence all the worksheet cells.

 New  Opens a blank worksheet.

;; open a worksheet at loading time
(define (preferences)
	(worksheet-open "sandbox"))

User interface

⏎ Enter key : new line

⇧-⏎ Shift-Enter key : Evaluates input (same as โ—๏ธ button)

ESCape key : clears a cell input & ouput areas. Same as x button

⌦ suppr : clears input area. Use (suppr-key [#f|#t]) to toggle this behaviour. The default is #f : clearing disabled.


โž• Adds a new cell

x  Clears the cell

โŒ Removes the cell


History of input expressions (16 max). The following keys will "recall" input expressions :

previous

next

first

last


&i short-cut โž› evaluates result labelled [#i]

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

Autocomplete

The lisp reader procedure will try to present choices based on the first characters you type and the frequency of preferred symbols.

⇥ (Tab) : Choose

๐Ÿ”ฝ : Next choice


Plotting


๐Ÿ“Š : Show/hide a cell graph. Requires the plot library : (lib 'plot.lib)


 Load  button

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.

On-line help

(version) โž› displays Echolisp version string and returns the version number.

(usage function-id) โž› displays syntax and parameters types for function into the information text field. Function-id may be a native function or an user defined function with a documentation string.

(us function-id) โž› short-cut for (usage ...)


(apropos string) โž› all symbols matching string

(apropos regexp) โž› all symbols matching regexp

(ap โ€ฆ) โž› synonym for (apropos โ€ฆ)


(help symbol) โž› opens page (or browser tab) about symbol (*)

(help letter) โž› opens alphabetical list at letter letter (*)

(?? symbol) โž› synonym for (help symb)


(info symbol description-string) โž› sets description for symbol

(info symbol) โž› symbol description or #f if none. Info strings are stored into the local data base - permanent local storage - inside the 'info' store. Use (info symbol null) to remove a description.

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

Notations

(function-id type1 type2 ...) โž› result

Call of function function-id with arguments which evaluate to values of type typei, and evaluates to 'result'. Arguments types may be :

Naming conventions for symbols

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

Language

Special characters

Symbolic expressions

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

(gensym) โž› generates a fresh new internal symbol, distinct from all other.

(make-symbol [name|string]) โž› generates a fresh new symbol, prefixed by name.

; 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 '๐ŸŽ'.
	

Programs and Evaluation

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 !

Boolean expressions

"All which is not #f is #t" (Ludwig Wittgenstein)

Boolean value #t (true)

Boolean value #f (false)

(boolean? obj) โž› #t iff obj is #t or #f

(not #f) โž› #t

(not any-other-than-#f) โž› #f

(or e1 e2 ..) โž› eval e1 e2 .. until ei not = #f and returns ei or #f none true

(or* e1 e2 ) โž› eval e1. If e1 = #f or null or 0 or "" : eval and returns e2. Else returns e1.

(and e1 e2 โ€ฆ) โž› eval e1 e2 .. stops on first ei = #f; returns elast or #f is none true

(xor e1 e2) โž› eval e1 and e2 and returns the exclusive or e1 โŠ— e2 Reminder: #t โŠ— #t = #f โŠ— #f = #f , #t โŠ— #f = #f โŠ— #t = #t

#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

Calculus

Operators

(identity x) โž› x

(+ a b c ...) โž› a + b + c + ...

(- a) โž› -a

(- a b c โ€ฆ) โž› a - b - c - โ€ฆ

(* a b c โ€ฆ) โž› a * b * c โ€ฆ

(/ a) โž› 1 / a

(/ a b c โ€ฆ) โž› a / (b * c * โ€ฆ)

(// a b) โž› float result: same as (exact->inexact (/ a b))

(% a b) โž› a modulo b

(min x y z โ€ฆ) โž› minimum of

(max x y z โ€ฆ) โž› maximum of

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

Constants

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 ;; e = - 1 ๐ŸŽฉ Euler
(log E)  โž›   1
(tan PI/2)  โž›   16331239353195370
(* I I)  โž›   -1+0i

(+ Infinity 7) โ†’ Infinity
(* Infinity -2016.2016) โ†’ -Infinity

Numbers - predicates

Set inclusion : Integer ⊂ Rational ⊂ Complex ⊂ Number. All predicates end with '?' and return #t (true) or #f (false).

(number? n)

(rational? q)

(integer? n)

(complex? z)

(exact? x)

(inexact? x)

(positive? x)→ #t iff n >= 0

(negative? x)

(positive*? n) → #t iff n > 0

(zero? x)

(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

Integer functions

(even? n)

(odd? n)

(floor x) โž› nearest integer <= x

(number-length x [base]) โž› number of digits of (floor x), in base b (default=10)

(ceil x) โž› nearest integer >= x

(round x) โž› nearest integer

(square? n) โž› is n a square ?

(modulo n p) โž› m such as n = q*p + m , 0 <= m < p

(% n p) โž› same as modulo

(quotient n p) โž› q such as n = q*p + m , 0 <= m < p


(1+ x) โž› x + 1

(add1 x) โž› x + 1

(1- x) โž› x - 1

(sub1 x) โž› x - 1

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

Arithmetic

All of these functions work for integers < 2e+9. For larger integers, the bigint.lib may be used.

(powmod base exp mod) โž› baseexp modulo mod

(gcd a b c โ€ฆ) โž› greatest common divisor

(lcm a b) โž› least common multiple = a * b / gcd (a,b)


(prime? p) โž› #t if p is prime

(primes n) โž› set of n first primes

(factor a) โž› least prime factor of a ; = a iff a is prime

(prime-factors n) โž› ordered list of prime factors

(random-prime n) โž› a prime p in [2โ€ฆn]

(next-prime n) โž› least prime p > n

(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

Bitwise operations

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.

(bit-count n ) -> number of bits set in n, 0 to 32

(bit-right n ) -> index of most significant right bit set in n, 0 to 31

(bitwise-ior n m ) -> logical or : 0|0 = 1, 1|0 = 0|1 = 1|1 = 1

(bitwise-and n m) -> logical and : 1&1 = 1, 1&0 = 0&1 = 0&0 = 0

(bitwise-xor n m ) -> logical exclusive or : 0โŠ—0 = 1โŠ—1 = 0, 0โŠ—1 = 1โŠ—0 = 1

(bitwise-not n) -> logical not : ~0 = 1, ~1 = 0

(bitwise-bit-set? n b) is bit number b (0 <= b < 31) set ? #t or #f

(arithmetic-shift n m ) -> left shift - multiply by 2m - if m >=0 ; right shift if m < 0


(number->string n [2|16]) -> base 10, 2 or hexadecimal conversion. May be long for huge (> 10000 digits) numbers

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

Combinatorics

NB: more combinatoric functions are defined in the list.lib library.

(factorial n) โž› n! = 2 * 3 * โ€ฆ * n

(! n) โž› n! = 2 * 3 * โ€ฆ * n Same as factorial

(Cnp n p ) โž› combinations : n! / (p! * (n-p)!)

(Anp n p) โž› arrangements : n! / (n-p) !


(vector-permute! vector permutation-vector) โž› permutes vector in place, using permutation-vector which is a permutation of the indices [0 ... n-1]. In other words, result[i] := vector[perm[i]]

(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


Rational numbers a/b

22/7 โž› read new rational

(rational? x) โž› #t or #f

(rational a b) โž› a/b

(num a/b) โž› numerator: a

(den a/b) โž› denominator: b

(rationalize x) โž› p/q : |x - p/q| < 0.0001

(rationalize x ฮต) โž› p/q : |p/q - x| < ฮต

(/ a b)โž› rational (when possible)

(// a b) โž› always float

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

Complex numbers z = a+ib

7+3i โž› read - input - a new complex

(complex? z) โž› #t or #f

(complex a b) โž› new complex = a + ib

(make-rect a b) โž› new complex = a + ib

(polar rho theta) โž› new complex = rho * (cos(theta) + i sin(theta))

(make-polar rho theta) โž› new complex = rho * (cos(theta) + i sin(theta))

(imag z) โž› imaginary part

(real z) โž› real part

(imag-part z) โž› imaginary part = b

(real-part z) โž› real part = a

(magnitude z) โž› rho = sqrt(a*a + b*b)

(angle z) โž› theta = atan2(b,a) in [-PI..PI]

(conjugate z) โž› z = a-ib

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].

Math functions

z ∈ 𝓒 - x ∈ 𝓡

(abs x) โž› |x|

(fract x) โž› fractional part

(sin z)

(cos z)

(tan z)

(log z)

(sqrt z) โž› square root

(cbrt z) โž› cubic root

(exp z) โž› ez

(expt z z1) โž› zz1

(^ z z1) โž› zz1 Same as expt

(acos x) โž› alpha in [0 .. PI]

(asin x) โž› alpha in [-PI/2.. PI/2]

(atan x)โž› alpha in [-PI/2 .. PI/2]

(atan y x) โž› alpha in [-PI .. PI] : tan(y/x) = alpha

(log2 x) โž› y : 2y = x

(log10 x) โž› y : 10y = 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

(random ) โž› random in [0 โ€ฆ 1[

(random -1) โž› random in ]-1 โ€ฆ 1[

(random int-base) โž› random integer in [0 .. base [

(random int-negative-base) โž› random integer in ]base ... -base[

(random-seed seed) โž› new seed

(shuffle list) O(n) operations

(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)  โž›  โšƒ

Predicates

(symbol? obj) โž› #t or #f

(procedure? obj) โž› #t or #f

(number? obj) โž› #t or #f

(null? obj) โž› #t if obj is null - which is the same as the empty list ()

(empty? obj) โž› same as (null? obj)

(!null? obj) โž› same as (not (null? obj))

(!empty? obj) โž› same as (not (empty? obj))

(list? obj) โž› #t if obj is a list or null

(pair? obj) โž› #t if obj is a list not null or dotted pair (a . b)

(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

Comparison operators

All things which are "eq?" are also "equal?" (Broderick Fitsche)

(eq? obj1 obj2) โž› #t iff obj1 and obj2 are the same object (pointer)

(eqv? obj1 obj2) โž› #t iff (eq? obj1 obj2) or same value objects or same numeric vectors

(equal? obj1 obj2) โž› #t iff (eqv? obj1 obj2) or isomorphic objects

(!eq? obj1 obj2) โž› same as (not (eq? obj1 obj2))

(!equal? obj1 obj2) โž› same as (not (equal? obj1 obj2))

(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

Numbers comparisons

(= x y)

(!= x y) same as (not (= x y))

(> x y)

(>= x y)

(< x y)

(<= x y)

(zero? x)

(!zero? x) โ†’ same as (not (zero? x))

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

Lists

"All lists are incomplete, except the empty list" (Maurice Blanchot)

null or () is the empty list.

(first list) โž› first item of list

(car list) โž› same as (first list)

(rest list) โž› rest of list, after first item

(cdr list) โž› same as (rest list)

(second list) โž› (first (rest list))

(cadr list) โž› (car (cdr list)) same as (second list)

(third list) โž› (first (rest (rest list)))

(caddr list) โž› (car (cdr (cdr list)) same as (third list)

(cddr list) โž› (cdr (cdr list))

and car/cdr combinations : caar, cadr, cdar, cddr, caaar, caadr, โ€ฆ

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

Lists - components

(length list)

(last list) โž› last element

(list-ref list index) โž› list[index] - index in [0..length(list)[

(list-index item list) โž› position of item in list - in [0..length(list)[ - or #f . Uses (equal?) predicate.


(sublist list from to) โž› new list = list [from ..to[

(list-tail list pos) โž› list [pos ... end] Same as (cddd..dr list). pos is in [0..length(list)[ ; starts from end if pos < 0


(take list n) โž› new list : n first elements of list

(drop list n) โž› new list : n first elements removed

๐Ÿ‘“ ๐Ÿ‘“ ๐Ÿ‘“ 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

Pairs

(cons item1 item2) โž› pair {item1 . item2}

(car pair) โž› item1

(cdr pair) โž› item2

(pair? pair) โž› # t

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

Lists - marking

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.

(mark list tag) โž› marks head of (sub)list with tag

(unmark list) โž› removes tag

(mark? list) โž› is list marked ? #f or tag

(mark-filter list) โž› extracts list of all marked sublists

(mark-filter list filter) โž› extracts list of all marked sublists, whose tag is eq to filter

(mark-print [#t | #f]) โž› show/hide marks - #t is default

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

Lists construction

(cons item null) โž› new list = (item) ; constructor : the mother of all lists

(cons item list) โž› new list : first = item, rest = list

(cons item-a item-b) โž› dotted pair ( item-a . item-b)

(append list1 list2 โ€ฆ ) โž› new list : makes a copy of list1 and appends list2..n.The last list may be an atom. (append '(a b c) d) is the same as (append '(a b c) (list d))

(list a b c โ€ฆ) โž› (a b c โ€ฆ) ; make a new list from items a,b, ...

(make-list length obj) โž› new list (obj obj obj โ€ฆ)


🌵 Chirurgy - Be careful - ๐Ÿ˜ต list is modified

(list-swap! list u v ) โž› (a b c โ€ฆ v โ€ฆ u โ€ฆ)

(list-swap-ref! list i j ) โž› swaps items at index i,j. i,j in [0 โ€ฆ length(list)-1]

(set-car! list new-first) โž› (new-first b c โ€ฆ)

(set-cdr! list list2) โž› (a x y z ..) ; replaces (rest list) by list2

(nconc list list2 โ€ฆ) โž› (a b c .. x y โ€ฆ) ; physically concatenates lists

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)

Lists of numbers

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 n) โž› {0 1 2 โ€ฆ n-1}

(range n ) โž› {0 1 2 โ€ฆ n-1}

(range start end ) โž› {start start+1 โ€ฆ end-1}

(range start end step) โž› {start start+step start+2*step โ€ฆ < end}

(srange start [end [step]]) โž› {start start+step start+2*step โ€ฆ < end}. Same as range, but start/end/step may be rational or float values.

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

Lists operations

(member item list) Looks for item in list โž› #f or sublist (item โ€ฆ) - uses equal? predicate

(member* item list) Looks for item in list, and recursively in sub-lists of list. โž› #f or sublist (item โ€ฆ) - uses equal? predicate

(memv item list) Looks for item in list โž› #f or sublist (item โ€ฆ) - uses eqv? predicate

(memq item list) Looks for item in list โž› #f or sublist (item โ€ฆ) - uses eq? predicate


(filter predicate list) โž› list all items such as (predicate item) is #t

(filter-count predicate list) โž› count items such as (predicate item) is #t


(reverse '(a b c d)) โž› (d c a b)

(flatten list) โž› recursively flattens sub-lists


(group list) โž› new list = group consecutive equal? items into sub-lists. O(n)

(group list compare-proc:2:2) โž› new list = group consecutive items into sub-lists, using compare-proc for testing equality. O(n)

(group* list) โž› new list = group equal? items into sub-lists. O(n2)

(group* list compare-proc:2:2) โž› new list = group items into sub-lists, using compare-proc for testing equality. O(n2)


(list-sort sort-predicate list) โž› new list sorted by (sort-predicate a b) -> #t|#f

(list-sort/fields num-fields list) list is a list of lists : (field0 field1 ..) Ascending sorts list by sorting first on field0, then field1, ..fieldi, i in [0..num-fields[. โž› new list


(shuffle list) โž› random ordering


(circular-list a b c) โž› (a b c a b โ€ฆ ad infinitum)

(circular? list) does this list contain auto-references ? โž› #t or #f

(copy list) โž› deep copy of list; can copy circular lists or lists with deep auto-references.
(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)))

๐Ÿ“– List library

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

(list-partition list predicate:1) โ†’ new list (left-list right-list) such as for each element left in left-list : (predicate left) is #t, other elements in right-list.

(list-partition list compare-proc:2 pivot) โ†’ new list (left-list right-list) such as for each element left in left-list : (compare-proc left pivot) is #t, other elements in right-list.


(list-rotate list n) โ†’ new list rotated left n times. n may be negative

(list-rotate! list n) โ†’ list is rotated left n times

(list-rotate-right! list n) โ†’ list is rotated right n times


(list-insert! list new-item after) โ†’ inserts new-item after after-item; uses eq? predicate to find after-item; error if after-item is not found.

(list-replace! list old-item new-item) โ†’ replaces (one time) old-item by new-item; uses eq? to find old-item; return #f if old-item not found.

(list-delete list item) โ†’ new list, with item deleted; #f if item not found.

;; see selection sort for examples of use.

Permutations and combinations

(sublists list p) โ†’ returns a list of the 2N sublists of list in unspecified order, including the empty - null - list. Rem. (sublists ()) โ†’ (()).


(list-permute list permutation) โ†’ a new permutation of list. permutation is a list or vector permutation of the integers 0..n-1 where n is length(list). The permutation may include repetitions.


(permutations list) โ†’ returns a list of the n! permutations of the elements of list.

(in-permutations list) โ†’ returns a stream delivering the n! permutations of the list (0 ... n-1).


(combinations list p) โ†’ returns a list of the combinations of the n elements of list taken p at a time witout repetition. The number of combinations is (Cnp n p) = n!/(p! * (n-p)!), p <=n.


(combinations/rep list p) โ†’ returns a list of the combinations of the n elements of list taken p at a time with possible repetition. The number of combinations with repetition is (Cnp n+p-1 p), p may be > n.

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

Environments

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


(environment? obj) is obj an environment ? โ†’ #t or #f

(bound? symbol) โ†’ #f or the environment in which symb is bound

(environment-current) โ†’ environment in which this function is called

(environment-bindings env) โ†’ env-list = ((name1 value1) (name2 value2) ...)

(environment-parent env) โ†’ null or parent

(environment-of lambda-closure | function-id | symbol ) โ†’ its environment or null

(environment-new env-list) โ†’ new environment with bindings (namei valuei)

system-global-environment โ†’ starter environment

user-initial-environment โ†’ user environment = top-level environment


(eval expression) โ†’ evaluates expression in current environment

(eval expression env) โ†’ evaluates expression in environment env




Functions

Function call

(operator val1 โ€ฆ vali โ€ฆ valn) โž› function call

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.

(apply fun list) โž› applies a function to a list of values

(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 fun:1 n) โž› list ((fun 0) (fun 1) ... (fun n-1)). fun:1 is a function of one integer argument in {0, 1, 2 ...}

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

Lambda

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 (arg1 โ€ฆ argn) expr1 โ€ฆ ) โž› n arguments

(lambda (arg1 .. argn (argn+1 defn+1) ..(argp defp)) expr1 โ€ฆ) โž› arguments with default values

(lambda (arg1 โ€ฆ argn . rest-id) expr1 โ€ฆ) โž› n arguments + variable number of args bound to rest list

(lambda rest-id expr1 โ€ฆ ) โž› variable number of arguments

(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

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

Function definition

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 (function-id arg1 โ€ฆ argn) expr1 โ€ฆ)

(define (function-id arg1 ... argn (argn+1 defn+1) ... (argp defp)) expr1 โ€ฆ)

(define (function-id arg1 โ€ฆ argn . rest-id) expr1 โ€ฆ)

(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 recursion - No Fibonacci was harmed during the making of this television computer program

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

Remember : Caching functions values

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.

(remember function-name ) โ†’ sets an empty cache for the function

(remember function-name init-vector ) โ†’ sets an initialized cache for the function : f(0) = v[0], ...

(forget function-name) โ†’ suppress the cache for the unction

(cache function-name) โ†’ #f or vector of values f(0) f(1) ...

(cache-size ) โ†’ cache size - the same for all functions

(cache-size new-size) โ†’ sets the cache size
;; 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

Functions composition

(-> x f1 f2 f2 ...) pipeline first โž› (flast ... ( f2 ( f1 x))). The fi are functions symbols or function calls : (fi a b c ...). If fi is a function call, then the value x for f1, or the previous result for fi>1 is inserted first in the list of parameters. If the parameters list include one or more place holders : _ , then a replacement is made at the placeholder location, instead of first location.


(->> x f1 f2 f3 ...) pipeline last โž› (flast ... ( f2 ( f1 x))). If fi is a function call, then the value x for f1, or the previous result for fi>1 is inserted last in the list of parameters. If the parameters list include one or more place holders : _ , then a replacement is made at the placeholder location, instead of last location.


(curry proc l1 l2 โ€ฆ) โž› returns a curried-proc - lambda expression - such as the call (curried-proc r1 r2 โ€ฆ) is equivalent to the call (proc l1 l2 โ€ฆ r1 r2 โ€ฆ)

(rcurry proc r1 r2 โ€ฆ) right-curry โž› returns a right-curried-proc - lambda expression - such as the call (right-curried-proc l1 l2 โ€ฆ) is equivalent to the call (proc l1 l2 โ€ฆ r1 r2 โ€ฆ )

curry is functionally equivalent to: (define (curry proc . left-args) (lambda right-args (apply proc (append left-args right-args))))

(compose f:1 g:1 h โ€ฆ last:n) โž› λ : f โˆ˜ g โˆ˜ h โˆ˜ โ€ฆ โˆ˜ last

(iterate f:1 n) โž› λ : f โˆ˜ f โˆ˜ f โˆ˜ โ€ฆ = fn

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

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 (function-name x [y [ z [ t]]]) expression-string) โž› function-name or #f in case of syntax error.

(inline (sphere x y z) "x-= 3 ; return x^2 + y^2 + z^2 - 25")
(plot-3d-xyz sphere)

Compile.lib - Functions compilation

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.

(compile function-name [options-string]) โž› #t or #f

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

Local bindings

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 ((id1 val-expr1) โ€ฆ) expr1 โ€ฆ exprn) โž› Parallel binds idi to val-expri and evals expr1 ..exprn

(let proc-id ((id1 val-expr1) โ€ฆ) expr1 โ€ฆ exprn) โž› Binds proc-id to the let lambda body

(let* ((id1 val-expr1) โ€ฆ) expr1 โ€ฆ exprn) โž› Sequential binds idi to val-expri and evals expr1 ..exprn

(letrec ((id1 val-expr1) โ€ฆ) expr1 โ€ฆ exprn) โž› Recursively binds idi to val-expri and evals expr1 ..exprn

(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

Local variables

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

Variables - Definitions -

Definition

(define var-id value) sets a binding for var-id - a symbol - in the current environment, which is user-initial-environment if the definitions is made at top-level. โž› var-id

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-global expr value) expr must evaluate to a symbol, the binding of which is set to value, inside the global - user-initial - environment. โž› symbol


(define-constant CONSTANT-ID value) installs a replacing macro for CONSTANT-ID. โž› CONSTANT-ID


(define-values (var-id1 โ€ฆ var-idi ..) value-expression) define several var's at once, โž› (var-id1 โ€ฆ var-idi ..)

(values val1 โ€ฆ vali โ€ฆ) โž› value expression

(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 

Assignment

(set! var-id value) โž› Sets a new binding for var-id in the current environment. The var-id must be defined - either globally, or locally such as a function argument - before being set. var-id is not evaluated. Returns (void)

(setv! var-id value) โž› same as set! , but returns value.


(set!-values (var-id ...) values-expression) โž› new parallel bindings for var-id's in the current environment. Returns (void). values-expression is either (values a b ..) or a list ( a b ...)


(++ var-id ) โž› Binds var-id to its value + 1. Same as (set! var-id (+ var-id 1)). Returns new var-id value.

(-- var-id ) โž› Binds var-id to its value - 1. Same as (set! var-id (- var-id 1)). Returns new var-id value.


(+= var-id increment) โž› Binds var-id to its value + increment. Same as (set! var-id (+ var-id increment)). Returns new var-id value.

(-= var-id increment) โž› Binds var-id to its value - increment. Same as (set! var-id (- var-id increment)). Returns new var-id value.


(*= var-id multiplier) โž› Binds var-id to its value + multiplier. Same as (set! var-id (* var-id multiplier)). Returns new var-id value.

(/= var-id divisor) โž› Binds var-id to its value / divisor. Same as (set! var-id (/ var-id divisor)). Returns new var-id value. Rational, exact division

(%= var-id modulo) โž› Binds var-id to its value modulo modulo. Same as (set! var-id (% ver-id modulo)). Returns new var-id value.

(//= var-id divisor) โž› Binds var-id to its value // divisor. Same as (set! var-id (// var-id divisor)). Returns new var-id value. Float, inexact division.


(symset! expr value) expr must evaluate to a symbol name, var-id. โž› Sets a new binding for var-id in the current environment. The var-id must be defined - either globally, or locally such as a function argument - before being set. Returns value.

(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

Mapping and folding

" โ€ฆ liste des chasseurs qu'Assourbanipal invitait ร  ses battues" (Marcel Proust)

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.

(for-each fun:1 lista) โž› evals (fun ai) for all i - returns void

(for-each fun:2 lista listb) โž› evals (fun ai bi) - returns void

(map fun:1 lista) โž› returns a list : ((fun a1) (fun a2) โ€ฆ)

(map fun:2 lista listb) โž› returns a list : ((fun a1 b1) (fun a2 b2) โ€ฆ)

(maplist fun:1 list) โž› returns a list : ((fun list) (fun (rest list)) (fun (rest(rest list))) โ€ฆ)


(every predicate:1 lista) โž› returns #t iff all (predicate ai) ... return #t. Else #f.

(every predicate:2 lista listb) โž› return #t iff all (predicate ai bi) โ€ฆ return #t. Else return #f.

(any predicate:1 lista) โž› returns ai if one of (predicate ai) returns #t. Else #f.

(any predicate:2 lista listb) โž› returns ( ai . bi) if one of (predicate ai bi) returns #t. Else returns #f.


(foldl fun:2 v0 lista) โž› accumulates vi = (fun ai vi-1) from left to right - return vn

(foldl fun:3 v0 lista listb) โž› accumulates vi = (fun ai bi vi-1) - returns vn

(foldr fun:2 v0 lista) โž› accumulates vi = (fun ai vi-1) from right to left - return vn

(foldr fun:3 v0 lista listb) โž› accumulates vi = (fun ai bi vi-1) - returns vn

(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

Vectors implement variable length arrays of lisp objects.. Vectors do self-evaluate.

#( a b c โ€ฆ) โž› read new vector

#( 0 4 PI I 333 โ€ฆ) โž› read new vector

(vector? V) โž› #t or #f

(vector a b c โ€ฆ) โž› new vector #(a b c ...)

(vector-empty? ) โž› #t or #f

(vector-length V)

(make-vector length) โž› new vector #(0 0 0 ...)

(make-vector length init) โž› new vector #(init init ...)

(vector-dup V) โž› new vector, shallow copy of V

(copy V) โž› new vector, deep copy of V

(vector-append V1 V2) โž› new vector of concatened contents

(build-vector length fun) โž› new vector #((fun 0) (fun 1) ...)


(subvector V start [end]) โž› new vector V[start] .. V[end-1]

(take V n) โž› new vector V[0]..V[n-1]

(drop V n) โž› new vector V[n]..V[last]


(vector->list V) โž› list

(list->vector '(a b c ...)) โž› new vector #(a b c ..)


(vector-fill! V a) โž› #(a a aโ€ฆ)

(vector-pop V) โž› #f if V is empty

(vector-push V obj) โž› adds obj at end of V

(vector-swap! V i j) tmp = V[i], V[i]=V[j],V[j] = tmp ; โž› tmp

(vector-shift V) โž› removes V[0] and returns it. #f if V is empty

(vector-rotate! V n) โž› rotates V in place, n times. Left if n < 0, right if n > 0.


(vector-ref V i) โž› V[i] , i in [0.. length[. Error if i is out of bounds

[V i] โž› same as (vector-ref V i). Short-cut, and quick access


(vector-remove-ref! V i) โž› removes V[i] and returns it.

(vector-set! V i obj) โž› set V[i] to obj. Returns obj. No error if i is out of bounds allocated by make-vector. Vector size increases as needed.


(vector+= V i increment) โž› set V[i] to V[i]+increment. Returns V[i].

(vector*= V i multiplier) โž› set V[i] to V[i]*multiplier. Returns V[i].


(vector-map fun V W ... ) โž› new vector [(fun V[0] W[0] ...) (fun V[1] W[1] ...) โ€ฆ.]

(for-each fun V W ... ) โž› call (fun V[0] W[0] ...) (fun V[1] W[1] ...) ... returns void


(vector-filter pred V) โž› new vector U from V, such as (pred U[i]) = #t

(vector-index value V [start-index]) โž› i such as (equal? V[i] value), or #f. Sequential search from start-index or 0 (default)

Sorted vectors

(vector-sort! sort-proc:2:2 V) โž› reorder vector such as (sort-proc V[i-1] V[i]) = #t


(vector-insert* sorted-vector/< value) inserts value in V, at the right place โž› value or #f

(vector-remove* sorted-vector/< value) removes value from V โž› value or #f

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

Types

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.

(make-type type-name [supertype] type-expression) โ†’ new Type. supertype is optional.

(type? object) Is object of type Type ? โ†’ #t or #f

(types) โ†’ list of known Types


(type-of? expr type) Checks expr value versus type. โ†’ #t or #f.

(type-check expr type [proc:1]) Checks expr value versus type. โ†’ #t if successful. Else if proc is present, returns (proc expr). Else raises an error.

(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

Typed EchoLisp

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.

(signature function-id) โ†’ signature = list-of-types or null

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

Polymorphism - Methods




๐Ÿšฒ Typed vectors library : vlib.lib ๐Ÿšฒ

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.

(make-<type>-vector length [init-value]) -> new constant sized typed vector

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

See also plot functions and typed vectors.

Bit-vectors

Bit-vectors - sets of #f/#t values - are implemented using uint32 vectors

.

(make-bit-vector n) โž› n-bits bit-vector, initialized to #f (0). Bits are numbered 0 .. n-1.

(make-bit-vector-1 n) โž› n-bits bit-vector, initialized to #t (1). Bits are numbered 0 .. n-1.

(build-bit-vector n fun:1:1) โž› n-bits bit-vector, bit b initialized to #f if (fun b) = #f, else to #t.


(bit-vector-set! bit-vector b [#t|#f]) โž› sets bit b , b in [0 .. n-1] to #t or #f

(bit-vector-ref bit-vector b) โž› #t or #f

(bit-vector-toggle bit-vector b) โž› toggles the value of bit b. โž› new value

(bit-vector-scan-0 bit-vector b) โž› bit number of first #f bit, from b included. โž› #f if not found

(bit-vector-scan-1 bit-vector b) โž› bit number of first #t bit, from b included. โž› #f if not found


(bit-vector-take bit-vector b n ) โž› list of n first values (b1 ... bn) such as bit-vector[bi] = #t

(bit-vector-count bit-vector b) โž› n = number of #t bits, up to b included.

(bit-vector-xcount bit-vector n) โž› b such as there are n #t bits up to b, included. #f if not found.



Sets

"Sets are lists, but lists are not sets" - Broderick Fitsche -

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.

โˆ… โž› constant : the empty set - same as null

#{b a c c d ...} โž› {a b c d ...} read a set, by calling make-set

(set? object) is object a set? โž› #t or #f

(make-set from-list) โž› new set from from-list

(set-equal? setA setB) โž› #t or #f (deep equality)

(set-intersect setA setB) โž› elements in A and in B

(set-product setA setB) โž› all pairs (a . b) where a in A and b in B

(set-union setA setB) โž› elements in A or B

(set-intersect? setA setB) โž› #t or #f

(set-substract setA setB) โž› elements in A, not in B

(set-subset? setA setB) โž› all elements of B in A ? โž› #t or #f

(set-sym-diff setA setB) โž› symmetrical difference : elements in (A or B) , not in (A and B)

(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

Strings

"All strings are immutable" (Ludwig Wittgenstein)

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 ) โž› get string output delimiter. " = default

(string-delimiter delimiter) โž› set string output delimiter. Use "" for none.

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

(string? obj) โž› #t if obj is a string, else #f

(string-empty? obj) โž› #t if obj is the empty string, else #f

(string obj) โž› obj converted to string


(string-alphabetic? str) โž› #t if all characters are in range [a-z A-Z รฉรจรช...], else #f

(string-length str)


(string-ref str index) โž› str[index]

(string-first str) โž› str[0]

(string-last str) โž› str[(string-length str) -1]

(string-rest str) โž› str[1 โ€ฆ]


(substring str start) โž› str[start โ€ฆ last]

(take str n) โž› str[0 โ€ฆ n[

(drop str n) โž› str[n โ€ฆ last]

(substring str -start) โž› str[last-start โ€ฆ last] - negative start

(substring str start end) โž› str[start โ€ฆend[


(string-append str1 str2 ..) โž› concatenates all stri. Use (string-append s) to make a copy of s

(string->list str) โž› explode string into list of characters

(string-join list [separator]) โž› concatenates each list elelemnt string representation, inserting separator. The default separator is " " .

(list->string list) โž› concatenates list items string representation


(string-upcase "abcd") โž› "ABCD"

(string-downcase "ABcD") โž› "abcd"

(string-titlecase "longtemps") โž› "Longtemps"

(string-randcase "longtemps") โž› "lOnGTeMps"


(string-replace str old new) โž› replaces old by new inside str

(string-remove str to-remove) โž› removes all characters - any order - of to-remove string from str

(string-match str substring) is substring inside string ? โž› #t or #f


(string-prefix? prefix str) โž› #t or #f

(string-suffix? suffix str) โž› #t or #f

(string-index needle-str str) โž› index >=0 or #f if needle not found


(string->number str) โž› parses string into integer or float (inexact) number. Returns #f if str does not represent a number.

(number->string number [base]) โž› conversion to base base. Default is 10.

(symbol->string [symbol | string]) โž› string from symbol name. Returns string if argument is a string.


(string->unicode string) โž› explodes string into list of unicode characters values

(unicode->string char-code) โž› unicode character = 1-character string

(unicode->string char-code-list) โž› concatenates char codes into a string

char-code may be decimal: 1028, hexadecimal:0x404, unicode:#\u0404


(string-pad-right object length) โž› new string of length length, right padded with spaces

(string-pad-left object length) โž› new string of length length, left padded with spaces


(string-diacritics string) โž› new string, replacing diacritics - รฉ,รจ,รด, .. - with non-accented characters.

(string-trim string) โž› new string with left, right spaces suppressed.

(string-trim-left string) โž› new string with left spaces suppressed.

(string-trim-right string) โž› new string with right spaces suppressed.


(string->html string) โž› new string, replacing all white spaces with html non-breaking spaces (&nbsp;)

Strings compare

(string=? str1 str2) โž› #t or #f

(string>=? str1 str2) โž› #t or #f

(string<=? str1 str2) โž› #t or #f

(string>? str1 str2) โž› #t or #f

(string<? str1 str2) โž› #t or #f


(string-ci=? str1 str2) โž› #t or #f ;; -ci : ignore case

(string-ci>=? str1 str2) โž› #t or #f

(string-ci<=? str1 str2) โž› #t or #f

(string-ci>? str1 str2) โž› #t or #f

(string-ci<? str1 str2) โž› #t or #f

(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

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.

(make-regexp pattern-string) โž› new regexp object


(string-replace str regexp replacement-string) โž› regular expression replace. regexp may use parenthesized substrings, and replacement-string may use the $i notation to denote the parenthesized substring matches.

(string-replace str regexp replacement-string mod) โž› use modifiers "i":ignore case, "g":global, ...


(string-match str regexp ) regular expression match โž› #t or #f

(string-match str regexp mod) modifier "i":ignore case โž› #t or #f


(string-split str [splitter] ) โž› list of substrings, splitted according to the regexp splitter separator. The default splitter is " ".


(regexp-match regexp str) โž› list of substrings matching regexp inside str, or empty list. If the regexp is a string, or does not use the "g" option, only the first matching occurence is returned.

(regexp-match* regexp str) โž› list of substrings matching regexp expressions inside regexp, or empty list. regexp-match* forces the "g" option = multiple occurences search option.

(regexp-exec regexp str) โž› list of substrings matching the parenthesized expressions inside regexp, or empty list

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

Date & Time

(current-time) -> seconds since 1/1/1970

(current-time-milliseconds )-> milliseconds


(date? object) -> is object a date ? #t or #f

(date year month day hour minute seconds milliseconds) -> new date object

Milliseconds, seconds, hour, .. are optional, in that order. Month must be in[1-12], day in [1-7], hour in [0-23].

(date [multiplier] unit-name) -> new date object = now + multiplier*unit

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].

(string->date date-string) -> new date

string->date accepte les formats yyyy-mm-dd et jj/mm/aaaa: (string->date "2016-11-13"), (string->date "13/11/1946") , (string->date "1/5/2015T14:48:00")


(seconds->date sec) -> new date since 1/1/1970

(currrent-date) -> new date : now


(date-diff date_1 date_2) -> difference in seconds

(date-add! date seconds) -> add seconds to the date object


(date->seconds date) -> seconds since 1/1/1970

(date->string date) -> localized date+time string

(date->date-string date) -> localized date string

(date->time-string date) -> localized time string

(date-format date language options-values-list) -> formatted date string



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"

Control - special forms -

(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

Looping and iterating

(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. exprn is the last expression in body.

(while cond expr1 โ€ฆ exprn) โž› loops evaluating expri until cond is #f or null - returns #f


(for ((v1 range1)(v2 range2) โ€ฆ) expr1 โ€ฆ exprn) โž› parallel loops. Returns last exprn unless a #:break => ret-value is encountered.

Range and sequence expressions

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 ((i end) โ€ฆ) body ) โž› i in range [0 โ€ฆ end[

(for ((j (in-range start end)) โ€ฆ) body) โž› j in [start โ€ฆ end[

(for ((k (in-range start end incr)) โ€ฆ) body) โž› k in [start โ€ฆ end[ by steps incr


(for ((i list) โ€ฆ) body) โž› i values : elements of list.

(for ((j stream) โ€ฆ) body) โž› j values : consecutive values of stream. See predefined sequences and streams : in-naturals, in-primes, in-permutations, in-cycle, ..


(for ((j (in-producer proc [arg1 arg2 โ€ฆ])) โ€ฆ) body) โž› j values : consecutive values of calls to (proc [arg1 arg2 โ€ฆ]). The arguments - if any - are evaluated once, when initializing the for loop. proc may be a state based procedure, which returns a different value at each call. Iteration stops when proc returns #f, else use a #:break to stop the producer iterations, or parallel iterations.


(for ((sst string ) โ€ฆ) body) โž› sst values : consecutive substrings of length 1.

(for ((i vector ) โ€ฆ) body) โž› i values : vector[0], vector[1], ...

(for (((k . v) hash ) โ€ฆ) body) โž› k, v values : all pairs (key . value) of hash, in unspecified order. Requires hash.lib

(for ((rec table ) โ€ฆ) body) โž› rec values : successive rows -instances of structure - of table. Requires sql.lib

(for ((gen procrastinator ) โ€ฆ) body) โž› gen values : successive calls of (next procrastinator). Requires sequences.lib. procrastinator is a sequence, iterator, combinator, generator, ..

Constructing values

(for/fold (acc init) ((i โ€ฆ) โ€ฆ) body) โž› returns acc - which is set to exprn at the end of each iteration

(for/sum ((i โ€ฆ) โ€ฆ) body) โž› returns sum of exprn

(for/product ((i โ€ฆ) โ€ฆ) body) โž› returns product of exprn

(for/list ((i โ€ฆ) โ€ฆ) body) โž› returns list of exprn

(for/vector ((i โ€ฆ) โ€ฆ) body) โž› returns vector of exprn

(for/string ((i โ€ฆ) โ€ฆ) body) โž› returns string concatenation of exprn


(for/and ((i โ€ฆ) โ€ฆ) body) โž› stops as soon as exprn is #f and returns #f. Else returns #t.

(for/or ((i โ€ฆ) โ€ฆ) body) โž› stops as soon as exprn is not #f and returns exprn. Else returns #f.


(for/max ((i โ€ฆ) โ€ฆ) body) โž› returns max of exprn.

Nested loops

(for* ((a range1)(b range2) โ€ฆ) body) โž› nested loops. Iterates over a, b, .. in order a1 b1 b2 .. a2 b1 .. Inner loops are reinitialized at each outer loop iteration. A #:break stops the whole for* iterations. Returns void, unless a #:break => ret-value is encountered.


(for*/fold (acc init) ((i โ€ฆ) โ€ฆ) body)

(for*/sum ((i โ€ฆ) โ€ฆ) body)

(for*/product ((j โ€ฆ) โ€ฆ) body)

(for*/list ((i โ€ฆ) โ€ฆ) body)

(for*/vector ((k โ€ฆ) โ€ฆ) body)

(for*/string ((i โ€ฆ) โ€ฆ) body)

(for*/and ((i โ€ฆ) โ€ฆ) body)

(for*/or ((i โ€ฆ) โ€ฆ) body)

(for*/max ((i โ€ฆ) โ€ฆ) body)

(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

(do ((variable1 init1 step1) โ€ฆ) (test final1 โ€ฆ) expr1 โ€ฆ)

Not very often used. See the Scheme report, expressions, 4.2.4.

amb operator - amb.lib

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.

amb-select

(amb-select predicate:1:1 (values1 values2 ...)) โ†’ first selection of choices (c1 c2 ...) among values lists, such as (predicate (c1 c2 ...) ) is #t.


(amb-select/random predicate:1:1 (values1 values2 ...)) โ†’ random selection of choices (c1 c2 ...) among values lists, such as (predicate (c1 c2 ...) ) is #t.

(amb-select/all predicate:1:1 (values1 values2 ...)) โ†’ list of all selections of choices (c1 c2 ...) among values lists, such as (predicate (c1 c2 ...) ) is #t.

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

amb functions

(amb-make-context ) โ†’ a new amb context to make the following functions work.

(amb context list-of-values) โ†’ next choice among list-of-values

(amb-fail) โ†’ will force amb calls to backtrack, and try new choices

(amb-require expr) โ†’ same as (unless expr (amb-fail))


(amb-run proc:1:n context [args ...]) proc is a one or more argument(s) procedure - (proc context args ...) - , which includes calls to amb and amb-fail/amb-require. Amb-run will try all possible choices until no failure is raised. Returns โ†’ (proc context [args ..]) if success, else #f.


(amb-choices context) โ†’ list of current choices

(amb-vector context) โ†’ vector of current choices. Same as (list->vector (amb-choices context)), but quicker.


(distinct? list) โ†’ #t if all elements of list are distincts - not eq? - . Else #f

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

Try, catch and throw

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

(throw error-id message) -> throws an user exception named error-id, with message message which can be any object.


(try try-body (catch (id message) catch-body)) ->
Evaluates try-body in sequence. If any user exception is thrown, calls the catch procedure with parameters error-id and message , executes its catch-body and return its value.
According to the received error-id, the catch procedure may decide to return something, or to leave, and return to top-level, by calling (error ...) .

See or load calc.glisp for use of (catch) and (throw)

Stacks

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.

(stack stack-id) new empty stack โž› stack-id

(stack-empty? stack-id) โž› #t or #f

(stack-length stack-id) โž› # of items


(push stack-id value) push value โž› value

(stack-top stack-id) โž› value, or #f if stack is empty

(pop stack-id) โž› pop value, or #f if stack is empty


(stack->list stack-id) โž› stack contents, as a list

(list->stack list stack-id) โž› new stack from list

(stack-swap stack-id) โž› swaps stack[top] & stack[top-1]

(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

Boxes are 1-dimension object, which serve as containers for a value, and allow to pass objects by reference.

(box value) โž› a new box, container for value

(set-box! a-box value) โž› -> set box contents

(unbox a-box) โž› get contents

(box? a-box) โž› is a-box a box ? #t or #f

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

Promises - (delay โ€ฆ) & (force โ€ฆ)

Delay and force implement lazy evaluation by means of promises objects.

(delay expression) โž› a promise to eval expression

(force promise) โž› force and cache evaluation

(promise? promise) โž› is promise a promise? #t or #f

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

Streams

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.


(stream? object) is object a stream? โž› #t or #f

(stream-empty? object) is object the empty-stream ? #t or #f

(stream-cons first-value rest-stream) โž› new stream ( first . rest-stream)

(stream-cons first-value rest-proc) โž› new stream (first . (delay rest-proc))

(stream-cons first-value empty-stream) โž› new stream ( first-value . empty)


(make-stream state-proc initial-state) โž› a new stream, formed by calling state-proc successively. Each call is (state-proc state), it should return a pair, the first item (car) being the value for the stream, and the rest (cdr) being the new state for the next call. For the first call, state is the given initial-state. At the end of the stream, proc should return some non-pair object. [Ref]


(stream-first stream) โž› first-value

(stream-rest stream) โž› empty-stream or new stream = (force rest-value)


(stream-add stream_1 stream_2) โž› new stream, sum of stream_i

(stream-mul stream_1 stream_2) โž› new stream, product of stream_i

(stream-map proc:2 stream_1 stream_2) โž› new stream, delivering (proc stream_1 stream_2)

(stream-filter fiter-proc:1 stream) โž› new stream, delivering elements of stream filtered by (filter-proc elem) = #t


(stream-ref stream n) โž› nth value of stream (forces eval of values 0 ... n)

(stream->list stream ) โž› list of values - โœ‹ careful if infinite stream !

(stream->list stream limit ) โž› list of n first values, n = min(limit, stream-length)

(take stream limit ) โž› same as (stream->list stream limit)


(stream-iterate stream) โž› destructive operation, delivering (stream-first stream) at each successive call, and replacing stream by (stream-rest stream), until the stream is empty.


Built-in streams & iterations

See for constructs, for usage of sequences/streams as iterators.

(in-cycle list) โž› infinite list delivering again and again the contents of list


(in-naturals [start]) โž› stream delivering 0,1,... โˆž or start,start+1,... โˆž

(in-range end) โž› stream delivering 0,1,... end-1

(in-range start end) โž› stream delivering start, start+1,..,end-1

(in-range start end step) โž› stream delivering start,...,end-1 by increments of step. Start,end,step do not need to be integers.

(in-range+ start [end [step]]) โž› stream delivering start .. end . Same as in-range, but end value is included in sequence

(in-permutations n) โž› stream delivering the n! permutations of the list (0 ... n-1). Requires the 'list' library : (load 'list).

(in-primes n) โž› infinite stream delivering successive primes from n. Requires the 'math' library : (load 'math).
;; 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)

Property lists

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.

(plist-keys symb) โž› sorted list of keys in hash table

(putprop symb value key) โž› adds or replace value for key

(getprop symb key) โž› value or #f

(get symb key) โž› same as getprop

(remprop symb key) removes property 'key'. โž› #t if found

(symbol-plist symb) โž› gets the whole plist

(set-plist! symb ((key1 value1)(key2 value2) ..)) โž› sets the whole plist

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

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.

(make-hash ) โž› new hash

(hash? obj) is obj a hash ? โž› #t or #f

(hash-clear! hash) โž› clears all (key . value) in hash

(hash-count hash) โž› # of keys in hash

(hash-set hash key value) sets or replaces (key . value) in hash โž› value

(hash-ref hash key) โž› value for key, or #f


๐Ÿ‘€ (hash-ref! hash key set-expr)) โž› returns value for key, or, if not found, sets value to (eval set-expr) - Note that set-expr is not evaluated if value is found, and may be a constant, like #f ,"NOT YET DEFINED" , ...

๐Ÿ‘€ (hash-ref! hash key set-proc:1:n)) โž› returns value for key, or, if not found, sets value to (set-proc key) - Note that set-proc is not evaluated if value is found. If key is a list (key1 key2 ...) (set-proc key1 key2 ...) is evaluated.


(hash-get-key hash value) โž› one key for value, or #f. Note: values are compared with equal?. This search by value is linear: โ„ฆ(n)

(hash-get-keys hash value) โž› list of all keys for value, or null.


(hash-remove! hash key) removes (key . value) from hash. โž› hash

(hash-map hash proc:2:2) call (proc key value) for all (key . value) in hash โž› list of all results

(hash-for-each hash proc:2:2) call for side-effect (proc key value) for all (key . value). โž› void

(hash->list hash) โž› new list, hash converted to a list of (key . value), in unspecified order.

(list->hash list hash) add/replace all (key . value) of list into hash. โž› hash


(hash-keys hash) โž› list of all keys, in unspecified order.

(hash-values hash) โž› list of all values, in unspecified order.


(hash-make-index hash) -> caches an internal index of hash (key . value) pairs. Returns hash.count = (hash-count hash)

(hash-index-key hash) -> key for index index in [0...hash.count]

(hash-index-value hash) -> value for index index in [0...hash.count]


(hash object) โž› an integer in [0..232-1]. Note. (unhash integer) โž› object is not yet implemented
(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 - SQL.LIB

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.

(make-table struct) โž› new table, from struct as returned by (struct name (field-name ...))

(table? object) is object a table ? โž› #t or #f

(table-count table) โž› number of rows in table

(table->list table) โž› contents of table in list form : (row0 row1 ..), where rowi is (field0 field1 ...) .

(list->table list table) โž› appends the contents of list to table ; list is a list of rows, in list format. Missing ending fields in a row are filled with #f.


(table-print table [nfrom [nto]]) tabular printing of rowsnfrom (default 0) to rownto (default table-count)โž› void

(table->html table ) โž› html source string : "<table> <tr> ..</table>" filled with table contents.


(table-insert table struct) โž› inserts a new row, rown, the contents of which is given by an instance of structure, and returns n. Insertion is made by reference, struct and rown share the same data.

(table-insert table list-of-values) inserts a new row, rown, the contents of which is given by list-of-values, and returns n.


(table-ref table row-index) โž› a structure instance = table[row-index] or #f. row-index in [0.. table-count[

(table-xref table row-index col-index) โž› a value = table[row-index][col-index] or #f. col-index in [0 ... # of columns[

(table-set! table row-index struct) replaces - by reference - table[row-index] by struct โž› struct

(table-xset! table row-index col-index value) replaces table[row-index][col-index] by value โž› value


(table-sort table sort-proc:2:2) โž› sorts table according to sort-proc. sort-proc compares two instances of structures, a and b, and returns a number < 0 (a lesser than b), 0 (equal), or > 0 (a greater than b).


(table-make-index table field-name) โž› indexes table on field-name

Example in Rosetta code

Select

	(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

Association lists

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.

(alist? object) โž› is object an association list? โž› #t or #f

(assoc key alist) โž› (keyi valuei) with (equal? key keyi), or #f

(assq key alist) โž› (keyi valuei) with (eq? key keyi), or #f

(assv key alist) โž› (keyi valuei) with (eqv? key keyi), or #f

(association-procedure predicate selector) โž› a custom look-up procedure using selector to extract keys, and predicate to compare keys.

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

Styles

CSS styles may be applied to classes of objects (error, string, ..) or particular symbols. Use the function style to specify a style.

(style) โž› all styles list, in (key-string value-string) format.

(style class-id) โž› style for this class or #f

(style object) โž› style for this object or #f

(style class-id css-style) โž› set style for all objects of class

(style object css-style) โž› set style for this object

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

"All warnings are orange, except a few errors" (Ludwig Wittgenstein)

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.

(error message-string object) โž› generates an error.

(+ 8 9))))
	๐Ÿ˜ warning: reader : too many right parenthesis: ')'
	โ†’ 17
	
(for ((i 99999999)) (if (= i 666) (error "bad number:" i)))
	๐Ÿ’ฌ error: bad number: 666 

Debugging

(trace function-id) -> argument values, [stack depth] and return value for f

(untrace function-id)


(assert expression) โž› error if expression evals to #f

(assert expression message-string)

(check-expect expression value) โž› warning if (not (equal? expression value))


(time expression) โž› time (msec) to eval expression


(debug option) โž› sets debug option (0 is default = none). The debug options - which may be ORed - are:
1 = print compilation output
2 = print syntax expansion output.


(js-eval javascript-expression-string) evaluates js expression โž› number or string


(console-log message object) โž› message and lisp representation of object to javascript debugger console

(console-dir object) โž› javascript representation of object to debugger console

(console-trace message object) โž› functions calls history trace to javascript console

(jsonify object) โž› string : object translated to JSON.

(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

Popup boxes

(alert alert-string) shows alert popup box โž› void

(confirm confirm-string) shows confirm popup box โž› #t (OK button) or #f (Cancel button)

Read operations

Read input from stdin

(input-expr proc:1 prompt-string) โ†’ (void). Sets the prompt to prompt-string, prepare to parse the next user input line as an expression, and to return (eval (proc expr)). Beware that this is an asynchronous operation. proc is the associated callback procedure.


(input-string proc:1 prompt-string) โ†’ (void). Sets the prompt to prompt-string, prepare to read the next user input line as a string, and to return (eval (proc string)).

(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

(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), (read-string) (read-number) and (read-list) use the browser prompt mechanism. They return #f if the user cancels the operation.

(read) โž› expression = number, symbol, list etc.

(read default-value)

(read default-value prompt-string) prompts with prompt-string dialog title, and default value


(read-string [default-value-string [ prompt-string]]) โž› returns a string

(read-number [default-value-number [ prompt-string]]) โž› returns a number

(read-list [default-value-string [ prompt-string]]) parses user input : space or "," separators - no "(" , no ")" needed - โž› returns a list

(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

Write operations

The write/display operations write to stdout. They all return (void).

(decimals ) โž› get number of shown decimals ( 0 = default = all)

(decimals n) โž› set number of shown decimals

(write object1 ..objecti ..) โž› to stdout, on same line

(writeln object1 ..objecti ..) โž› to stdout, on next line

(newline) โž› flushes stdout and starts a new line

(display object) โž› display format : unquoted strings, etc.

(display object css-style-string) โž› styled display

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

Formatted print - printf

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:

%[width][.precision]specifier or ~[width][.precision]specifier

The specifiers are the following :


(format format-string val1 val2 ... valn) โž› formatted string

(printf format-string val1 val2 ... valn) prints formatted string and returns void

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

(html-print html-string) Clears the stdout area, and replaces its contents - innerHTML - with html-string โž› void

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

Pretty printing

Requires the print library. Remember that also exist array-print and table-print in matrix.lib and sql.lib.

(pretty-print expression [max-line-length]) Evaluates expression and pretty prints the result โž› void. Default max-line-length is 140. All sub-expressions which fit on a line are not indented.

(pp expression) Synonym for pretty-print

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

Input/output

stdin - Input from keyboard

(autocomplete-delay 0) โž› cancel autocomplete

(autocomplete-delay msec) โž› set delay - default = 40

stdin - Meta keys

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

(define-modifier-key ["alt"|"ctrl"|"cmd"|null]) โž› sets the modifier to use; null if no meta keys (this is the default).

(meta-key [1-letter-string|1-digit-string] [replace-string|null]) โž› sets the mapping for letter or digit.

(meta-keys) โž› return the current mapping.
;; 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"

Customizing a cell input/output fields : stdin/stdout

(stdin-hide [#t|#f]) โ†’ hides/shows stdin

(stdin-background color-string) โž› set stdin background color

(stdin-color color-string) โž› set stdin text color

(stdin-font ) โž› get stdin text font (default "Verdana")

(stdin-font font-id-string) โž› set stdin text font

(stdin-font-size ) โž› get stdin text size in px units (default around "12px")

(stdin-font-size size-number) โž› set stdin text size in px units. Numeric value, without "px".


(stdout-hide [#t|#f]) โ†’ hides/shows stdout

(stdout-clear ) โž› clears stdout and returns (void)

(stdout-background color-string) โž› set stdout background color

(stdout-color color-string) โž› set stdout text color

(stdout-font ) โž› get stdout text font (default "Verdana")

(stdout-font font-id-string) โž› set stdout text font

(stdout-font-size ) โž› get stdout text size in px units (default around "12px")

(stdout-font-size size-number) โž› set stdout text size in px units

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

Local files and server files access

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 ) โž› read and eval local file selected using the browser file dialog. Same as click on the  Load  button.

(load filename) โž› read and eval file ./lib/filename.glisp located on server.
(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.

File to string

Converts a local file or URL to a string. The file contents is displayed in a new cell.

(file->string success-proc) โž› read as text a local file selected using the browser file dialog, and calls (success-proc file-name text).

(file->string success-proc file-name) โž› read as text a file located on server, and calls (success-proc file-name text).
(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")

Saving on disk

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.

(save-as object filename) โž› #t or #f

๐Ÿ“— Local storage - Local database

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-verbose [#t|#f]) -> messages on|off

(local-stores [filter]) -> list of names of local stores, possibly filtered by the filter string

(local-make-store store) -> new store store

(local-delete-store! store) -> delete store and contents and keys

(local-keys [store]) -> list of all keys in store. 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"

Local stores - Symbols value access

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.

(local-symbol? [store.]symbol) -> is symbol symbol stored in store-id ? #t or #f

(local-put [store.]symbol) -> saves - replaces - symbol binding into store.

(local-add [store.]symbol) -> saves symbol binding into store. Error if symbol already known.

(local-get [store.]symbol) -> retrieves and returns value - null if none found - and bind it to symbol.

;; 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 - (key value) access

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.

(local-add-value key value [store]) -> adds new (key value) in store. Error if key already exitsts. Returns key (user or auto-incremented)

(local-put-value key value [store]) -> adds/replaces (key value) in store. Returns key (user or auto-incremented)

(local-get-value key [store]) ->retrieves value for key. Returns null if unknown key

(local-delete key store) -> deletes (key value) from store. No default value for store.

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

๐Ÿ“— Local storage - Definitions - Packages

The user defined preferences function is automatically evaluated at boot time, and automatically saved in the 'user' package.


(define (preferences) โ€ฆ) ;; user preferences function


(definitions) -> lists all functions definitions in memory, as strings

(undefine function-symb) -> reset definition

(edit function-symb) -> writes the definition to a new cell for editing


(save-package store) -> saves all symbols/functions definitions named store.name into store. Returns list of symbols or functions names. (*)

(load-package store) -> loads the whole store into memory; Returns list of symbols or function names. (*)

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

Lisp reader

(reader-set-prompt! [symbol|string]) โ†’ sets a new prompt text for the input field.

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.

(reader-set-proc! reader-procedure prompt-string) โ†’ installs a new reader procedure, with prompt-string as placeholder

(reader-rem-proc) โ†’ reverts to the last reader procedure - standard reader if none -

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 old-string new-string) โ†’ old string - which may be a regular expression - is replaced by new-string everywhere in the input stream

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

(reader-dict-new key-value-list) โ†’ new reader dictionary from list of (key value)

(reader-dict-set! key value) โ†’ adds an entry to the dictionary

(reader-dict-set! key #f) โ†’ removes entry from the dictionary

(reader-dict) โ†’ current reader dictionnary

(load-reader-dict dict-id) โ†’ load from local storage

(save-reader-dict dict-id) โ†’ saves the dictionary into local storage

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

(text-parse text-string) โ†’ list of strings. The separators are included in the list, as 1-character strings.

(text-parse text-string separators) โ†’ list of strings

(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!!.")

Quoting

โ€œBackquoteโ€ or โ€œquasiquoteโ€ expressions are useful for constructing a list structure when most but not all of the desired structure is known in advance.

(quote object) -> object

(quasiquote template) -> template, with unquote/unquote-splicing evaluated. Other items are "quoted" : unchanged.

(unquote object) -> evaluates inside a template

(unquote-splicing object) -> object must evaluates to a list. The list contents are inserted - ( and ) "stripped" away- inside the template.

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

macro-characters

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

Syntax rules

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.

(define-syntax-rule pattern template) โ†’ Transforms pattern according to template if a match is found..


(define-syntax function-id (syntax-rules keywords-list clause1 ... clausen)) โ†’
If a match is found between a call (function-id args ..) with a clause (patterni templatei), transforms the call according to templatei. Else raises an error.

;; 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-id rules

Syntax rules allow to transform lists into lists. Syntax-id rules allow to transform identifiers - symbols - into lists.

(syntax-ids) โ†’ list of all known sysntax-id identifiers.


(define-syntax-id id expr) The symbol id is replaced by expr. (define-syntax-id id null) to remove a definition

Dot notation : pattern matching and replacement occur when the pattern id is _.suffix or prefix._

(define-syntax-id _.suffix expr) Matches any symbol with id = some-prefix.suffix . The placeholder _ will be replaced by the symbol prefix inside the template.

(define-syntax-id prefix._ expr) Matches any symbol with id = prefix.some-suffix . The placeholder _ will be replaced by the symbol suffix inside the template.

(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

Libraries

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.

(lib library) โ†’ loads library from server

(require library|(library0 ...)) takes a name or a list of names in input; โ†’ raises an error if library not loaded

(lib-functions library) โ†’ all functions in library

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

Struct.lib - Structures

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.

(lib 'struct.lib) โž› loads the struct library


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--! procedure and has the following signature :

โœ’๏ธ (define (change-proc instance old-value tentative-new-value) body)

(struct <struct> [super] (field-desc โ€ฆ) [options ...]) Defines a new structure with name '<struct>'. Binds the descriptor symbol struct:<struct> to this structure, and generates the following creation and access functions :


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

(struct <struct> super-struct (field-desc0 โ€ฆ field-descn-1)) โž› new structure <struct> which inherits of super-struct fields. If super-struct has m fields, generates a structure with m + n fields.


(struct <struct> (field-name โ€ฆ.) #:initialize init-proc:1)

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 :

โœ’๏ธ (define (init-proc <struct>:instance) body)



(struct <struct> (field-name โ€ฆ.) #:tostring string-proc)

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:

โœ’๏ธ (define (string-proc <struct>:instance) body)

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

(copy instance) โž› new deep copy of instance
;; See polymorphic copy

Structures - Types - Methods

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

Structures - Low level procedures

A struct declaration generates the constant keywords #:<struct>.<slot-name> which are bound to the corresponding slots numbers.

(struct-get instance slot-number) โž› value for slot slot-number of structure instance instance. No validity checks performed for arguments. Slots are numbered 0,1, ...


(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

Matching - Match.lib

(match expr clause clause .. [(else body)]) โ†’ error if no match and no else clause, else returns the value of the first matching clause, or the value of the else body.


(check-match expr pattern [proc:1] ) โ†’ #t if matching is successful. Else if proc is present, returns (proc expr). Else raises an error.

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 :

matcher :=

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

Reader macros replace patterns by templates - using the match mechanism : variable replacement, etc. - inside an input expression, before any evaluation.

(define-macro name pattern template) -> new reader macro

(define-macro name null) -> delete macro name

(macro? name) -> #f or macro contents

(reader-macros ) -> list of installed macros

(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 EchoLisp - infix.lib

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    
  

Infix EchoLisp - Top level

(use-infix #t) -> switch to top-level infix mode

use-infix (#f) -> quit top-level infix mode

(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.lib - Classes, Generics, Methods, Instances

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.lib - Plotting and Drawing

(lib 'plot.lib) โž› loads the plot library.

(plot-on) or ๐Ÿ“Š button โž› shows the drawing area - canvas - ant its controls.

(plot-off) or ๐Ÿ“Š button โž› hides the drawing area

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

(plot-size [pixels])โž› gets/sets the drawing area to a (size x size) bit-map. Default is 410x410 pixels

(plot-init) โž› reset ALL plot parameters

(plot-undo) โž› undo last drawing : curve, grid, text, โ€ฆ

(plot-clear) โž› clears area and resets the undo stack

Drawing parameters

(plot-color color) โž› sets the drawing color

(plot-background color) โž› sets the background color

(plot-fill-color color) โž› sets the fill color

(plot-line-width n) โž› sets the line width (default 2)


(make-gradient x0 y0 x1 y1) โž› new linear gradient from P0 to P1

(make-circular-gradient x0 y0 r0 x1 y1 r1) โž› new circular gradient from circle (P0, r0) to circle (P1, r1). ri in pixels unit.

(gradient-add-stop gradient x color) โž› adds stop color to gradient. Sets plot fill color to gradient.


(plot-minmax ) โž› gets current ((xmin xmax) (ymin ymax))

(plot-x-minmax range) โž› sets xmin and xmax for the grid (default: auto, initial values (-1,1))

(plot-y-minmax range) โž› sets ymin and ymax for the grid (default: auto, initial values (-1,1))

(plot-x-minmax 'auto) โž› sets automatic (computed) value for xmin, xmax

(plot-y-minmax 'auto) โž› sets automatic (computed) value for ymin, ymax

Drawing objects

(plot-edit) โž› to be used after a sequence of drawings, to take a snapshot and enable the plot controls.


(plot-segment x0 y0 x1 y1) โž› draws line segment from P0 to P1, with current plot-color and plot-line-width.

(plot-rect x0 y0 x1 y1) โž› draws and fills rectangle, corners (P0, P1)


(plot-circle x0 y0 R) โž› draws and fills circle, center at P0, radius R - R in pixels units -

(plot-arc x0 y0 R α β [#t|#f]) โž› draws and strokes arc, center at P0, radius R - R in pixels units - , from angle α to β. Counter-clockwise if #t (default), clockwise if #f.


(plot-square x0 y0 W) โž› draws and fills square centered at P0, width W - W in pixels units

(plot-axis [x0 [y0 [color]]]) โž› draw two axis at point (x0,y0) - Defaults : x0 = 0 ,y0 = x0.

(plot-grid [x-unit [y-unit [color]]]) โž› draws grid by steps of x-unit, y-unit. Defaults : 10 steps subdivision.

(plot-font font) โž› font for text to draw. Default: "16px verdana"

(plot-text string x0 y0 [color]) โž› draws text "string" at (x0,y0)

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


๐Ÿ“ˆ Curves plotting procedures

(plot-steps steps) โž› number of sampling steps. Default 500

(plot fx x-range) โž› plots fx , x in x-range

(plot-xy fxy x-range y-range) โž› plots fxy , x in x-range, y in y-range

(plot-sequence fn n-range) โž› plots sequence fn(i), i in n-range

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

Parametric curves

(plot-param fxu fyu u-range) โž› plot paremetric curve x= fxu(u), y=fyu(u), u in u-range.

(plot-polar rhou thetau u-range) โž› plot polar curve rho = rhou(u), theta = thetau(u), u in u-range.

(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

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-animate seconds) โž› re-plots, varying t in [0โ€ฆ1].

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

Complex functions

Domain coloring of complex values is performed using the plot-z functions.

(plot-z-arg f_z x-range y-range) โž› complex values. hue = function (arg), light = function (modulus)

(plot-z-mod f_z x-range y-range) โž› complex values. hue = function (modulus), light = function (arg)

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

Interpolation functions

(fminmax fx x-range) โ†’ (min-of-fx max-of-fx) approximative values

(linear x xmin xmax ) โ†’ (x-xmin)/(xmax-xmin) : mapping [xmin xmax] to [0 1]

(linear x xmin xmax ymin ymax) โ†’ ymin + (x-xmin)*(ymax-ymin)/(xmax-xmin) : mapping [xmin xmax] to [ymin ymax]

(smoothstep x) โ†’ -2x3 + x2 smooth interpolation between 0 and 1

(s-curve x gamma) โ†’ xγ interpolation between 0 and 1. Slope = function of gamma parameter.

(plot smoothstep '(0 1))
(plot-axis 0.5 0.5)
(plot (lambda(x) (s-curve x 3)) '(0 1))

(fminmax sin -PI)  โ†’   (-1 1)

Pixels

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

(gray g) โž› rgb-gray-color from 0=black to 1=white

(rgb r g b) โž› rgb-color

(rgb->list rgb-color) โž› list (r g b a) , integers in [0..255]

(rgba r g b a) โž› rgb-color with transparency a (1 = opaque)

(hsv->rgb h s v) โž› converts (h s v) color to (r g b) color

(hsva->rgb h s v a) โž› converts (h s v a) color to (r g b a) color

(plot-rgb rgb-funxy x-range y-range)

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

Integer functions. Mapping N to N*N

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.

(plot-spiral rgb-funn n-range) -> plots rgb-fun(n) onto a spiral

(plot-hilbert rgb-funn n-range) -> plots rgb-fun(n) onto an Hilbert curve

;;  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 - Time series

"Time series are also data series" - Simon Gallubert in 'Temps, espace et fantaisie' -

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] .

(data-serie [list|vector]) -> sorts, and converts to canonical form

(time-serie [list|vector]) -> sorts, checks dates, and converts to canonical form

(data-serie-get x-value) -> y-value at x. Performs linear interpolation between xi, xi+1 or di,di+1


(data-serie-x serie i) -> x-value of n-th point. Same as (car (vector-ref serie n))

(data-serie-y serie i) -> y-value of n-th point. Same as (cdr (vector-ref serie n))


(plot-dots data-serie string) -> Draws the text "string" , centered at each (xi,yi) point.

(plot-time-serie time-serie [ interval [ date-range]]) -> draws the curve xi = f(di)
Sampling is given by interval in seconds - default 1 DAY = 3600*24; default date range is [d0 dn]

(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) "๐Ÿ“Œ")
...

Canvas, bit-maps and typed vectors

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.

(plot-clear) โ†’ clears the canvas - all bytes set to 0.

(plot-size ) โ†’ (width . height) , canvas dimensions in pixel units.

(plot-size width height) โ†’ (width . height) , sets canvas dimensions in pixel units.


(pixels->uint8-clamped-vector) โ†’ new bit-map = (big) vector of length width*height*4, image of canvas contents. Each 8-bits element is a rgba componet, in order r, g, b, a, clamped to [0..255]


(pixels->[u]int32-vector) โ†’ new bit-map = (big) vector of length width*height, image of the canvas contents. Each 32-bits element is an unsigned/signed rgba color.


(pixels-ref bit-map x y) โ†’ rgba color at x + y*width

(pixels-set! bit-map x y rgba-color) โ†’ sets pixel at x + y*width

(pixels-map proc:2:2 bit-map) โ†’ sets bit-map[i] to (proc x y), i = x + width*y, x in [0...width[, y in [0...height[.


(make-region in-region:3:3 bit-map x0 y0) โ†’ recursively colors orthogonal adjacent pixels with color at (x0,y0), starting from pixel (x0,y0). (in-region bit-map x y) is a predicate used to select pixels which belongs to the region.


(vector->pixels bit-map) draws bit-map contents onto the canvas. โ†’ number of bytes written

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

Plot-3d.lib - 3D plotting

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.

(lib 'three.lib) โž› loads the three.js library.

(lib 'plot-3d.lib) โž› loads the plot library.

(plot-3d-show) or ๐ŸŽฅ button โž› shows the drawing area - Web GL renderer - and its controls. Use the ๐ŸŽจ button to hide/show the controls.

(plot-3d-hide) or โšช๏ธ button โž› hides the drawing area


Buttons

3D scene parameters

(scene-3d-reset ) โž› Sets all parameters to their default values.

(scene-3d param1 value1 param2 value2 ...) โž› Sets scene parameters. Parami, valuei are not evaluated.
(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

3D drawing functions

All these functions return the bounding box used for drawing.

(plot-3d-box ) โž› ((xmin xmax) (ymin ymax) (zmin zmax))


(plot-3d fxy) โž› plots z = (fxy x y)

(plot-3d-xyz fxyz) โž› plots poins (fxyz x y z) = 0 - Implicit surface definition, using marching cubes.

(plot-3d-param fx fy fz) โž› plots point x = (fx u v), y = (fy u v), z = (fz u v). - Parametric surface definition.

(cplot-3d fcxy) โž› plots |cz| = |(fcxy x + iy)| - Complex surface definition. Points are colored according to θ = arg(cz), red if θ = 0 ( cz real).


(cplot-3d-blob (isolevel blob-definition blob-definition ...))

3D drawing decorations

Parameters/values

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 .

3D objects

The following are used to add objects to the surface being drawn : To Be Completed Later

3D advanced

Custom functions may be defined for surface coloring, or surface transformation. All these functions are inline functions

Math.lib

(number->list n) โž› list of decimal digits = explode

(list->number list) โž› implode list of digits|strings into number

Arithmetic

(mean values-sequence) โž› mean value of values-sequence which is a list, vector, sequence or finite procrastinator.

(sigma f:1 nfrom nto) โž› Σ (f n), n in [nfrom...nto]

(sigma-2 f:2 nfrom nto mfrom mto) โž› ΣΣ (f n m), n in [nfrom...nto], m in [mfrom .. mto]

(product f:1 nfrom nto) โž› Π (f n), n in [nfrom...nto]


(egcd m n) extented gcd โž› (g a b) such as a*m + b*n = g = gcd(a,b)

(crt-solve a-list m-list) chinese remainder theorem โž› x such as x = a[i] (mod m[i]). m[i] and m[j] must be co-primes.


(divides? a b) โž› #t if b exactly divides a, else #f.

(num-divisors n) โž› number of integer divisors (n excluded)

(sum-divisors n) โž› sum of integer divisors (n excluded)

(nth-prime n) โž› nth prime (small n)

(primes-pi n) โž› number of primes <= n

(in-primes n) โž› infinite stream delivering successive primes from n


(bernoulli n) โž› Bernoulli number[n]. B0=1, B1=1/2, Bodd=0, B2=1/6, ...
(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.

Continued fractions

A continued fraction is a list - finite or infinite - of coefficients (a0 a1 a2 ...) which compute the following :

In Lisp form :

(+ a0 (/ ( + a1 (/ ( + a2 (/ ( + a3 ...)))))

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 number [n]) -> converts number to a continued fraction. n (optional) is the maximum number of terms.


(contfract->number continued-fraction [n] ) -> value of continued-fraction, up to n terms. If no n, precision is 1e-12 .


(convergents continued-fraction [n]) -> list of n first convergents = rational numbers which approximate the continued fraction value. If no n, stops when precision < 1.e-10

(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

Polynomial

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

(poly->string var-id P) โž› string : a0 + a1x + a2 x^2 + โ€ฆ

(poly->string var-id P Q) โž› string : a0 + a1x + a2 x^2 + โ€ฆ / b0 + b1x + b2x^2 + โ€ฆ

(poly->html var-id P [Q] ) โž› string : a0 + a1x + a2 x2 + โ€ฆ


(poly x P) โž› value of real poly P(x) at x

(poly x P Q) โž› value of P(x) / Q(x) at x

(cpoly z Pz) โž› value of complex poly P(z) at z

(cpoly z Pz Qz) โž› value of P(z) / Q(z) at z


(poly-add P Q) -> new poly P + Q

(poly-sub P Q) -> new poly P - Q

(poly-mul P Q) -> new poly P * Q

(poly-mul-k P k) -> new poly k * P

(poly-pow P n) -> new poly Pn

(poly-div A B) -> new polys (Q R) such as A = B * Q + R , and R = 0 or dยฐ(R) < dยฐ(B).

(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

Analysis

(math-precision) โž› ε value

(math-precision value) โž› set ε value

(~= a b) โž› #t if |a - b| < ε , else #f

(root f xmin xmax) โž› x0 in [xminโ€ฆxmax], |f(x0)| < ε , or null if not found.

(roots f xmin xmax) โž› list of all roots, (xi) in [xminโ€ฆxmax], |f(xi)| < ε, or null if none.

(croot f zmin zmax) โž› z0 in rectangle [zminโ€ฆzmax], |f(z0)| < ε

(croots f zmin zmax) โž› list of all complex roots, zi in rectangle [zminโ€ฆzmax], |f(zi)| < ε

(integrate f xmin xmax) โž› โˆซ f(x) dx , x in [xminโ€ฆxmax]

(deriv f x0) โž› f'(x0)

(serie f x nmax) โž› Σ xn * f(n), n = [0..nmax]

(cserie f z nmax) โž› Σ zn * f(n), n = [0..nmax]

(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

Functions

(gamma z) โž› Gamma function value at z (real or complex) : Γ(z)

(standard-normal x) โ†’ standard normal distribution at x. μ = 0, σ = 1.

(normal x μ σ) โ†’ normal distribution

(normal-2 x y ρ μ1 σ122]]) -> normal distribution of (x y). ρ in [-1 1] is the correlation coefficient. Default for μ2, σ2 are μ11.

(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

Fractals

(fractal z zc n) iterates n times z = z2 + zc. โ†’ zn or Infinity.

(fractal-p z zc p n) iterates n times z = zp + zc. โ†’ zn or Infinity.

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

 

Vector operations

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.

(dot-product vector-a vector-b) โž› Σ ai*bi.

(cross-product vector-za vector-zb) โž› new vector [a1*b2-a2*b1 a2*b0-a0*b2 a1*b0-a0*b1].


(cdot-product vector-za vector-zb) โž› Σ zai*zbi.

(cdot-product* vector-za vector-zb) โž› Σ zai*zbi.

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

๐Ÿ“ Distances in Rn

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.

(in-interval? x a b) Is x inside [a .. b] ? โž› #t or #f

(in-open-interval? x a b) Is x inside ]a .. b[ ? โž› #t or #f


(pythagore a b) โž› (a*a + b*b)1/2

(distance xa ya xb yb) โž› ((xa-xb)2 + (ya-yb)2)1/2


(point-in-disk? x y disk) Is the point (x y) inside the disk disk ? โž› #t or #f. A disk is a vector #(x0 y0 R).

(disk-in-disk? D1 D2) Is the disk D1 inside the disk D2 ? โž› #t or #f. A disk is a vector #(x0 y0 R).

(rect-in-disk? rect disk) Is the rectangle rect inside the disk disk ? โž› #t or #f. A rectangle is a vector #(x0 y0 width height) where x0,y0 are the top-left corner coordinates.

(rect-disk-intersect? rect disk) Does the rectangle rect intersects the disk disk ? โž› #t or #f.


(norm-1 vector-a vector-b) โž› Σ | ai - bi| : taxicab distance.

(norm-2 vector-a vector-b) โž› (Σ (| ai - bi|)2) 1/2 : euclidean distance

(norm-p vector-a vector-b p ) โž› (Σ (| ai - bi|)p) 1/p

(norm-inf vector-a vector-b ) โž› Max (| ai - bi|) โž› limit of the above, for p โž› โˆž

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

2D-arrays and matrices - Matrix.lib

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


(make-array n p) โ†’ new array (n p) initialized to 0

(build-array n p proc:2:2) โ†’ new array (n p) such as aij = (proc i j)

(vectorโ†’array V n p) โ†’ new array (n p) filled - rows first - with successive elements of V

(list->array list n p) โ†’ new array (n p) filled - rows first - with successive elements of list

(array-copy A) โ†’ shallow copy of A


(array-ref A i j) โ†’ Aij

(A i j) โ†’ Aij Short-cut for fast access.


(array-set! A i j value) โ†’ Aij := value

(array-row A i) โ†’ row vectori

(array-col A j) โ†’ column vectorj

(array-set-row! A i vector[p]) โ†’ sets row vectori

(array-set-col! A j vector[n]) โ†’ sets column vectorj


(array-map proc:1:1 A) โ†’ new array B such as Bij = (proc Aij)


(array-print A) โ†’ prints A on stdout, in tabular format

(array->html A) โ†’ html source string : "<table class='matrix'> .... </table>" filled with array contents.

Matrices

(matrix-row-num M) โ†’ n = number of rows

(matrix-col-num M) โ†’ p = number of columns

(matrix-ref M i j) โ†’ Mij (synonym of array-ref)

(matrix-set! M i j value) โ†’ Mij := value (synonym of array-set!)


(matrix-transpose M ) โ†’ new matrix T (p n), Tji = Mij

(matrix-mult Mnp Npq) โ†’ new matrix Pnq = M * N

(matrix-add Mnp Nnp) โ†’ new matrix Pnp = M + N


(matrix-swap-rows! M i k) โ†’ swaps rows i & k inside M .


(matrix-solve Mnn Anh) โ†’ matrix Xnh such as M * X = A. Uses LU-decomposition.

(matrix-invert Mnn) โ†’ matrix M-1nn such as M * M-1 = Idnn.


(matrix-lu-decompose Mnn) โ†’ list of three matrices (Pnn Unn Lnn ) such as P * M = L * U, P is a permutation matrix, U and L are upper and lower matrices.

(determinant Mnn) โ†’ | M |

(lib 'matrix)
;; See Cramer's rule.

Bigint.lib

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

Sequences.lib : Procrastinators - Iterators - Generators - Sequences

Procrastinators

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

NB: the following functions apply to all sub-classes of procrastinators.

(procrastinator? obj) โ†’ #t if obj is a procrastinator, else #f

(procrastinator list|vector) โ†’ new procrastinator from list or vector

(dup procrastinator) โ†’ new procrastinator, duplicate of initialized procrastinator.

(init procrastinator) โ†’ re-initializes procrastinator


(next procrastinator) โ†’ next value or #f if no more values. Changes the procrastinator state.

(take procrastinator n) โ†’ list of n first values. For compatobility reasons (take object n) may be written as (take n object).

(take procrastinator #:all) โ†’ list of all values

(drop procrastinator n) โ†’ new procrastinator , duplicate of procrastinator , after dropping the n first values


(tail procrastinator) โ†’ new procrastinator - rest - , skipping the first value of procrastinator.


(nth procrastinator n) โ†’ nth value, or #f. Calls (next) n + 1 times

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.

(length procrastinator) โ†’ number of values to return before #f, or Infinity.


(append p1 p2) โ†’ new procrastinator, delivering the contents of p1, then the contents of p2

(filter proc:1:1 procrastinator) โ†’ new procrastinator from procrastinator, returning only values such as (proc value) = #t


(for-each proc:1:1 procrastinator) โ†’ calls (proc (next procrastinator)) until #f. Returns void.

(for-each proc:2:2 p1 p2) โ†’ calls (proc (next p1 ) (next p2 )) until p1 or p2 exhausted. returns void.


(map proc:1:1 procrastinator) โ†’ new procrastinator, returning (proc (next procrastinator)).

(map proc:2:2 p1 p2) โ†’ new procrastinator, returning (proc (next p1 ) (next p2 )) ... )


(foldl proc:2:2 acc procrastinator) fold left โ†’ sets acc to (proc (next procrastinator acc)) until exhausted. Returns acc.

(foldl proc:3:3 acc p1 p2) โ†’ sets acc to (proc (next p1) (next p2) acc) until p1 or p2 exhausted. Return acc.


(scanl proc:2:2 acc0 p1) scan left โ†’ new list or procrastinator accumulating intermediate results : (acc0, acc1 = (proc (next p1) acc0), ... accn = (proc (next p1) accn-1)).


(scanl proc:3:3 acc0 p1 p2) โ†’ new list or procrastinator accumulating intermediate results : (acc0, acc1 = (proc (next p1) (next p2) acc0), ... accn = (proc (next p1) (next p2) accn-1)).

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

(take/when pred:1:1 procrastinator n) โ†’ list of first values - at most n - such as (pred value) is #t

(take/while pred:1:1 procrastinator n) โ†’ list of first consecutive values - at most n - such as (pred value) is #t.

(drop/while pred:1:1 procrastinator n) โ†’ new procrastinator, after dropping at most n consecutive values such as (pred value) is #t.


(sum procrastinator [n]) โ†’ sum of n first values. Default for n is Infinity (all)

(sum/when pred:1:1 procrastinator [n]) โ†’ sum of first n values such as (pred value) = #t. Default for n is Infinity (all).


(min procrastinator ) โ†’ min of values.

(max procrastinator ) โ†’ max of values.

Lazy lists

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

(kons first rest-expression) โ†’ new lazy list. rest-expression is not (yet) evaluated.

(first : rest-expression) โ†’ same as above.
(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

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.

[start ..] โ†’ new sequence [start start+1 .. Infinity[

[start second ..] โ†’ new sequence [start start+step .. Infinity[ , with step = second - first.

[start .. last] โ†’ new sequence [start start+1 .. last[. Same as (sequence start last)

[start second .. last] โ†’ new sequence [start start+step .. last[ , with step = second - first. Same as (sequence start second last)

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

Strings sequences

[from-string .. to-string] โ†’ new string-sequence [from-string .. to-string]. Same as (sequence from-string to-string).

(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

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

(iterator/n f:1:1 n0) โ†’ new iterator returning f(n0), f(n0+1), f(n0+2) .... stops whenever f() returns #f


(iterator/f f:1:1 seed) โ†’ new iterator returning: seed, (f seed), (f(f seed)), (f(f(f seed))), ... stops whenever f() returns #f


(iterator->list iterator) โ†’ new list of all values returned by (next iterator). Same as (take iterator Infinity), but truncated if iterator is infinite.
(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.

Indices

Given a vector of integer dimensions #(d0 d1 d2 ..), returns all vector indices #(i0 i1 i2 ..) such as 0 <= ik < dk.

(indices dimensions-vector) โ†’ new procrastinator returning #(i0 i1 i2 ..).

(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

Combinators require the list library : (lib 'list).

(powerset list) โ†’ new combinator returning all subsets of list. 2(length list) subsets

(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

(combinator list k) โ†’ new combinator returning all combinations of k items among list elements

(combinator/rep list k) โ†’ new combinator returning all combinations - with repetitions - of k items among list elements. k may be > (length list)

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

Generators

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.

(make-generator gen-proc:1 init-state) โ†’ new generator, with procedure gen-proc and initial state init-state.

(next generator) โ†’ runs - in loop fashion - the generator procedure until next yield, and get next value from the generator.


(yield value) stops the generator execution, and returns control and value back to the caller, which is a (next) call.

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

Tasks

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

(make-task task-proc:1 init-state) -> new task, with procedure task-proc and initial state init-state. NB. The task is waiting to be run

(task-run task [msec]) -> run or restart a task with idle time msec or 1000 (default) .

(task-stop task) -> stops the task, as soon as task-proc returns.

(task-stop-all ) -> stops all running tasks. Same as CTRL-C key.


(state task) -> returns the task state.

(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    

Semaphores

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.

(make-semaphore init-count) -> new semaphore with count init-count


(semaphore-empty? semaphore) -> #t is the semaphore message queue is empty, else #f.

(semaphore-push semaphore message) -> push (FIFO style) message onto the semaphore queue.

(semaphore-pop semaphore) -> #f is the semaphore message queue is empty, else deletes first message from queue, and returns it.


(wait semaphore) -> decrements semaphore count. If < 0, sets the caller task waiting for semaphore.

(signal semaphore) -> increments semaphore count. Awakes one of the tasks waiting for semaphore , if any.


(sleep msec) -> sets the calling task sleeping during msec milli-seconds




Timer.lib

A sound is one of the symbols: ok, ko, tick, tack, woosh, beep, digit .

(play-sound sound-id) -> plays a sound


(at-every interval timer-proc-id) -> calls (timer-proc t), every interval milli-seconds ; t is the current time - milli-seconds ; stops when timer_proc returns #f or user presses CTRL-C ;

(wait duration timer-proc-id) -> calls (timer-proc), after duration milli-seconds


(at date alert-proc-id) -> calls once alert-proc when (current-date) > date

(at [multiplier] unit-name alert-proc-id) -> calls once alert-proc at (now + multiplier * unit). See date for units (day, jour, etc.).

๐Ÿ’พ 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"))

Web.lib

(mail address-string subject-string expr) -> send mail


(string->url string) โž› url encoding for string

(open-url url-string) โž› open page (or Tab)

(oeis list-of-integers) โž› look-up in the On-line Encyclopedia of Integer Sequences

(oeis string) โž› look for sequence or author name in the OEIS

(inverter a-number) โž› look-up in Simon Plouffe's inverter

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

GIMPS primes

JSON lib

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-import JSON-string) -> parses input JSON-string and returns a lisp object

(export-json lisp-obj) -> stringifies lisp-obj and returns a JSON string


;; 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 ๐ŸŽฉ)

jsObjects

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").

(json? object) is object a jsObject ? โ†’ #t or #f

(make-json key-value-list) โ†’ a new jsObject with same (key value) pairs as the input key-value-list

(string->json JSON-string) โ†’ unserialize to new jsObject

(json->string jsObject) โ†’ serialize to JSON string


(json->plist jsObject) โ†’ new key-value-list from jsObject deprecated

(json->hash jsObject) โ†’ new hash table from jsObject Requires hash.lib.

(json->struct jsObject ) โ†’ new instance from jsObject. The slots names must be a subset of the JSON keys found in jsObject


(json-keys jsObject) โ†’ list of all keys of jsObject

(json-types jsObject) โ†’ list of all keys/subkeys in jsObject, with associated type

(json-get jsObject key-string ) โ†’ value of key in jsObject

(json-put jsObject key-string value) โ†’ sets value of key in jsObject, or creates a new key if not existing.


(json->lisp jsObject) โ†’ conversion to lisp object

(lisp->json lisp-object) โ†’ conversion to jsObject

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

Indexed data base - idb.lib

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.

(db-verbose [#f|#t]) -> messages on operation completion. #f is default.

(db-name) -> name of current idb

(db-version ) -> version of current idb

(db-stores ) -> list of stores in current idb

(db-make-store name) -> new store

(db-delete-store! name) -> deletes store and contents

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

โœ’๏ธ (define (onsuccess result) body )
โœ’๏ธ (define (onerror error-reason) body )

IDB stores - Symbols value access

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.

(db-keys store onsuccess) โ†’ #t. Build list of all keys in store and calls (onsuccess keys-list)

(db-put [store.]symbol) โ†’ saves - replaces - symbol binding into store.

(db-get [store.]symbol [onsuccess [onerror]]) โ†’ retrieves value - null if none found - and bind it to symbol.

(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

IDB stores - (key value) access

(db-put-value [key|#:auto] value store [onsuccess [onerror]])
โ†’ stores/replaces a new value in store. The key is either key or auto-incremented. Calls (onsuccess key).


(db-add-value [key|#:auto] value store [onsuccess [onerror]])
โ†’ stores a new value in store. The key is either key or auto-incremented. Calls (onsuccess key) when operation is complete. Calls (onerror key) if key already exists.


(db-get-value key store onsuccess [onerror])
โ†’ gets value infrom store. Calls (onsuccess value) when operation is complete. Calls (onerror key) if key is not found.

(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    
  

(db-put-values imin imax [key-proc|#:auto] value-proc store [oncomplete [onerror]])
โ†’ Stores multiple values at once. (key-proc i) and (value-proc i) are the (key value) providers for i in [imin imax]. Uses auto-increment keys if key-proc = #:auto. Calls (oncomplete (keymin keymax)) at operation completion. May be used to populate the data base from a list or vector.


(db-get-range [keymin|...] [keymax|...] store onsuccess [onerror])
โ†’ retrieves all values for key interval [keymin ... keymax]. Calls (onsuccess list-of-values)


(db-select selector store onsuccess [onerror])
โ†’ Selects all values such as (selector key value) is not #f. Calls (onsuccess selected-values-list)

(db-select selector store onsuccess [onerror])
โ†’ Counts all records such as (selector key value) is not #f. Calls (onsuccess count)

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

(db-create name) โ†’ creates an idb, which becomes current

(db-open name) โ†’ opens idb, make it current

(db-close ) โ†’ closes the current idb

(db-delete-db! name) โ†’ deletes an idb and its contents

๐ŸŒด๐ŸŒฑ - Tree.lib

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.

(tree? object) is object a root node ? โ†’ #t or #f

(make-tree datum) โ†’ root node

(node-add-leaf node datum) add a leaf to node โ†’ new leaf node

(node-add-tree node tree) add tree as new son of node โ†’ tree

(tree-delete-node root node) โ†’ deletes node and all its sons

(tree-replace-node root node tree) โ†’ replaces node by the tree tree

(make-tree 'albert)
   โ†’  (๐ŸŒด albert) ;; root node with datum albert

(node-leaf? node) is node a leaf ? โ†’ #t or #f

(node-sons node) โ†’ ๐ŸŒด๐ŸŒฑ๐ŸŒด๐ŸŒฑ forest = list of all sons of node or null if is a leaf

(node-left node) โ†’ null or leftmost - first - son of node

(node-right node) โ†’ null or rightmost - last - son of node

(node-datum node) โ†’ datum at node

(node-set-datum node datum) โ†’ sets datum at node

See Knuth's power tree

(tree-ref root datum) โ†’ node such as (equal? node.datum datum) or null

(tree-fold proc:2 acc0 root) โ†’ computes acci+1 := proc(nodei.datum acci) for all nodes - returns acclast

(tree-for-each proc:1 root) โ†’ calls (proc node) for all tree nodes

(tree-count root) โ†’ pair : (# of nodes . tree-depth). The tree depth is the maximum path length from the root to a leaf node.



๐ŸŒฑ -Binary search trees

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.

(make-bin-tree key value) โ†’ root node with datum = (key . value)

(bin-tree-empty? root) โ†’ #t or #f

(bin-tree-insert root key value) adds a new node (key . value) at the right place โ†’ key or #f if (key . value) already here

(bin-tree-delete root key) deletes node located at key โ†’ #t if node found, else #f

(bin-tree-first root) โ†’ (key . value) for smallest key. โ†’ null if empty tree.

(bin-tree-last root) โ†’ (key . value) for greatest key. โ†’ null if empty tree.


(bin-tree-pop-first root) โ†’ (key . value) for smallest key, and delete it. โ†’ null if empty tree

(bin-tree-pop-last root) โ†’ (key . value) for greatest key, and delete it. โ†’ null if empty tree.


(tree-balance root) reorganizes the tree to minimize the tree-depth. โ†’ (# of nodes . tree-depth). O(n) time, but not in constant space.



queues

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.

(queue queue-id) new empty queue โž› queue-id

(queue-empty? queue-id) โž› #t or #f

(queue-length queue-id) โž› # of items


(enqueue queue-id value) enqueue last element โž› value

(q-push queue-id value) :: synonym for enqueue

(queue-top queue-id) โž› value = first element, or #f if queue is empty

(dequeue queue-id) โž› first element , or #f if queue is empty

(q-pop queue) :: synonym for dequeue


(queue->list queue-id) โž› queue contents, as a list

(list->queue list queue-id) โž› new queue from list

See Moving average

ๅจ Heaps - heap.lib

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

(make-heap compare-proc:2) โž› new heap; The compare-proc function defines the heap ordering.

(heap? object) is object a heap? โž› #t or #f


(heap-push heap object) โž› inserts object into heap โž› object

(heap-pop heap) โž› removes the 'first' element, i.e min, max, .. according to the ordering function, and returns it or #f is the heap is empty.

(heap-top heap) โž› returns the 'first' element without removing it, or #f


(heap-length heap) โž› number of elements in heap

(heap-empty? heap) is the heap empty? โž› #t or #f

(heap->list heap) โž› list of heap elements, in unspecified order

(list->heap list heap) orders elements of list according to compare-proc, and make them replace the contents of heap โž› heap

Example : taxicab numbers

โ™บ Graph.lib - Directed and undirected graphs

Notations & definitions

(graph? obj) โž› is obj a graph ? โž› #t or #f

(make-graph graph-label) โž› new empty graph

(graph-make-vertex G label) โž› new vertex u of G, or already existing such as (eq? L(u) label).

(graph-delete-vertex G u) removes u and all arcs uโž›v , vโž›u from G; โž› #t or #f if u not in G

(vertex-set-label u label) set label for vertex u โž› label

(vertex-label u ) โž› label of vertex u

(graph-vertex-ref G label) โž› first vertex u such as (eq? L(u) label), or null

Hint : to mark/unmark vertices, use (mark u value) (mark? u) (unmark u)


(graph-make-arc G u v) add new arc uโž›v to G; โž› (L(u) . L(v))

(graph-delete-arc G u v) delete uโž›v. return #t if found, #f if not found

(graph-make-edge G u v) add new edge u-v to G; โž› (L(u) . L(v))

(graph-delete-edge G u v) delete u-v; โž› #t if found, #f if not found


(graph-order G) โž› number of vertices

(graph-size G) โž› number of arcs

(graph-vertex-out G u) โž› list of vertices v such as uโž›v โˆˆ G , or null

(graph-vertex-in G u) โž› list of vertices v such as vโž›u โˆˆ G , or null

(graph-vertex-outdegree G u) โž› number of vertices v such as uโž›v โˆˆ G , or 0

(graph-vertex-indegree G u) โž› number of vertices v such as vโž›u โˆˆ G , or 0


(for ((u graph) ... ) expr1 โ€ฆ exprn) iterates on u values = all vertices of graph. Use with for, and any for*, for/... form.

(graph-for-each proc:1 G) โž› call (proc u) for each vertex u - undefined order -


(graph-cycle G u0 ) โž› a cycle (u0 u1 ... un) or null if no cycle exists including u0.

(graph-cycle G ) โž› find a cycle (u0 u1 ... un) or null if no cycle exists in G.

(graph-min-path G u v) โž› a minimal path (u u1 ... un v) or null if no path exists; u and v are distinct vertices.

(graph-dag-sort G ) topological sort โž› an ordering (u1 ... un) such as there is no arc ui+kโž›ui or null if no ordering exists i.e G is not a direct acyclic graph -


(graph-print G) โž› G in human readable form. vertex : adjacency list from each vertex.

(graph-print-vertex G u) โž› u in human readable form Label:in-degree:out-degree

(graph-sort G) sort adjacency lists according to label โž› G. does not modify the graph structure

Complete sample code in Rosetta code.

UI - Interface.lib

UI Elements

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.

(ui-create-element tag attr-value-list) โ†’ elem. Creates a new element of type "tag", and sets initial attribute values. attr-value-list is null or a list ((attr1 value1) ...)

(ui-set-attribute elem attribute value) โ†’ sets value string for attribute attribute of elem.

(ui-get-attribute elem attribute) โ†’ attribute value for elem.

(ui-attributes elem ) โ†’ list of (attribute value).

(ui-set-value input-elem value) โ†’ sets and returns elem.value

(ui-get-value input-elem) โ†’ returns elem.value

(ui-get-numvalue input-elem) โ†’ returns (integer or float) the numerical value of elem.value or #f if error.


(ui-set-style elem property value) โ†’ sets a property style value

(ui-get-style elem property) โ†’ gets a property style value

(ui-set-html elem html-string) โ†’ sets element.innerHTML


(ui-set-name elem name) โ†’ sets the element name. Internal name, not HTML attribute. Useful for referencing elements in error messages.

(ui-get-name elem) โ†’ returns the element name or "[object HTML<tag>Element]" if none.


(ui-disable elem[#t|#f]) โ†’ disable/enable element

(ui-focus elem) โ†’ sets the focus onto element

UI construction

(ui-add elem) โ†’ elem. Adds an element to the current cell UI. Elements are added in-line. Tip : insert a new <div> or <br> element to vertically arrange the following element.

(ui-insert-after elem reference) โ†’ adds element after reference element.

(ui-insert-before elem reference) โ†’ adds element before reference element.

(ui-clone elem) โ†’ new deep clone of elem.

(ui-hide elem [#t|#f]) โ†’ hides/shows element.

(ui-remove elem) โ†’ removes elem and all possible children.

(ui-clear ) โ†’ removes all UI elements.

UI events

(ui-on-change elem h:2:2) โ†’ Adds and event handler to an input element : slider, text area, ... (h elem newvalue) is a two-arguments procedure which will be called on change events.

(ui-on-click elem h:1:1) โ†’ Adds and event handler to a clickable element : button. (h elem ) is a one-argument procedure which will be called on click events.

(ui-on-focus elem h:1:1) โ†’ Adds and event handler. (h elem) is a one-argument procedure which will be called on focus events.

(ui-on-blur elem h:1:1) โ†’ Adds and event handler. (h elem) is a one-argument procedure which will be called on blur - leave focus - events.


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

Cell elements

(stdin) โ†’ stdin element = the cell input area

(stdout) โ†’ stdout element = the cell output area

(ui) โ†’ UI element = the cell ui element

(ui-set-style (ui) ' backgroundColor "orange")

Words.lib

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* .

(word-new word) โž› new word, with no tags

(word? word) is word a known word ? โž› #f or record (word tag tag ..)

(word-index word) โž› num index for word or -1

(word-ref num) โž› num-th word or #f


(word-tag word tag) โž› add tag for word

(word-set-tags! word (tagi .. tagi )) โž› add tagS for word

(word-remove-tag word tag)

(word-tags word) โž› list of tags for word

(word-tag? word tag) โž› has word this tag ? #t or #f

(word-tags? word (tagi .. tagj ..)) โž› has word tagi AND tagj and .. ? #t or #f


(words-select pattern tags limit) โž› list of matching words or null

(word-random pattern tags) โž› one random matching word or #f


(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

๐Ÿ’ฟ Audio.lib ๐Ÿ“€

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

(audio-src [file|url]) โ†’ gets or sets the audio source file/url, and preloads it..

(audio-play ) โ†’ plays the audio file.

(audio-pause ) โ†’ pause.

(audio-volume [volume]) โ†’ gets or sets the audio volume, a number in [0..1].


(audio-show ) โ†’ shows the audio control.

(audio-hide ) โ†’ hides the audio control.

(lib 'audio)
	(audio-src "./sounds/dalida")
	(audio-play)
	(audio-volume 0.8)
	(audio-show)

Alphabetical list of system symbols and functions

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 -