lambdaspeech
::
kernel
1
|
list
|
login
|
load
|
|
_img http://lambdaway.free.fr/workshop/data/mies_pav.jpg {center {i The Barcelona Pavilion, Mies van der Rohe}} _h1 kernel {blockquote {center ( See how '{lambda talk} can take benefit form KERNEL : [[WSA3]] )}} _p You are in '{lambda tank}, a wiki propulsed by a functional language '{lambda talk}. _p In the current page we introduce {b KERNEL}, a version of '{lambda talk} reduced to the main ({i and required}) special form {code (lambda (w) expression)}, two optional ({i and useful}) special forms, [{code (def name expression), (if then else)}], and a third optional special form {code (quote expression) or '(expression)} used to display unevaluated expressions. A single dictionary initially empty is progressively populated with a set of primitives built on the powerful tools brought for free by any web browsers, for instance STRINGS, ARRAYS, MATHS, HTML/CSS/SVG, DOM, ... not to speak of JAVASCRIPT, this LISP in C clothes. _p Note that: _ul {i just for the fun}, the {b lambda} symbol is keyed in as {b \} and displayed as {b λ}, _ul in order to avoid conflicts with the '{lambda talk}'s evaluator, curly braces '{} are replaced by round braces (), _ul the set of primitives is created outside the KERNEL's function and can be extended on demand, _ul and the evaluator is written in less than 150 lines of plain javascript without any external dependancies. Open the page editor to analyze the JS code, you can copy it and build a small HTML file to test it outside this wiki. _h2 1) input _p Enter any expression in the frame below - for instance {code Hello World} -, you can play freely following the syntax shown below ... {textarea {@ id="input" style="width:99%; height:300px; font:normal 0.8em courier new; color:#fff; background:#444" onkeyup="update()"} (h2 1. working with an empty dictionary) In this section we build data & control structures from scratch, we don't use the '(if bool then one else two) special form. (h3 1.1. e := w | '(\ (w) e) | '(e e) | '(def w e)) (pre 1. building an abstraction and applying it immediately '((\ (:a :b) swapping :a and :b gives :b :a as expected) hello world) -> ((\ (:a :b) swapping :a and :b gives :b :a as expected) hello world) 2. naming the abstraction part ... '(def swap (\ (:a :b) swapping :a and :b gives :b :a as expected)) -> (def swap (\ (:a :b) swapping :a and :b gives :b :a as expected)) 3. ... then applying it to words '(swap hello world) -> (swap hello world) ) (h3 1.2. booleans, pairs, lists and recursion) (pre 1: a set of primary functions: '(def | (\ (:x :y) :x)) -> (def | (\ (:x :y) :x)) '(def ø (\ (:x :y) :y)) -> (def ø (\ (:x :y) :y)) '(def ? (\ (:x :y :z) (:x :y :z))) -> (def ? (\ (:x :y :z) (:x :y :z))) '(def [] (\ (:x :y :z) (:z :x :y))) -> (def [] (\ (:x :y :z) (:z :x :y))) '(def [ (\ (:z) (:z |))) -> (def [ (\ (:z) (:z |))) '(def ] (\ (:z) (:z ø))) -> (def ] (\ (:z) (:z ø))) '(def ø? (\ (:z) (:z (| ]) [))) -> (def ø? (\ (:z) (:z (| ]) [))) 2: booleans '(| hello world) -> (| hello world) '(ø hello world) -> (ø hello world) '(? | hello world) -> (? | hello world) '(? ø hello world) -> (? ø hello world) 3: a pair '(def P ([] hello world)) -> (def P ([] hello world)) '([ (P)) -> ([ (P)) '(] (P)) -> (] (P)) 4: a list '(def L ([] hello ([] brave ([] new ([] world ø))))) -> (def L ([] hello ([] brave ([] new ([] world ø))))) 0: '([ (L)) -> ([ (L)) and '(ø? (L)) -> (ø? (L)) 1: '([ (] (L))) -> ([ (] (L))) and '(ø? (] (L))) -> (ø? (] (L))) 2: '([ (] (] (L)))) -> ([ (] (] (L)))) and '(ø? (] (] (L)))) -> (ø? (] (] (L)))) 3: '([ (] (] (] (L))))) -> ([ (] (] (] (L))))) and '(ø? (] (] (] (L))))) -> (ø? (] (] (] (L))))) 3: '([ (] (] (] (L))))) -> (] (] (] (] (L))))) and '(ø? (] (] (] (] (L)))))) -> (ø? (] (] (] (] (L)))))) 5: leading to this recursive algorithm: '(def D (\ (:l) (((ø? :l) ([] (\ (:l) ) (\ (:l) ([ :l) (D (] :l))))) :l))) -> (def D (\ (:l) (((ø? :l) ([] (\ (:l) ) (\ (:l) ([ :l) (D (] :l))))) :l))) '(D (L)) -> (D (L)) ) (h3 1.3. two applications) (h4 1.3.1. the Hanoï Towers) (pre '(def hanoi (\ (:n :from :to :via) (((ø? :n) ([] (\ (:n :from :to :via) ) (\ (:n :from :to :via) (hanoi (] :n) :from :via :to) (br) move disc ([ :n) from tower :from to tower :to (hanoi (] :n) :via :to :from) ))) :n :from :to :via))) -> (def hanoi (\ (:n :from :to :via) (((ø? :n) ([] (\ (:n :from :to :via) ) (\ (:n :from :to :via) (hanoi (] :n) :from :via :to) (br) move disc ([ :n) from tower :from to tower :to (hanoi (] :n) :via :to :from) ))) :n :from :to :via))) '(hanoi (L) A B C) -> (hanoi (L) A B C) ) _img http://sdz.tdct.org/sdz/medias/uploads.siteduzero.com_files_172001_173000_172211.gif (h4 1.3.2. the Hilbert Curve) (prewrap '(def left (\ (:d :n) (((ø? :n) ([] (\ (:d :n) ) (\ (:d :n) T90 (right :d (] :n)) M:d T-90 (left :d (] :n)) M:d (left :d (] :n)) T-90 M:d (right :d (] :n)) T90 ))) :d :n))) -> (def left (\ (:d :n) (((ø? :n) ([] (\ (:d :n) ) (\ (:d :n) T90 (right :d (] :n)) M:d T-90 (left :d (] :n)) M:d (left :d (] :n)) T-90 M:d (right :d (] :n)) T90 ))) :d :n))) '(def right (\ (:d :n) (((ø? :n) ([] (\ (:d :n) ) (\ (:d :n) T-90 (left :d (] :n)) M:d T90 (right :d (] :n)) M:d (right :d (] :n)) T90 M:d (left :d (] :n)) T-90 ))) :d :n))) -> (def right (\ (:d :n) (((ø? :n) ([] (\ (:d :n) ) (\ (:d :n) T-90 (left :d (] :n)) M:d T90 (right :d (] :n)) M:d (right :d (] :n)) T90 M:d (left :d (] :n)) T-90 ))) :d :n))) '(left 10 ([] hello ([] world ø))) -> (left 10 ([] hello ([] world ø))) ) _p where T90, T-90 and 10 are considered as words. The output is a sequence of words waiting for a graphic device to display curves, see section 7. add DRAWING functions _img http://lambdaway.free.fr/workshop/data/brussels/bibliotheque_virtuelle.jpg {center {i An infinity of words}} (h2 2. adding WORD, STRING, ARRAY functions) (p We define 3 data types: word, string, array) (ul (li 1. a word is empty or a group of chars except spaces and braces '() ) (li 2. a string is empty or a sequence of words (ul (li booleans and numbers are words) (li quotes are useless around words and strings) )) (li 3. an array is an ordered set of indexed values (ul (li values can be words, strings and arrays) (li pairs, lists, and trees are arrays) )) (li 4. functions working on words, strings and arrays are polymorphic) (li 5. the set of functions can be extended on demand) ) (p This is the list of functions, polymorphic - (i except x.new functions)) (pre 1. w.new, s.new, a.new, 2. type, null?, empty?, equal?, isin?, 3. display, length, reverse, concat, sort, 4. first, last, rest, get, 5. set!, slice!, addfirst!, addlast!, subfirst!, sublast!, 6. replace, serie, map, reduce ) {hr} {center {b See an improved version in [[WSA3]]. }} {hr} (h3 testing:) (pre '(w.new hello) -> (w.new hello) '(w.new hello brave new world) -> (w.new hello brave new world) '(w.new (a.new 1 2 3 4 5)) -> (w.new (a.new 1 2 3 4 5)) '(s.new hello) -> (s.new hello) '(s.new hello brave new world) -> (s.new hello brave new world) '(s.new (a.new 1 2 3 4 5)) -> (s.new (a.new 1 2 3 4 5)) '(a.new hello) -> (display (a.new hello)) '(a.new hello brave new world) -> (display (a.new hello brave new world)) '(a.new (a.new 1 2 3 4 5)) -> (display (a.new (a.new 1 2 3 4 5))) '(type hello) -> (type hello) '(type hello brave new world) -> (type hello brave new world) '(type (a.new 1 2 3 4 5)) -> (type (a.new 1 2 3 4 5)) w|s|a '(null?) -> (null?) w|s|a '(null? x) -> (null? x) w|s '(empty?) -> (empty?) w|s '(empty? x) -> (empty? x) a '(empty? (a.new)) -> (empty? (a.new)) a '(empty? (a.new 1)) -> (empty? (a.new 1)) w|s|a '(equal? x x) -> (equal? x x) w|s|a '(equal? x y) -> (equal? x y) w '(isin? e hello) -> (isin? e hello) s '(isin? brave in hello brave new world) -> (isin? brave in hello brave new world) a '(isin? 2 (a.new 1 2 3 4 5)) -> (isin? 2 (a.new 1 2 3 4 5)) w '(display hello) -> (display hello) s '(display hello brave new world) -> (display hello brave new world) a '(display (a.new 1 2 3 4 5)) -> (display (a.new 1 2 3 4 5)) w '(length hello) -> (length hello) s '(length hello brave new world) -> (length hello brave new world) a '(length (a.new 1 2 3 4 5)) -> (length (a.new 1 2 3 4 5)) w '(reverse hello). -> (reverse hello) s '(reverse hello brave new world) -> (reverse hello brave new world) a '(reverse (a.new 1 2 3 4 5)) -> (display (reverse (a.new 1 2 3 4 5))) w '(concat hello world) -> (concat hello world) s '(concat hello brave new world) -> (concat hello brave new world) a '(concat (a.new 1 2 3) (a.new 4 5 6)) -> (display (concat (a.new 1 2 3) (a.new 4 5 6))) w '(sort > hello) -> (sort > hello) s '(sort > hello brave new world) -> (sort > hello brave new world) a '(sort > (a.new 3 1 4 5 2)) -> (display (sort > (a.new 3 1 4 5 2))) w '(get 1 hello) -> (get 1 hello) s '(get 1 hello brave new world) -> (get 1 hello brave new world) a '(get 1 (a.new 1 2 3 4 5)) -> (get 1 (a.new 1 2 3 4 5)) w '(first hello) -> (first hello) s '(first hello brave new world) -> (first hello brave new world) a '(first (a.new 1 2 3 4 5)) -> (first (a.new 1 2 3 4 5)) w '(last hello) -> (last hello) s '(last hello brave new world) -> (last hello brave new world) a '(last (a.new 1 2 3 4 5)) -> (last (a.new 1 2 3 4 5)) w '(rest hello) -> (rest hello) s '(rest hello brave new world) -> (rest hello brave new world) a '(rest (a.new 1 2 3 4 5)) -> (display (rest (a.new 1 2 3 4 5))) // modify input w '(set! 2 x hello) -> (set! 2 x hello) s '(set! 2 old hello brave new world) -> (set! 2 old hello brave new world) a '(set! 2 0 (a.new 1 2 3 4 5)) -> (display (set! 2 0 (a.new 1 2 3 4 5))) w '(slice! 1 2 hello) -> (slice! 1 2 hello) s '(slice! 1 2 hello brave new world) -> (slice! 1 2 hello brave new world) a '(slice! 1 2 (a.new 1 2 3 4 5)) -> (display (slice! 1 2 (a.new 1 2 3 4 5))) w '(addfirst! _ hello) -> (addfirst! _ hello) s '(addfirst! _ hello brave new world) -> (addfirst! _ hello brave new world) a '(addfirst! _ (a.new 1 2 3 4 5)) -> (display (addfirst! _ (a.new 1 2 3 4 5))) w '(addlast! _ hello) -> (addlast! _ hello) s '(addlast! _ hello brave new world) -> (addlast! _ hello brave new world) a '(addlast! _ (a.new 1 2 3 4 5)) -> (display (addlast! _ (a.new 1 2 3 4 5))) w '(subfirst! hello) -> (subfirst! hello) s '(subfirst! hello brave new world) -> (subfirst! hello brave new world) a '(subfirst! (a.new 1 2 3 4 5)) -> (display (subfirst! (a.new 1 2 3 4 5))) w '(sublast! hello) -> (sublast! hello) s '(sublast! hello brave new world) -> (sublast! hello brave new world) a '(sublast! (a.new 1 2 3 4 5)) -> (display (sublast! (a.new 1 2 3 4 5))) '(replace new by old in hello brave new world) -> (replace new by old in hello brave new world) '(map u hello brave new world) -> (map u hello brave new world) '(reduce u hello brave new world) -> (reduce u hello brave new world) '(serie 0 20 2) -> (serie 0 20 2) ) (h3 some applications:) (pre '(def pair (a.new hello world)) -> (def pair (a.new hello world)) '(display (pair)) -> (display (pair)) '(first (pair)) -> (first (pair)) '(last (pair)) -> (last (pair)) '(display (rest (pair))) -> (display (rest (pair))) '(def list (a.new hello brave new world)) -> (def list (a.new hello brave new world)) '(display (list)) -> (display (list)) '(def add_style (\ (:f :l) (if (empty? :l) then else (:f (first :l)) (add_style :f (rest :l))))) -> (def add_style (\ (:f :l) (if (empty? :l) then else (:f (first :l)) (add_style :f (rest :l))))) '(add_style u (list)) -> (add_style u (list)) '(add_style (\ (:l) (b (i :l))) (list)) -> (add_style (\ (:l) (b (i :l))) (list)) ... and so on, for instance a QUICKSORT ) (h4 quicksort) (prewrap 1. three functions for readability: '(def BT.data (\ (:t) (get 0 :t))) -> (def BT.data (\ (:t) (get 0 :t))) '(def BT.left (\ (:t) (get 1 :t))) -> (def BT.left (\ (:t) (get 1 :t))) '(def BT.right (\ (:t) (get 2 :t))) -> (def BT.right (\ (:t) (get 2 :t))) 2. adding a leaf to the tree: '(def BT.add (\ (:x :t) (if (empty? :t) then (a.new :x (a.new) (a.new)) else (if (= :x (BT.data :t)) then :t else (if (< :x (BT.data :t)) then (a.new (BT.data :t) (BT.add :x (BT.left :t)) (BT.right :t)) else (a.new (BT.data :t) (BT.left :t) (BT.add :x (BT.right :t)) )))))) -> (def BT.add (\ (:x :t) (if (empty? :t) then (a.new :x (a.new) (a.new)) else (if (= :x (BT.data :t)) then :t else (if (< :x (BT.data :t)) then (a.new (BT.data :t) (BT.add :x (BT.left :t)) (BT.right :t)) else (a.new (BT.data :t) (BT.left :t) (BT.add :x (BT.right :t)) )))))) 3. creating the tree from an array of numbers: '(def BT.create (def BT.create.rec (\ (:t1 :t2) (if (empty? :t1) then :t2 else (BT.create.rec (rest :t1) (BT.add (first :t1) :t2)) ))) (\ (:t) (BT.create.rec :t (a.new)) )) -> (def BT.create (def BT.create.rec (\ (:l :t) (if (empty? :l) then :t else (BT.create.rec (rest :l) (BT.add (first :l) :t)) ))) (\ (:l) (BT.create.rec :l (a.new)) )) 4. walking the canopy -> sorting in increasing order: '(def BT.sort (\ (:t) (if (empty? :t) then else (BT.sort (BT.left :t)) (BT.data :t) (BT.sort (BT.right :t)) ))) -> (def BT.sort (\ (:t) (if (empty? :t) then else (BT.sort (BT.left :t)) (BT.data :t) (BT.sort (BT.right :t)) ))) ) (h4 Testing) (prewrap 1. generating random numbers: '(def numbers (a.new (map (\ (:n) (floor (* (random) 100000))) (serie 1 100)))) -> (def numbers (a.new (map (\ (:n) (floor (* (random) 100000))) (serie 1 100)))) = (display (numbers)) 2. creating the tree is the main work: '(def tree (BT.create (numbers))) -> (def tree (BT.create (numbers))) 3. walking the canopy is fast: '(BT.sort (tree)) -> (BT.sort (tree)) 4. walking with new leaves is fast: '(BT.sort (BT.add -1 (tree))) -> (BT.sort (BT.add -1 (tree))) '(BT.sort (BT.add 50000 (tree))) -> (BT.sort (BT.add 50000 (tree))) '(BT.sort (BT.add 100000 (tree))) -> (BT.sort (BT.add 100000 (tree))) ) _img http://lambdaway.free.fr/workshop/data/brussels/nombres.jpg {center {i an infinity of numbers}} (h2 3. adding MATH functions) (prewrap numbers and related operators are built on javascript numbers are extended to big numbers, complex numbers, ... vectors and matrices for 2D, 3D ... [ + * - / % < > <= >= = != not or and // operators abs ceil floor round min max random serie // pow sqrt exp log sin cos tan asin acos atan E PI // +++ *** ... // big numbers c.+ c.* c.- // complex numbers ] '(* 1 2 3 4 5 6) -> (* 1 2 3 4 5 6) '(def fac (\ (:n) (if (< :n 1) then 1 else (* :n (fac (- :n 1)))))) -> (def fac (\ (:n) (if (< :n 1) then 1 else (* :n (fac (- :n 1)))))) '(fac 6) -> (fac 6) '(fac 100) -> (fac 100) (def bigint 123456789012345678901234567890) = (bigint) '(* (bigint) (bigint)) -> (* (bigint) (bigint)) '(*** (bigint) (bigint)) -> (*** (bigint) (bigint)) '(serie 1 20 2) -> (serie 1 20 2) '(* (serie 1 100)) -> (* (serie 1 100)) '(map (\ (x) (* x x)) (serie 1 20)) -> (map (\ (x) (* x x)) (serie 1 20)) '(reduce *** (serie 1 100)) -> (reduce *** (serie 1 100)) ... and so on, for instance the HORNER/NEWTON algorithm ) (h4 horner & newton) (pre '(def horner (def horner.r (\ (:a :z :q :p) (if (empty? :a) then (a.new :p (/ :p :q)) else (horner.r (rest :a) :z (+ (* :z :q) :p) (+ (* :z :p) (first :a)))))) (\ (:a :z) (horner.r :a :z 0 0))) -> (def horner (def horner.r (\ (:a :z :q :p) (if (empty? :a) then (a.new :p (/ :p :q)) else (horner.r (rest :a) :z (+ (* :z :q) :p) (+ (* :z :p) (first :a)))))) (\ (:a :z) (horner.r :a :z 0 0))) '(def newton (\ (:a :x) (if (< (abs (first (horner :a :x))) 1.0e-15) then :x else (newton :a (- :x (last (horner :a :x)))) ))) -> (def newton (\ (:a :x) (if (< (abs (first (horner :a :x))) 1.0e-15) then :x else (newton :a (- :x (last (horner :a :x)))) ))) '(first (horner (a.new 9 8 7 6 5 4 3 2 1) 10)) // 9.x^8 + ... + 1.x^0 -> (first (horner (a.new 9 8 7 6 5 4 3 2 1) 10)) // for x = 10 '(newton (a.new 1 0 -2) 1) // 1x^2 + 0x - 2 = 0 -> x^2 = 2 -> x = √2 -> x = (newton (a.new 1 0 -2) 1) ) _img http://lambdaway.free.fr/workshop/data/brussels/engrenages.jpg {center {i hyper text}} (h2 4. adding HTML/CSS functions) (pre [ span div [ul ol li] [dl dt dd] [table tr td] [h1 h2 h3 h4 h5 h6] p center blockquote [pre prewrap code] [b i u] [sup sub] del [br hr] a img input ... ] '(b (i (u hello world))) -> (b (i (u hello world))) '(span (@ style="font:bold 2.0em optima; color:#f00;")Hello World) -> (span (@ style="font:bold 2.0em optima; color:#f00;")Hello World) '(def col (\ (:col :txt) (span (@ style="color::col;"):txt))) -> (def col (\ (:col :txt) (span (@ style="color::col;"):txt))) '(col #f00 hello brave new world) -> (col #f00 hello brave new world) '(col #00f hello brave new world) -> (col #00f hello brave new world) '(map u hello brave new world) -> (map u hello brave new world) '(reduce u hello brave new world) -> (reduce u hello brave new world) and so on... for instance the Dirac equation. ) (h4 Dirac equation) (center (@ style="font-size:1.5em;") i(del h)(quotient 30 ∂ψ ∂t) '(x,t) = (paren 3 [)mc(sup 2)α(sub 0) - i(del h)c(sigma 30 j=1 3) α(sub j) (quotient 30 ∂ ∂x(sub j))(paren 3 ])ψ'(x,t) ) (p A set of functions can be defined to render Math Symbols. For instance the above (b Dirac equation) is not a picture but the result of the code below:) (pre '(center i(del h)(quotient 30 ∂ψ ∂t)(x,t) = (paren 3 [) mc(sup 2)α(sub 0) - i(del h)c (sigma 30 j=1 3) α(sub j) (quotient 30 ∂ ∂x(sub j)) (paren 3 ]) ψ(x,t) )) (p built on standard HTML and CSS rules:) (pre '(def quotient (\ (:s :num :denom) (table (@ style="width::spx; display:inline-block; vertical-align:middle; text-align:center;") (tr (td (@ style="border:0 solid; border-bottom:1px solid;"):num)) (tr (td (@ style="border:0 solid;"):denom)) ))) -> (def quotient (\ (:s :num :denom) (table (@ style="width::spx; display:inline-block; vertical-align:middle; text-align:center;") (tr (td (@ style="border:0 solid; border-bottom:1px solid;"):num)) (tr (td (@ style="border:0 solid;"):denom)) ))) '(def sigma (\ (:s :one :two) (table (@ style="width::spx; display:inline-block; vertical-align:middle; text-align:center;") (tr (td (@ style="border:0 solid;"):two)) (tr (td (@ style="border:0 solid; font-size:2em; line-height:0.7em;")Σ)) (tr (td (@ style="border:0 solid;"):one)) ))) -> (def sigma (\ (:s :one :two) (table (@ style="width::spx; display:inline-block; vertical-align:middle; text-align:center;") (tr (td (@ style="border:0 solid;"):two)) (tr (td (@ style="border:0 solid; font-size:2em; line-height:0.7em;")Σ)) (tr (td (@ style="border:0 solid;"):one)) ))) '(def paren (\ (:s :p) (span (@ style="font:normal :sem optima; vertical-align:-0.15em;"):p))) -> (def paren (\ (:s :p) (span (@ style="font:normal :sem optima; vertical-align:-0.15em;"):p))) ) (h2 5. adding DOM functions) (pre '(center (input (@ type="range" min="0" max="255" value="128" step="1" oninput ="nextElementSibling.innerHTML = this.value;")) (div (@ id="slider" style="font:bold 3.0em georgia")128) ) -> (center (input (@ type="range" min="0" max="255" value="128" step="1" oninput ="nextElementSibling.innerHTML = this.value;")) (div (@ style="font:bold 3.0em georgia")128) ) ... and several other examples. ) (h2 6. adding GRAPHIC functions) _p We use the Hilbert algorithm introduced in section 1. , a primitive {b turtle} translating M10, T90 and T-90 words into 2D SVG points and some SVG functions [ {b svg path circle ...} ]: (pre '(def one ([] . ø)) -> (def one ([] . ø)) '(def two ([] . (one))) -> (def two ([] . (one))) '(def three ([] . (two))) -> (def three ([] . (two))) '(def four ([] . (three))) -> (def four ([] . (three))) '(def five ([] . (four))) -> (def five ([] . (four))) '(svg (@ width="330px" height="330px" style="box-shadow:0 0 8px #888;") (def path_style (\ (:col :d) fill="transparent" stroke=":col" stroke-width=":d")) (path (@ d="M (turtle 10 10 0 (left 10 (one)))" (path_style black 9))) (path (@ d="M (turtle 40 10 -90 (left 10 (two)))" (path_style red 7))) (path (@ d="M (turtle 10 10 0 (left 10 (three)))" (path_style green 5))) (path (@ d="M (turtle 160 10 -90 (left 10 (four)))" (path_style blue 3))) (path (@ d="M (turtle 10 10 0 (left 10 (five)))" (path_style grey 1) id="spline" )) (circle (@ cx="0" cy="0" r="5" fill="#ff0" stroke="#f00") (animateMotion (@ dur="100s" repeatCount="indefinite" rotate="auto") (mpath (@ xlink:href="#spline")) ) ) ) -> (center (svg (@ width="330px" height="330px" style="box-shadow:0 0 8px #888;") (def path_style (\ (:col :d) fill="transparent" stroke=":col" stroke-width=":d")) (path (@ d="M (turtle 10 10 0 (left 10 (one)))" (path_style black 9))) (path (@ d="M (turtle 40 10 -90 (left 10 (two)))" (path_style red 7))) (path (@ d="M (turtle 10 10 0 (left 10 (three)))" (path_style green 5))) (path (@ d="M (turtle 160 10 -90 (left 10 (four)))" (path_style blue 3))) (path (@ d="M (turtle 10 10 0 (left 10 (five)))" (path_style grey 1) id="spline" )) (circle (@ cx="0" cy="0" r="5" fill="#ff0" stroke="#f00") (animateMotion (@ dur="100s" repeatCount="indefinite" rotate="auto") (mpath (@ xlink:href="#spline")) ) ) )) ) (h2 7. adding more functions) (p Populating the dictionary is endless. Currently it contains 120 primitives - from lib to turtle - followed by new functions defined by the user in the current page and listed below:) (blockquote (@ style="padding:10px; color:#800;") (lib) ) } _p ... and see the result in real time in the output frame. _h2 2) output {center {@ id="infos"}...} {div {@ id="output" style="box-shadow:0 0 8px #000; padding:10px; background:#eee; "}...} _h2 3) next _img http://lambdaway.free.fr/workshop/data/brussels/poles.jpg {center {i The Sagrada Familia, Barcelona, Antonio Gaudi}} _p To conclude it is interesting to note that '{lambda talk} is nothing but {b KERNEL} with a set of special forms extended to nine [ {code lambda def quote if let macro script style require }] {i and a few other things}. It can be said that only one special form is required in the language, the {b lambda special form}, and that the eight other ones are nothing but "syntactic sugar". Which are obviously very useful in the real life! _h2 4) code _img http://lambdaway.free.fr/workshop/data/brussels/operators.jpg {center {i data is code and code is data}} _p The KERNEL's JS code is in less than 150 lines: {pre °° var KERNEL = (function() { var regexp = /\(([^\s()]*)(?:[\s]*)([^()]*)\)/g; var DICT = {}, LAMB_num = 0; var QUOT = {}, QUOT_num = 0; var evaluate = function(s) { var bal = balance(s); if (bal.left === bal.right) { s = preprocessing(s); s = eval_specials(s,'quote',eval_quote); s = eval_specials(s,'lambda',eval_lambda); s = eval_specials(s,'if',eval_if); s = eval_specials(s,'def',eval_def,true); s = eval_forms(s); s = postprocessing(s); } return { val:s, bal:bal }; }; var eval_forms = function(s) { while (s !== (s = s.replace(regexp, eval_form))); return s; }; var eval_form = function() { var f = arguments[1] || "", r = arguments[2] || ""; return DICT.hasOwnProperty(f) ? DICT[f].apply(null, [r]) : "⊂" + f + " " + r + "⊃"; }; var eval_specials = function(s,symbol,eval_symbol,flag) { while (s !== (s = form_replace(s, symbol, eval_symbol, flag))) ; return s; }; var eval_lambda = function(s) { s = eval_specials(s,'lambda',eval_lambda); var index = s.indexOf(")"), argStr = supertrim(s.substring(1, index)), args = argStr === "" ? [] : argStr.split(" "), body = supertrim(s.substring(index + 2)), name = "_LAMB_" + LAMB_num++; DICT[name] = function() { var valStr = supertrim(arguments[0]), vals = valStr === "" ? [] : valStr.split(" "), bod = body; if (vals.length < args.length) { for (var i = 0; i < vals.length; i++) bod = bod.replace(RegExp(args[i], "g"), vals[i]); var _args_ = args.slice(vals.length).join(" "); bod = eval_lambda("(" + _args_ + ") " + bod); } else if (vals.length === args.length) { for (var i=0; i < args.length; i++) bod = bod.replace( RegExp(args[i], "g"), vals[i] ); } else { var _vals_ = vals.slice(0,args.length); _vals_[args.length-1] = vals.slice(args.length-1,vals.length).join(' '); for (var i=0; i < args.length; i++) bod = bod.replace( RegExp(args[i], "g"), _vals_[i] ); } bod = eval_specials(bod,'if',eval_if); return eval_forms(bod); }; return name; }; var eval_def = function(s, flag) { s = eval_specials(s,'def',eval_def,false); var index = s.search(/\s/); var name = s.substring(0, index).trim(); var body = s.substring(index).trim(); if (body.substring(0, 6) === "_LAMB_") { DICT[name] = DICT[body]; } else { body = eval_forms(body); DICT[name] = function() { return body; }; } return flag ? name : ""; }; var eval_if = function(s) { s = eval_specials(s,'if',eval_if); var index1 = s.indexOf( 'then' ), index2 = s.indexOf( 'else' ), bool = s.substring(0,index1).trim(), one = s.substring(index1+5,index2).trim(), two = s.substring(index2+5).trim(); return (eval_forms(bool) === 'true')? one : two }; var eval_quote = function(s) { // (* 2 3) var name = "_QUOT_" + QUOT_num++; QUOT[name] = s; return name; // _QUOT_n }; var preprocessing = function(s) { s = s.replace( /\(\\/g, "(lambda" ); LAMB_num = 0; QUOT_num = 0; s = apo2quote( s ); return s; }; var postprocessing = function(s) { s = s.replace(/_QUOT_\d+/g, function(s) { return "("+QUOT[s]+")" }); // s = s.replace(/\(lambda/g, "(\\"); s = s.replace(/\(lambda/g, "(
λ
"); LAMB_num = 0; QUOT_num =0; return s; }; var form_replace = function(str, symbol, func, flag) { symbol = "(" + symbol + " "; var s = catch_form(symbol, str); return s === "none" ? str : str.replace(symbol+s+")", func(s,flag)); }; var catch_form = function(symbol, str) { var start = str.indexOf(symbol); if (start == -1) return "none"; var nb = 1, index = start; while (nb > 0 && index < 1000000) { index++; if (str.charAt(index) == "(") nb++; else if (str.charAt(index) == ")") nb--; } return str.substring(start + symbol.length, index); }; var apo2quote = function (s) { // '(...) return s.replace(/'\(([\s\S]*?)\)/g, "(quote $1)"); // -> (quote (...)) }; var balance = function(s) { var strt = s.match(/\(/g), stop = s.match(/\)/g); strt = strt ? strt.length : 0; stop = stop ? stop.length : 0; return { left: strt, right: stop }; }; var supertrim = function(s) { return s.trim().replace(/\s+/g, " "); }; DICT["lib"] = function() { var str = "", index = 0; for (var key in DICT) { if (DICT.hasOwnProperty(key) && key.substring(0, 6) !== "_LAMB_") { str += key + ", "; index++; } } return "DICT: ["+index+"] ["+str.substring(0,str.length-2)+"]"; }; return { evaluate:evaluate, supertrim:supertrim, DICT:DICT } })(); °°} _p Then comes the rather long sequence of primitives. _p You can open the wiki page's frame editor to analyze the JS code. _p Then you could take a look at the '{lambda way} [[project|?view=start]]. _p Welcome. {script ;; var update = function() { var t0 = new Date().getTime(), code = document.getElementById('input').value, result = KERNEL.evaluate( code ), time = new Date().getTime() - t0; document.getElementById('infos').innerHTML = '(' + result.bal.left + ':' + result.bal.right + ') ' + time + 'ms'; if (result.bal.left === result.bal.right) document.getElementById('output').innerHTML = result.val ; }; setTimeout( update, 10); var KERNEL = (function() { var regexp = /\(([^\s()]*)(?:[\s]*)([^()]*)\)/g; var DICT = {}, LAMB_num = 0; var QUOT = {}, QUOT_num = 0; var evaluate = function(s) { var bal = balance(s); if (bal.left === bal.right) { s = preprocessing(s); s = eval_specials(s,'quote',eval_quote); s = eval_specials(s,'lambda',eval_lambda); s = eval_specials(s,'if',eval_if); s = eval_specials(s,'def',eval_def,true); s = eval_forms(s); s = postprocessing(s); } return { val:s, bal:bal }; }; var eval_forms = function(s) { while (s !== (s = s.replace(regexp, eval_form))); return s; }; var eval_form = function() { var f = arguments[1] || "", r = arguments[2] || ""; return DICT.hasOwnProperty(f) ? DICT[f].apply(null, [r]) : "⊂" + f + " " + r + "⊃"; }; var eval_specials = function(s,symbol,eval_symbol,flag) { while (s !== (s = form_replace(s, symbol, eval_symbol, flag))) ; return s; }; var eval_lambda = function(s) { s = eval_specials(s,'lambda',eval_lambda); var index = s.indexOf(")"), argStr = supertrim(s.substring(1, index)), args = argStr === "" ? [] : argStr.split(" "), body = supertrim(s.substring(index + 2)), name = "_LAMB_" + LAMB_num++; DICT[name] = function() { var valStr = supertrim(arguments[0]), vals = valStr === "" ? [] : valStr.split(" "), bod = body; if (vals.length < args.length) { for (var i = 0; i < vals.length; i++) bod = bod.replace(RegExp(args[i], "g"), vals[i]); var _args_ = args.slice(vals.length).join(" "); bod = eval_lambda("(" + _args_ + ") " + bod); } else if (vals.length === args.length) { for (var i=0; i < args.length; i++) bod = bod.replace( RegExp(args[i], "g"), vals[i] ); } else { var _vals_ = vals.slice(0,args.length); _vals_[args.length-1] = vals.slice(args.length-1,vals.length).join(' '); for (var i=0; i < args.length; i++) bod = bod.replace( RegExp(args[i], "g"), _vals_[i] ); } bod = eval_specials(bod,'if',eval_if); return eval_forms(bod); }; return name; }; var eval_def = function(s, flag) { s = eval_specials(s,'def',eval_def,false); var index = s.search(/\s/); var name = s.substring(0, index).trim(); var body = s.substring(index).trim(); if (body.substring(0, 6) === "_LAMB_") { DICT[name] = DICT[body]; } else { body = eval_forms(body); DICT[name] = function() { return body; }; } return flag ? name : ""; }; //// IF : {if bool then one else two} var eval_if = function(s) { s = eval_specials(s,'if',eval_if); var index1 = s.indexOf( 'then' ), index2 = s.indexOf( 'else' ), bool = s.substring(0,index1).trim(), one = s.substring(index1+5,index2).trim(), two = s.substring(index2+5).trim(); return (eval_forms(bool) === 'true')? one : two }; var apo2quote = function (s) { // '(* 2 3) return s.replace(/'\(([\s\S]*?)\)/g, "(quote $1)"); // -> (quote (* 2 3)) }; var eval_quote = function(s) { // (* 2 3) var name = "_QUOT_" + QUOT_num++; QUOT[name] = s; return name; // _QUOT_n }; var preprocessing = function(s) { s = s.replace( /\(\\/g, "(lambda" ); LAMB_num = 0; QUOT_num = 0; s = apo2quote( s ); return s; }; var postprocessing = function(s) { s = s.replace(/_QUOT_\d+/g, function(s) { return "(" + QUOT[s] + ")" }); // s = s.replace(/\(lambda/g, "(\\"); s = s.replace(/\(lambda/g, "(
λ
"); LAMB_num = 0; QUOT_num =0; return s; }; var form_replace = function(str, symbol, func, flag) { symbol = "(" + symbol + " "; var s = catch_form(symbol, str); return s === "none" ? str : str.replace(symbol + s + ")", func(s, flag)); }; var catch_form = function(symbol, str) { var start = str.indexOf(symbol); if (start == -1) return "none"; var nb = 1, index = start; while (nb > 0 && index < 1000000) { index++; if (str.charAt(index) == "(") nb++; else if (str.charAt(index) == ")") nb--; } return str.substring(start + symbol.length, index); }; var balance = function(s) { var strt = s.match(/\(/g), stop = s.match(/\)/g); strt = strt ? strt.length : 0; stop = stop ? stop.length : 0; return { left: strt, right: stop }; }; var supertrim = function(s) { return s.trim().replace(/\s+/g, " "); }; DICT["lib"] = function() { var str = "", index = 0; for (var key in DICT) { if (DICT.hasOwnProperty(key) && key.substring(0, 6) !== "_LAMB_") { str += key + ", "; index++; } } return "DICT: [" + index + "] [" + str.substring(0, str.length - 2) + "]"; }; return { evaluate:evaluate, supertrim:supertrim, DICT:DICT } })(); //// populating the dictionary var WSA = (function () { var ARRA = {}, ARRA_num = 0; var isWord = function (z) { return (z !== '' && z.substring(0,6) !== '_ARRA_' && z.indexOf(" ") === -1) }; var isString = function (z) { return (z !== '' && z.substring(0,6) !== '_ARRA_' && z.indexOf(" ") !== -1) }; var isArray = function (z) { return (z !== '' && z.substring(0,6) === '_ARRA_') }; KERNEL.DICT['w.new'] = function () { var args = KERNEL.supertrim(arguments[0]); if (isWord(args)) return args else if (isString(args)) return args.replace(/\s/g,"") else if (isArray(args)) return ARRA[args].join("") }; KERNEL.DICT['s.new'] = function () { var args = KERNEL.supertrim(arguments[0]); if (isWord(args)) return args.split("").join(" ") else if (isString(args)) return args else if (isArray(args)) return ARRA[args].join(" ") }; KERNEL.DICT['a.new'] = function () { var args = KERNEL.supertrim(arguments[0]); var name = '_ARRA_' + ARRA_num++; if (args === "") res = [] else if (isWord(args)) res = args.split("") else if (isString(args)) res = args.split(" ") else if (isArray(args)) res = ARRA[args] ARRA[name] = res; return name; }; KERNEL.DICT['type'] = function() { var args = KERNEL.supertrim(arguments[0]); if (isWord(args)) return 'word' else if (isString(args)) return 'string' else if (isArray(args)) return 'array' }; KERNEL.DICT['null?'] = function() { // '' or "" or _ARRA_n var args = KERNEL.supertrim(arguments[0]); return (args === "")? "true" : "false" }; KERNEL.DICT['empty?'] = function () { // '' or "" or _ARRA_n var args = arguments[0].trim(); if (args === "") return "true" else if (!isArray(args)) return "false" else return (ARRA[args].length < 1)? "true" : "false" }; KERNEL.DICT['equal?'] = function() { // var args = KERNEL.supertrim(arguments[0]).split(" "); return (args[0] === args[1])? "true" : "false" }; KERNEL.DICT['isin?'] = function() { // (isin? v x) var args = KERNEL.supertrim(arguments[0]).split(' '), val = args.shift(), s = args.join(" "); if (isWord(s)) { s = s.split(""); return (s.lastIndexOf(val) !==-1)? "true" : "false" } else if (isString(s)) { s = s.split(" "); return (s.lastIndexOf(val) !==-1)? "true" : "false" } else if (isArray(s)) { return (ARRA[s].lastIndexOf(val) !==-1)? "true" : "false" } }; //// KERNEL.DICT['display'] = function() { var args = KERNEL.supertrim(arguments[0]); if (isWord(args)) return "'"+args+"'" else if (isString(args)) return '"'+args+'"' else if (isArray(args)) return "["+ARRA[args]+"]" }; KERNEL.DICT['length'] = function() { var args = KERNEL.supertrim(arguments[0]); if (isWord(args)) return args.length else if (isString(args)) return args.split(" ").length else if (isArray(args)) return ARRA[args].length }; //// KERNEL.DICT['reverse'] = function () { var args = KERNEL.supertrim(arguments[0]); if (isWord(args)) return args.split("").reverse().join("") else if (isString(args)) return args.split(" ").reverse().join(" ") else if (isArray(args)) { var name = '_ARRA_' + ARRA_num++; ARRA[name] = ARRA[args].reverse(); return name; } }; KERNEL.DICT['concat'] = function () { var args = KERNEL.supertrim(arguments[0]).split(' '); if (args.length === 0) return '' else if (args.length === 1) return args[0] else if (args.length === 2) { if (isWord(args[0]) && isWord(args[1])) return args[0]+args[1] else if (isArray(args[0]) && isArray(args[1])) { var name = '_ARRA_' + ARRA_num++; ARRA[name] = ARRA[args[0]].concat(ARRA[args[1]]); return name; } } else return args.join(" ") }; KERNEL.DICT['sort'] = function () { // (sort comp words) var args = KERNEL.supertrim(arguments[0]).split(' '); comp = args.shift(), s = args.join(' '); if (isWord(s)) { if (comp === '>') return s.split('').sort( function(a,b) { return a > b } ).join('') else return s.split('').sort( function(a,b) { return a < b } ).join('') } else if (isString(s)) { if (comp === '>') return s.split(' ').sort( function(a,b) { return a > b } ).join(' ') else return s.split(' ').sort( function(a,b) { return a < b } ).join(' ') } else if (isArray(s)) { var res = []; if (comp === '>') res = ARRA[s].slice().sort( function(a,b) { return a - b } ) else res = ARRA[s].slice().sort( function(a,b) { return b - a } ) var name = '_ARRA_' + ARRA_num++; ARRA[name] = res; return name } }; //// KERNEL.DICT['first'] = function() { // 'hello' "hello brave new world" _ARRA_n var args = KERNEL.supertrim(arguments[0]); if (isWord(args)) return args.charAt(0) else if (isString(args)) return args.split(" ")[0] else if (isArray(args)) return ARRA[args][0] }; KERNEL.DICT['last'] = function() { // 'hello' "hello brave new world" _ARRA_n var args = KERNEL.supertrim(arguments[0]); if (isWord(args)) return args.charAt(args.length-1) else if (isString(args)) { var arr = args.split(" "); return arr[arr.length-1] } else if (isArray(args)) return ARRA[args][ARRA[args].length-1] }; KERNEL.DICT['rest'] = function() { // 'hello' "hello brave new world" _ARRA_n var args = KERNEL.supertrim(arguments[0]); if (isWord(args)) return args.substring(1) else if (isString(args)) return args.split(" ").slice(1).join(" "); else if (isArray(args)) { var name = '_ARRA_' + ARRA_num++; ARRA[name] = ARRA[args].slice(1); return name; } }; KERNEL.DICT['get'] = function() { var args = KERNEL.supertrim(arguments[0]).split(' '), i = parseInt(args.shift()), s = args.join(' '); if (isWord(s)) return s.charAt(i) else if (isString(s)) return s.split(" ")[i] else if (isArray(s)) return ARRA[s][i] }; KERNEL.DICT['set!'] = function() { // (set i char string) var args = KERNEL.supertrim(arguments[0]).split(' '), i = parseInt(args.shift()), v = args.shift(), s = args.join(" "); if (isWord(s)) { s = s.split(""); s[i] = v; return s } else if (isString(s)) { s = s.split(' '); s[i] = v; return s } else if (isArray(s)) { var name = '_ARRA_' + ARRA_num++; ARRA[name] = ARRA[s].slice(); ARRA[name][i] = v; return name } }; // KERNEL.DICT['slice!'] = function() { // i0 i1 'hello' | "hello brave new world" | _ARRA_n var args = KERNEL.supertrim(arguments[0]).split(' '), i0 = parseInt(args.shift()), i1 = parseInt(args.shift()), args = args.join(' '); if (isWord(args)) return args.substring(i0,i1+1) else if (isString(args)) return args.split(" ").slice(i0,i1+1).join(" ") else if (isArray(args)) { ARRA[args] = ARRA[args].slice(i0,i1+1) return args } }; KERNEL.DICT['addfirst!'] = function() { // val 'hello' "hello brave new world" _ARRA_n var args = KERNEL.supertrim(arguments[0]).split(" "), val = args.shift(), args = args.join(" "); if (isWord(args)) return val + args else if (isString(args)) return val + " " + args else if (isArray(args)) { ARRA[args].unshift(val); return args; } }; KERNEL.DICT['addlast!'] = function() { var args = KERNEL.supertrim(arguments[0]).split(" "), val = args.shift(), args = args.join(" "); if (isWord(args)) return args + val else if (isString(args)) return args + " " + val else if (isArray(args)) { ARRA[args].push(val); return args; } }; KERNEL.DICT['subfirst!'] = function() { var args = KERNEL.supertrim(arguments[0]); if (isWord(args)) return args.substring(1) else if (isString(args)) return args.substring(1) else if (isArray(args)) { ARRA[args].shift(); return args; } }; KERNEL.DICT['sublast!'] = function() { var args = KERNEL.supertrim(arguments[0]); if (isWord(args)) return args.substring(0,args.length-1) else if (isString(args)) return args.substring(0,args.length-1) else if (isArray(args)) { ARRA[args].pop(); return args; } }; //// REPLACE SERIE MAP REDUCE KERNEL.DICT['replace'] = function () { // (replace one by two in text) var str = KERNEL.supertrim(arguments[0]); // one by two in text var index = str.indexOf('by'); var one = str.substring(0,index).trim(); str = str.substring(index+2).trim(); index = str.indexOf('in'); var two = str.substring(0,index).trim().replace(/€/g,'$'); two = (two !== 'space')? two : ' '; str = str.substring(index+2).trim(); str = str.replace( RegExp(one,'g'), two ); return str; }; KERNEL.DICT['serie'] = function () { // {serie start end [step]} var args = KERNEL.supertrim(arguments[0]).split(' '); var start = parseFloat( args[0] ), end = parseFloat( args[1] ), step = parseFloat( args[2] || 1), str = ''; if (step == 0) return start; step = Math.abs(step); if (start < end) for (var i=start; i<=end; i+= step) { str += i + ' '; } else if (start > end) for (var i=start; i>=end; i-= step) { str += i + ' '; } return str.substring(0, str.length-1); }; KERNEL.DICT['map'] = function () { // {map func serie} var args = KERNEL.supertrim(arguments[0]).split(' '); var func = args.shift(); var str = ''; if (KERNEL.DICT[func] !== undefined) { for (var i=0; i< args.length; i++) str += KERNEL.DICT[func].call( null, args[i] ) + ' '; } return str.substring(0, str.length-1); }; KERNEL.DICT['reduce'] = function () { // {reduce func serie} var args = KERNEL.supertrim(arguments[0]).split(' '); var func = args.shift(); // * var r = args[0]; // [1,2,3,4] for (var i=1; i< args.length; i++) // {* r args[i]} r = KERNEL.DICT[func].call(null, (r + " " + args[i])); return r }; return { ARRA:ARRA } //// end WORDS, STRINGS, ARRAYS })(); //// HTML/CSS/SVG var HTML = (function() { var htmltags = [ 'span', 'div', 'a', 'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'table', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'b', 'i', 'u', 'center', 'br', 'hr', 'blockquote', 'del', 'sup', 'sub', 'code', 'img', 'pre', 'input', 'canvas', 'svg', 'line', 'rect', 'circle', 'ellipse', 'polygon', 'polyline', 'path', 'text', 'g', 'mpath', 'use', 'textPath', 'pattern', 'image', 'clipPath', 'defs', 'animate', 'set', 'animateMotion', 'animateTransform', 'title', 'desc' ]; KERNEL.DICT['@'] = function () { // (@ style="color:#f00;") var a = arguments[0]; return '@@' + a + '@@' // @@style="color:#f00;@@ }; KERNEL.DICT['prewrap'] = function () { // {prewrap ...} var args = arguments[0]; return '
' + args + '
' }; for (var i=0; i< htmltags.length; i++) { KERNEL.DICT[htmltags[i]] = function(tag) { return function() { var args = arguments[0].trim(); // save spaces for pre var attr = args.match( /@@[\s\S]*?@@/ ); if (attr == null) { return '<'+tag+'>'+args+''+tag+'>'; } else { args = args.replace( attr[0], '' ).trim(); attr = attr[0].replace(/^@@/, '').replace(/@@$/, ''); return '<'+tag+' '+attr+'>'+args+''+tag+'>'; } } }(htmltags[i]); } return { htmltags:htmltags } })(); //// MATH var MATH = (function() { var mathtags = [ "abs", "acos", "asin", "atan", "ceil", "cos", "exp", "floor", "pow", "log", "random", "round", "sin", "sqrt", "tan", "min", "max" ]; for (var i = 0; i < mathtags.length; i++) { KERNEL.DICT[mathtags[i]] = (function(tag) { return function() { return tag.apply(null, KERNEL.supertrim(arguments[0]).split(" ")) }; })(Math[mathtags[i]]); } KERNEL.DICT["+"] = function() { var a = KERNEL.supertrim(arguments[0]).split(" "), r; if (a.length === 0) r = 0; else if (a.length === 1) r = a[0]; else if (a.length === 2) r = Number(a[0]) + Number(a[1]); else for (var r = 0, i = 0; i < a.length; i++) r += Number(a[i]); return r; }; KERNEL.DICT["-"] = function() { var a = KERNEL.supertrim(arguments[0]).split(" "), r; if (a.length === 0) r = 0; else if (a.length === 1) r = -a[0]; else if (a.length === 2) r = a[0] - a[1]; else for (var r = a[0], i = 1; i < a.length; i++) r -= a[i]; return r; }; KERNEL.DICT["*"] = function() { var a = KERNEL.supertrim(arguments[0]).split(" "), r; if (a.length === 0) r = 1; else if (a.length === 1) r = a[0]; else if (a.length === 2) r = a[0] * a[1]; else for (var r = 1, i = 0; i < a.length; i++) r *= a[i]; return r; }; KERNEL.DICT["/"] = function() { var a = KERNEL.supertrim(arguments[0]).split(" "), r; if (a.length === 0) r = 1; else if (a.length === 1) r = 1/a[0]; else if (a.length === 2) r = a[0]/a[1]; else for (var r = a[0], i = 1; i < a.length; i++) r /= a[i]; return r; }; KERNEL.DICT["%"] = function() { var a = KERNEL.supertrim(arguments[0]).split(" "); return Number(a[0]) % Number(a[1]); }; KERNEL.DICT["<"] = function() { var a = KERNEL.supertrim(arguments[0]).split(" "); var x = Number(a[0]), y = Number(a[1]); return (x < y) ? "true" : "false"; }; KERNEL.DICT[">"] = function() { var a = KERNEL.supertrim(arguments[0]).split(" "); var x = Number(a[0]), y = Number(a[1]); return (x > y) ? "true" : "false"; }; KERNEL.DICT["<="] = function() { var a = KERNEL.supertrim(arguments[0]).split(" "); var x = Number(a[0]), y = Number(a[1]); return (x <= y) ? "true" : "false"; }; KERNEL.DICT[">="] = function() { var a = KERNEL.supertrim(arguments[0]).split(" "); var x = Number(a[0]), y = Number(a[1]); return (x >= y) ? "true" : "false"; }; KERNEL.DICT['='] = function() { // {= one two} var a = KERNEL.supertrim(arguments[0]).split(' '), x = Number(a[0]), y = Number(a[1]); return (!(x < y) && !(y < x))? 'true' : 'false'; }; KERNEL.DICT['not'] = function () { var a = KERNEL.supertrim(arguments[0]); return (a === 'true')? 'false' : 'true'; }; KERNEL.DICT['or'] = function () { var terms = KERNEL.supertrim(arguments[0]).split(' '); for (var ret=false, i=0; i< terms.length; i++) if (terms[i] === 'true') return 'true'; return ret; }; KERNEL.DICT['and'] = function () { // (and (= 1 1) (= 1 2)) -> false var terms = KERNEL.supertrim(arguments[0]).split(' '); for (var ret=true, i=0; i< terms.length; i++) if (terms[i] === 'false') return 'false'; return ret; }; // BIG INTS KERNEL.DICT['+++'] = function () { var args = KERNEL.supertrim(arguments[0]).split(' '), a = args[0].split("").reverse(), b = args[1].split("").reverse(), n = Math.max(a.length, b.length), c = [], d = 0; for (var i=0; i < n; i++) { c[i] = (a[i] | 0) + (b[i] | 0) + d; if (c[i] > 9) { c[i] -= 10; d = 1; } else { d = 0; } } if (d === 1) c.push(1); return c.reverse().join('') }; KERNEL.DICT['***'] = function () { var args = KERNEL.supertrim(arguments[0]).split(' '), a = args[0].split("").reverse(), b = args[1].split("").reverse(), c = []; for ( var i1 = 0; i1 < a.length; i1++ ) { for ( var i2 = 0; i2 < b.length; i2++ ) { var j = i1 + i2; c[j] = a[i1] * b[i2] + (c[j] | 0); if ( c[j] > 9 ) { var f = Math.floor( c[j] / 10 ); c[j] -= f * 10; c[j+1] = f + (c[j+1] | 0); } } } return c.reverse().join("") }; // and so on ... return { mathtags:mathtags } })(); //// TURTLE FOR SVG KERNEL.DICT['turtle'] = function () { var draw = function(str) { // {turtle x0 y0 a0 M100 T90 M50 T-45 ...} var args = str.split(' '); var x0 = parseFloat(args[0]), y0 = parseFloat(args[1]), a0 = parseFloat(args[2]), poly = []; poly.push( [x0, y0, a0] ); for (var i=3; i < args.length; i++) { var act = args[i].charAt(0), val = parseFloat(args[i].substring(1)); if (act === 'M') { var p = poly[poly.length-1], a = p[2] * Math.PI / 180.0, x = p[0] + val * Math.sin(a), y = p[1] + val * Math.cos(a); poly.push( [x,y,p[2]] ) } else { var p = poly.pop(); poly.push( [p[0],p[1],p[2]+val] ) } } for (var pol = '', i=0; i < poly.length; i++) pol += Math.round(poly[i][0]) + ' ' + Math.round(poly[i][1]) + ' '; return pol }; return draw( KERNEL.supertrim(arguments[0]) ); }; // and so on ... } ;; end script _p {i Alain Marty - 2019/10/21}
lambdaspeech v.20200126