mondo.test.mjs - <short description TODO> Copyright (C) 2022 Strudel contributors - see https://github.com/tidalcycles/strudel/blob/main/packages/mini/test/mini.test.mjs This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses/.
10const parser = new MondoParser(); 11const p = (code) => parser.parse(code, -1); 12 13describe('mondo tokenizer', () => { 14 const parser = new MondoParser(); 15 it('should tokenize with locations', () => 16 expect( 17 parser 18 .tokenize('(one two three)') 19 .map((t) => t.value + '=' + t.loc.join('-')) 20 .join(' '), 21 ).toEqual('(=0-1 one=1-4 two=5-8 three=9-14 )=14-15')); 22 // it('should parse with loangleions', () => expect(parser.parse('(one two three)')).toEqual()); 23 it('should get loangleions', () => 24 expect(parser.get_locations('s bd rim')).toEqual([ 25 [0, 1], 26 [2, 4], 27 [5, 8], 28 ])); 29}); 30describe('mondo s-expressions parser', () => { 31 it('should parse an empty string', () => expect(p('')).toEqual({ type: 'list', children: [] })); 32 it('should parse a single item', () => 33 expect(p('a')).toEqual({ type: 'list', children: [{ type: 'plain', value: 'a' }] })); 34 it('should parse an empty list', () => expect(p('()')).toEqual({ type: 'list', children: [] })); 35 it('should parse a list with 1 item', () => 36 expect(p('(a)')).toEqual({ type: 'list', children: [{ type: 'plain', value: 'a' }] })); 37 it('should parse a list with 2 items', () => 38 expect(p('(a b)')).toEqual({ 39 type: 'list', 40 children: [ 41 { type: 'plain', value: 'a' }, 42 { type: 'plain', value: 'b' }, 43 ], 44 })); 45 it('should parse a list with 2 items', () => 46 expect(p('(a (b c))')).toEqual({ 47 type: 'list', 48 children: [ 49 { type: 'plain', value: 'a' }, 50 { 51 type: 'list', 52 children: [ 53 { type: 'plain', value: 'b' }, 54 { type: 'plain', value: 'c' }, 55 ], 56 }, 57 ], 58 })); 59 it('should parse numbers', () => 60 expect(p('(1 .2 1.2 10 22.3)')).toEqual({ 61 type: 'list', 62 children: [ 63 { type: 'number', value: '1' }, 64 { type: 'number', value: '.2' }, 65 { type: 'number', value: '1.2' }, 66 { type: 'number', value: '10' }, 67 { type: 'number', value: '22.3' }, 68 ], 69 })); 70 it('should parse comments', () => 71 expect(p('a // hello')).toEqual({ 72 type: 'list', 73 children: [ 74 { type: 'plain', value: 'a' }, 75 { type: 'comment', value: '// hello' }, 76 ], 77 })); 78}); 79 80let desguar = (a) => { 81 return printAst(parser.parse(a), true); 82}; 83 84describe('mondo sugar', () => { 85 it('should desugar []', () => expect(desguar('[a b c]')).toEqual('(square a b c)')); 86 it('should desugar [] nested', () => expect(desguar('[a [b c] d]')).toEqual('(square a (square b c) d)')); 87 it('should desugar <>', () => expect(desguar('<a b c>')).toEqual('(angle a b c)')); 88 it('should desugar <> nested', () => expect(desguar('<a <b c> d>')).toEqual('(angle a (angle b c) d)')); 89 it('should desugar mixed [] <>', () => expect(desguar('[a <b c>]')).toEqual('(square a (angle b c))')); 90 it('should desugar mixed <> []', () => expect(desguar('<a [b c]>')).toEqual('(angle a (square b c))')); 91 92 it('should desugar #', () => expect(desguar('s jazz # fast 2')).toEqual('(fast 2 (s jazz))')); 93 it('should desugar # square', () => expect(desguar('[bd cp # fast 2]')).toEqual('(fast 2 (square bd cp))')); 94 it('should desugar # twice', () => expect(desguar('s jazz # fast 2 # slow 2')).toEqual('(slow 2 (fast 2 (s jazz)))')); 95 it('should desugar # nested', () => expect(desguar('(s cp # fast 2)')).toEqual('(fast 2 (s cp))')); 96 it('should desugar # within []', () => expect(desguar('[bd cp # fast 2]')).toEqual('(fast 2 (square bd cp))')); 97 it('should desugar # within , within []', () => 98 expect(desguar('[bd cp # fast 2, x]')).toEqual('(stack (fast 2 (square bd cp)) x)'));
it('should desugar .(.', () => expect(desguar('[jazz hh.(.fast 2)]')).toEqual('(square jazz (fast 2 hh))'));
102 it('should desugar , |', () => expect(desguar('[bd, hh | oh]')).toEqual('(stack bd (or hh oh))')); 103 it('should desugar , | of []', () => 104 expect(desguar('[bd, hh | [oh rim]]')).toEqual('(stack bd (or hh (square oh rim)))')); 105 it('should desugar , square', () => expect(desguar('[bd, hh]')).toEqual('(stack bd hh)')); 106 it('should desugar , square 2', () => expect(desguar('[bd, hh oh]')).toEqual('(stack bd (square hh oh))')); 107 it('should desugar , square 3', () => 108 expect(desguar('[bd cp, hh oh]')).toEqual('(stack (square bd cp) (square hh oh))')); 109 it('should desugar , angle', () => expect(desguar('<bd, hh>')).toEqual('(stack bd hh)')); 110 it('should desugar , angle 2', () => expect(desguar('<bd, hh oh>')).toEqual('(stack bd (angle hh oh))')); 111 it('should desugar , angle 3', () => 112 expect(desguar('<bd cp, hh oh>')).toEqual('(stack (angle bd cp) (angle hh oh))')); 113 it('should desugar , ()', () => expect(desguar('(s bd, s cp)')).toEqual('(stack (s bd) (s cp))')); 114 it('should desugar * /', () => expect(desguar('[a b*2 c d/3 e]')).toEqual('(square a (* 2 b) c (/ 3 d) e)')); 115 it('should desugar []*x', () => expect(desguar('[a [b c]*3]')).toEqual('(square a (* 3 (square b c)))')); 116 it('should desugar []*<x y>', () => expect(desguar('[a b*<2 3> c]')).toEqual('(square a (* (angle 2 3) b) c)')); 117 it('should desugar x:y', () => expect(desguar('x:y')).toEqual('(: y x)')); 118 it('should desugar x:y:z', () => expect(desguar('x:y:z')).toEqual('(: z (: y x))')); 119 it('should desugar x:y*x', () => expect(desguar('bd:0*2')).toEqual('(* 2 (: 0 bd))')); 120 it('should desugar x&y:z', () => expect(desguar('bd&3:8')).toEqual('(& (: 8 3) bd)')); 121 it('should desugar a..b', () => expect(desguar('0..2')).toEqual('(.. 2 0)')); 122 /* it('should desugar x $ y', () => expect(desguar('x $ y')).toEqual('(x y)')); 123 it('should desugar x $ y z', () => expect(desguar('x $ y z')).toEqual('(x (y z))')); 124 it('should desugar x $ y . z', () => expect(desguar('x $ y . z')).toEqual('(z (x y))')); */
126 it('should desugar README example', () => 127 expect(desguar('s [bd hh*2 (cp # crush 4) <mt ht lt>] # speed .8')).toEqual( 128 '(speed .8 (s (square bd (* 2 hh) (crush 4 cp) (angle mt ht lt))))', 129 )); 130 131 it('should desugar (#)', () => expect(desguar('(#)')).toEqual('(fn (_) _)')); 132 it('should desugar lambda', () => expect(desguar('(# fast 2)')).toEqual('(fn (_) (fast 2 _))')); 133 it('should desugar lambda call', () => expect(desguar('((# mul 2) 2)')).toEqual('((fn (_) (mul 2 _)) 2)')); 134 it('should desugar lambda with pipe', () => 135 expect(desguar('(# fast 2 # room 1)')).toEqual('(fn (_) (room 1 (fast 2 _)))')); 136 /* const lambda = parser.parse('(lambda (_) (fast 2 _))'); 137 const target = { type: 'plain', value: 'xyz' }; 138 it('should desugar_lambda', () => 139 expect(printAst(parser.desugar_lambda(lambda.children, target))).toEqual('(fast 2 xyz)')); */ 140}); 141 142describe('mondo arithmetic', () => { 143 let multi = 144 (op) => 145 (init, ...rest) => 146 rest.reduce((acc, arg) => op(acc, arg), init); 147 148 let lib = { 149 '+': multi((a, b) => a + b), 150 add: multi((a, b) => a + b), 151 '-': multi((a, b) => a - b), 152 sub: multi((a, b) => a - b), 153 '*': multi((a, b) => a * b), 154 '/': multi((a, b) => a / b), 155 mod: multi((a, b) => a % b), 156 eq: (a, b) => a === b, 157 lt: (a, b) => a < b, 158 gt: (a, b) => a > b, 159 and: (a, b) => a && b, 160 or: (a, b) => a || b, 161 not: (a) => !a, 162 run: (...args) => args[args.length - 1], 163 def: () => 0, 164 sin: Math.sin, 165 cos: Math.cos, 166 PI: Math.PI, 167 cons: (a, b) => [a, ...(Array.isArray(b) ? b : [b])], 168 car: (pair) => pair[0], 169 cdr: (pair) => pair.slice(1), 170 list: (...items) => items, 171 nil: [], 172 isnull: (items) => items.length === 0, 173 concat: (...msgs) => msgs.join(''), 174 error: (...msgs) => { 175 throw new Error(msgs.join(' ')); 176 }, 177 }; 178 function evaluator(node, scope) { 179 if (node.type !== 'list') { 180 // is leaf 181 return scope[node.value] ?? lib[node.value] ?? node.value; 182 } 183 // is list 184 const [fn, ...args] = node.children; 185 if (typeof fn !== 'function') { 186 throw new Error(`"${fn}": expected function, got ${typeof fn} "${fn}"`); 187 } 188 return fn(...args); 189 } 190 const runner = new MondoRunner({ evaluator }); 191 let evaluate = (exp, scope) => runner.run(`run ${exp}`, scope); 192 let pretty = (exp) => printAst(runner.parser.parse(exp), false); 193 //it('should eval nested expression', () => expect(runner.run('add 1 (mul 2 PI)').toFixed(2)).toEqual('7.28')); 194 195 it('eval number', () => expect(evaluate('2')).toEqual(2)); 196 it('eval string', () => expect(evaluate('abc')).toEqual('abc')); 197 it('eval list', () => expect(evaluate('(+ 1 2)')).toEqual(3)); 198 it('eval nested list', () => expect(evaluate('(+ 1 (+ 2 3))')).toEqual(6)); 199 it('def number', () => expect(evaluate('(def a 2) a')).toEqual(2)); 200 it('def + ref number', () => expect(evaluate('(def a 2) (* a a)')).toEqual(4)); 201 it('def + call lambda', () => expect(evaluate('(def sqr (fn (x) (* x x))) (sqr 3)')).toEqual(9));
sicp
204 it('sicp 8.1', () => expect(evaluate('(+ 137 349)')).toEqual(486)); 205 it('sicp 8.2', () => expect(evaluate('(- 1000 334)')).toEqual(666)); 206 it('sicp 8.3', () => expect(evaluate('(* 5 99)')).toEqual(495)); 207 it('sicp 8.4', () => expect(evaluate('(/ 10 5)')).toEqual(2)); 208 it('sicp 8.5', () => expect(evaluate('(+ 2.7 10)')).toEqual(12.7)); 209 it('sicp 9.1', () => expect(evaluate('(+ 21 35 12 7)')).toEqual(75)); 210 it('sicp 9.2', () => expect(evaluate('(* 25 4 12)')).toEqual(1200)); 211 it('sicp 9.3', () => expect(evaluate('(+ (* 3 5) (- 10 6))')).toEqual(19)); 212 it('sicp 9.4', () => 213 expect(pretty('(+ (* 3 (+ (* 2 4) (+ 3 5))) (+ (- 10 7) 6))')).toEqual(`(+ 214 (* 3 215 (+ 216 (* 2 4) 217 (+ 3 5) 218 ) 219 ) 220 (+ 221 (- 10 7) 6 222 ) 223)`)); // this is not exactly pretty printing by convention..
225 let scope = {}; 226 it('sicp 11.1', () => expect(evaluate('(def size 2) (* 5 size)', scope)).toEqual(10)); 227 it('sicp 11.2', () => 228 expect(evaluate('(def pi 3.14159) (def radius 10) (* pi (* radius radius))', scope)).toEqual(314.159)); 229 it('sicp 11.3', () => expect(evaluate('(def circumference (* 2 pi radius))', scope)).toEqual(0)); 230 it('sicp 11.4', () => expect(evaluate('circumference', scope)).toEqual(62.8318)); 231 it('sicp 13.1', () => expect(evaluate('(* (+ 2 (* 4 6)) (+ 3 5 7))')).toEqual(390)); 232 it('sicp 16.1', () => expect(evaluate('(def (square x) (* x x))', scope)).toEqual(0)); 233 // it('sicp 16.1', () => expect(evaluate('(def (square x) (* x x))', scope)).toEqual(0)); 234 it('sicp 17.1', () => expect(evaluate('(square 21)', scope)).toEqual(441)); 235 it('sicp 17.2', () => expect(evaluate('(square (+ 2 5))', scope)).toEqual(49)); 236 it('sicp 17.3', () => expect(evaluate('(square (square 3))', scope)).toEqual(81)); 237 it('sicp 17.4', () => expect(evaluate(`(def (sumofsquares x y) (+ (square x) (square y)))`, scope)).toEqual(0)); 238 it('sicp 17.5', () => expect(evaluate(`(sumofsquares 3 4)`, scope)).toEqual(25)); 239 it('sicp 17.6', () => expect(evaluate(`(def (f a) (sumofsquares (+ a 1) (* a 2))) (f 5)`, scope)).toEqual(136)); 240 it('sicp 21.1', () => expect(evaluate(`(sumofsquares (+ 5 1) (* 5 2))`, scope)).toEqual(136)); 241 242 it('sicp 22.1', () => 243 expect( 244 evaluate( 245 `(def (abs x) 246 (match 247 ((gt x 0) x) 248 ((eq x 0) 0) 249 ((lt x 0) (- 0 x)) 250 ))`, // sicp was doing (- x), which doesnt work with our - 251 scope, 252 ), 253 ).toEqual(0)); 254 255 it('sicp gt1', () => expect(evaluate(`(gt -12 0)`, scope)).toEqual(false)); 256 it('sicp gt2', () => expect(evaluate(`(gt 0 -12)`, scope)).toEqual(true)); 257 it('sicp lt1', () => expect(evaluate(`(lt -12 0)`, scope)).toEqual(true)); 258 it('sicp lt2', () => expect(evaluate(`(lt 0 -12)`, scope)).toEqual(false)); 259 260 it('sicp 24.1', () => expect(evaluate(`(abs (- 3))`, scope)).toEqual(3)); 261 it('sicp 24.2', () => expect(evaluate(`(abs (+ 3))`, scope)).toEqual(3)); 262 it('sicp 24.3', () => expect(evaluate(`(abs -12)`, scope)).toEqual(12)); 263 264 it('sicp 24.4', () => expect(evaluate(`(def (abs x) (if (lt x 0) (- 0 x) x))`, scope)).toEqual(0)); 265 it('sicp 24.5', () => expect(evaluate(`(abs -13)`, scope)).toEqual(13)); 266 it('sicp 25.1', () => expect(evaluate(`(and (gt 6 5) (lt 6 10))`, scope)).toEqual(true)); 267 it('sicp 25.2', () => expect(evaluate(`(and (gt 4 5) (lt 6 10))`, scope)).toEqual(false)); 268 269 it('sicp ex1.1.1', () => expect(evaluate(`(def a 3)`, scope)).toEqual(0)); 270 it('sicp ex1.1.2', () => expect(evaluate(`(def b (+ a 1))`, scope)).toEqual(0)); 271 it('sicp ex1.1.3', () => expect(evaluate(`(+ a b (* a b))`, scope)).toEqual(19)); 272 it('sicp ex1.1.4', () => expect(evaluate(`(if (and (gt b a) (lt b (* a b))) b a)`, scope)).toEqual(4)); 273 it('sicp ex1.1.5', () => expect(evaluate(`(match ((eq a 4) 6) ((eq b 4) (+ 6 7 a)) (else 25))`, scope)).toEqual(16)); 274 it('sicp ex1.1.6', () => expect(evaluate(`(+ 2 (if (gt b a) b a))`, scope)).toEqual(6)); 275 it('sicp ex1.1.7', () => 276 expect(evaluate(`(* (match ((gt a b) a) ((lt a b) b) (else -1)) (+ a 1))`, scope)).toEqual(16));
.. cant use "+" and "-" as standalone expressions, because they are parsed as operators...
1.1.7 Example: Square Roots by Newton’s Method
284 it('sicp 30.1', () => 285 expect(evaluate(`(def (goodenuf guess x) (lt (abs (- (square guess) x)) 0.001))`, scope)).toEqual(0)); 286 it('sicp 30.2', () => expect(evaluate(`(goodenuf 1 1.001)`, scope)).toEqual(true)); 287 it('sicp 30.3', () => expect(evaluate(`(goodenuf 1 1.002)`, scope)).toEqual(false)); 288 it('sicp 30.4', () => expect(evaluate(`(def (average x y) (/ (+ x y) 2))`, scope)).toEqual(0)); 289 it('sicp 30.5', () => expect(evaluate(`(average 18 20)`, scope)).toEqual(19)); 290 it('sicp 30.6', () => expect(evaluate(`(def (improve guess x) (average guess (/ x guess)))`, scope)).toEqual(0)); 291 it('sicp 31.1', () => 292 expect( 293 evaluate( 294 `(def (sqrtiter guess x) (if (goodenuf guess x) 295 guess 296 (sqrtiter (improve guess x) x)))`, 297 scope, 298 ), 299 ).toEqual(0)); 300 it('sicp 31.2', () => expect(evaluate(`(def (sqrt x) (sqrtiter 1.0 x))`, scope)).toEqual(0)); 301 it('sicp 31.3', () => expect(evaluate(`(sqrt 9)`, scope)).toEqual(3.00009155413138)); 302 it('sicp 31.4', () => expect(evaluate(`(sqrt (+ 100 37))`, scope)).toEqual(11.704699917758145)); 303 // eslint-disable-next-line no-loss-of-precision 304 it('sicp 31.5', () => expect(evaluate(`(sqrt (+ (sqrt 2) (sqrt 3)))`, scope)).toEqual(1.77392790232078925)); 305 it('sicp 31.6', () => expect(evaluate(`(square (sqrt 1000))`, scope)).toEqual(1000.000369924366));
lexical scoping
308 it('sicp 39.1', () => 309 expect( 310 evaluate( 311 ` 312(def (sqrt x) 313 (def (goodenough guess) 314 (lt (abs (- (square guess) x)) 0.001)) 315(def (improve guess) 316 (average guess (/ x guess))) 317(def (sqrt-iter guess) 318 (if (goodenough guess) guess (sqrt-iter (improve guess)))) 319(sqrtiter 1.0))
recursive fac
iterative fac
331 it('sicp 41.3', () => 332 expect( 333 evaluate( 334 ` 335(def (factorial n) (factiter 1 1 n)) 336(def (factiter product counter maxcount) 337 (if (gt counter maxcount) 338 product 339 (factiter (* counter product) 340 (+ counter 1) 341 maxcount))) 342`, 343 scope, 344 ), 345 ).toEqual(0)); 346 it('sicp 41.4', () => expect(evaluate(`(fac 4)`, scope)).toEqual(24));
46.1 (def (+ a b) (if (= a 0) b (inc (+ (dec a) b)))) (def (+ a b) (if (= a 0) b (+ (dec a) (inc b))))
Exercise 1.10 Ackermann’s function
356 it('sicp 47.1', () => 357 expect( 358 evaluate( 359 ` 360(def (A x y) (match ((eq y 0) 0) 361((eq x 0) (* 2 y)) 362((eq y 1) 2) 363(else (A (- x 1) (A x (- y 1)))))) 364`, 365 scope, 366 ), 367 ).toEqual(0)); 368 it('sicp 47.2', () => expect(evaluate(`(A 1 10)`, scope)).toEqual(1024)); 369 it('sicp 47.3', () => expect(evaluate(`(A 2 4)`, scope)).toEqual(65536)); 370 it('sicp 47.4', () => expect(evaluate(`(A 3 3)`, scope)).toEqual(65536)); 371 it('sicp 47.5', () => 372 expect( 373 evaluate( 374 ` 375(def (f n) (A 0 n)) 376(def (g n) (A 1 n))) 377(def (h n) (A 2 n)) 378(def (k n) (* 5 n n)) 379 `, 380 scope, 381 ), 382 ).toEqual(0));
Tree Recursion recursive process
iterative process
example: counting change
414 it('sicp 52.2', () => 415 expect( 416 evaluate( 417 ` 418(def (countchange amount) (cc amount 5)) 419(def (cc amount kindsofcoins) 420 (match 421 ((eq amount 0) 1) 422 ((or (lt amount 0) (eq kindsofcoins 0)) 0) 423 (else (+ 424 (cc amount (- kindsofcoins 1)) 425 (cc (- amount (firstdenomination kindsofcoins)) kindsofcoins)))))
todo: pascals triangle
exponentiation recursive
exponentiation iterative
exponentiation fast
- = repeated addition
gcd / euclid
65 smallest divisor 67 fermat test ....
higher order procedures
543 it('sicp 78.1', () => 544 expect( 545 evaluate( 546 ` 547(def (inc n) (+ n 1)) 548(def (cube a) (* a a a)) 549(def (sumcubes a b) 550(sum cube a inc b)) 551(sumcubes 1 10) 552 `, 553 scope, 554 ), 555 ).toEqual(3025)); 556 557 it('sicp 78.2', () => 558 expect( 559 evaluate( 560 ` 561 (def (identity x) x) 562 (def (sumintegers a b) 563 (sum identity a inc b)) 564 (sumintegers 1 10) 565 `, 566 scope, 567 ), 568 ).toEqual(55));
pisum
integral
587 it('sicp 79.2', () => 588 expect( 589 evaluate( 590 ` 591(def (integral f a b dx) 592 (def (adddx x) (+ x dx)) 593(* (sum f (+ a (/ dx 2.0)) adddx b) dx)) 594(integral cube 0 1 0.01) 595 `, 596 scope, 597 ), 598 ).toEqual(0.24998750000000042)); 599 // maximum callstack... 600 //it('sicp 79.3', () => expect(evaluate(`(integral cube 0 1 0.001)`, scope)).toEqual(0.249999875000001));
lambdas
603 it('sicp 83.1', () => expect(evaluate(`((fn (x) (+ x 4)) 5)`)).toEqual(9));
605 it('sicp 83.2', () => 606 expect( 607 evaluate( 608 ` 609(def (pisum a b) 610 (sum (fn (x) (/ 1.0 (* x (+ x 2)))) 611 a 612 (fn (x) (+ x 4)) 613 b)) 614(* 8 (pisum 1 1000)) 615`, 616 scope, 617 ), 618 ).toEqual(3.139592655589783)); 619 it('sicp 83.3', () => 620 expect( 621 evaluate( 622 ` 623(def (integral f a b dx) 624 (* (sum f 625 (+ a (/ dx 2.0)) 626 (fn (x) (+ x dx)) 627 b) 628 dx)) 629(integral cube 0 1 0.01) 630`, 631 scope, 632 ), 633 ).toEqual(0.24998750000000042)); 634 it('sicp 84.1', () => expect(evaluate(`((fn (x y z) (+ x y (square z))) 1 2 3)`, scope)).toEqual(12));
let expressions
637 it('sicp 87.1', () => 638 expect( 639 evaluate( 640 ` 641(+ (let ((x 3)) 642(+ x (* x 10))) x) 643`, 644 { x: 5 }, 645 ), 646 ).toEqual(38)); 647 it('sicp 87.2', () => 648 expect( 649 evaluate( 650 ` 651(let ((x 3) 652(y (+ x 2))) 653(* x y)) 654 `, 655 { x: 2 }, 656 ), 657 ).toEqual(12)); 658 it('sicp 88.1', () => 659 expect( 660 evaluate( 661 ` 662(def (f g) (g 2)) 663(f square) 664 `, 665 scope, 666 ), 667 ).toEqual(4)); 668 it('sicp 88.2', () => 669 expect( 670 evaluate( 671 ` 672 (def (f g) (g 2)) 673 (f (fn (z) (* z (+ z 1)))) 674 `, 675 scope, 676 ), 677 ).toEqual(6));
Finding roots of equations by the half-interval method
680 it('sicp 89.1', () => 681 expect( 682 evaluate( 683 ` 684(def (search f negpoint pospoint) 685 (let ((midpoint (average negpoint pospoint))) 686 (if (closeenough negpoint pospoint) 687 midpoint 688 (let ((testvalue (f midpoint))) 689 (match ((positive testvalue) 690 (search f negpoint midpoint)) 691 ((negative testvalue) 692 (search f midpoint pospoint)) 693 (else midpoint))))))
695(def (closeenough x y) (lt (abs (- x y)) 0.001)) 696 697(def (negative x) (lt x 0)) 698(def (positive x) (gt x 0)) 699 700(def (halfintervalmethod f a b) (let ((avalue (f a)) 701(bvalue (f b))) 702(match ((and (negative avalue) (positive bvalue)) 703(search f a b)) 704((and (negative bvalue) (positive avalue)) 705(search f b a)) (else 706(error "Values are not of opposite sign" a b))))) 707 708(halfintervalmethod sin 2.0 4.0) 709`, 710 scope, 711 ), 712 ).toEqual(3.14111328125)); 713 714 it('sicp 89.1', () => 715 expect(evaluate(`(halfintervalmethod (fn (x) (- (* x x x) (* 2 x) 3)) 1.0 2.0)`, scope)).toEqual(1.89306640625));
Finding fixed points of functions
718 it('sicp 92.1', () => 719 expect( 720 evaluate( 721 ` 722(def tolerance 0.00001) 723(def (fixedpoint f first-guess) 724 (def (closeenough v1 v2) (lt (abs (- v1 v2)) tolerance)) 725 (def (try guess) 726 (let ((next (f guess))) 727 (if (closeenough guess next) next (try next)))) 728 (try first-guess))
730(fixedpoint cos 1.0) 731`, 732 scope, 733 ), 734 ).toEqual(0.7390822985224023)); 735 it('sicp 93.1', () => 736 expect(evaluate(`(fixedpoint (fn (y) (+ (sin y) (cos y))) 1.0)`, scope)).toEqual(1.2587315962971173)); 737 // Maximum call stack size exceeded (expected) 738 /* it('sicp 93.2', () => 739 expect(evaluate(`(def (sqrt x) (fixedpoint (fn (y) (/ x y)) 1.0)) (sqrt 4)`, scope)).toEqual(0)); */ 740 it('sicp 93.3', () => 741 expect(evaluate(`(def (sqrt x) (fixedpoint (fn (y) (average y (/ x y))) 1.0)) (sqrt 7)`, scope)).toEqual( 742 2.6457513110645907, 743 )); 744 // Procedures as Returned Values 745 it('sicp 97.1', () => 746 expect(evaluate(`(def (averagedamp f) (fn (x) (average x (f x)))) ((averagedamp square) 10)`, scope)).toEqual(55)); 747 it('sicp 98.1', () => 748 expect(evaluate(`(def (sqrt x) (fixedpoint (averagedamp (fn (y) (/ x y))) 1.0)) (sqrt 7)`, scope)).toEqual( 749 2.6457513110645907, 750 )); 751 it('sicp 98.2', () => 752 expect( 753 evaluate(`(def (cuberoot x) (fixedpoint (averagedamp (fn (y) (/ x (square y)))) 1.0)) (cuberoot 7)`, scope), 754 ).toEqual(1.912934258514886)); 755 it('sicp 99.1', () => 756 expect( 757 evaluate( 758 ` 759 (def (deriv g) (fn (x) (/ (- (g (+ x dx)) (g x)) dx))) 760 (def dx 0.00001) 761 (def (cube x) (* x x x)) 762 ((deriv cube) 5) 763 `, 764 scope, 765 ), 766 ).toEqual(75.00014999664018)); 767 // With the aid of deriv, we can express Newton’s method as a fixed-point process: 768 it('sicp 100.1', () => 769 expect( 770 evaluate( 771 ` 772(def (newtontransform g) 773(fn (x) (- x (/ (g x) ((deriv g) x))))) 774(def (newtonsmethod g guess) (fixedpoint (newtontransform g) guess)) 775(def (sqrt x) (newtonsmethod (fn (y) (- (square y) x)) 1.0)) 776(sqrt 7) 777 `, 778 scope, 779 ), 780 ).toEqual(2.6457513110645907)); 781 // whatever this is 782 it('sicp 101.1', () => 783 expect( 784 evaluate( 785 ` 786 (def (fixedpointoftransform g transform guess) (fixedpoint (transform g) guess)) 787 (def (sqrt x) (fixedpointoftransform 788 (fn (y) (/ x y)) averagedamp 1.0)) 789 (sqrt 7) 790 `, 791 scope, 792 ), 793 ).toEqual(2.6457513110645907)); 794 it('sicp 101.2', () => 795 expect( 796 evaluate( 797 ` 798(def (sqrt x) (fixedpointoftransform 799(fn (y) (- (square y) x)) newtontransform 1.0)) 800(sqrt 7) 801 `, 802 scope, 803 ), 804 ).toEqual(2.6457513110645907));
data abstraction
rational arithmetic
809 it('sicp 114.1', () => 810 expect( 811 evaluate( 812 ` 813(def (addrat x y) 814 (makerat (+ (* 815 (numer x) (denom y)) 816 (* (numer y) (denom x))) 817 (* (denom x) (denom y)))) 818(def (subrat x y) 819 (makerat (- (* (numer x) (denom y)) 820 (* (numer y) (denom x))) 821 (* (denom x) (denom y)))) 822(def (mulrat x y) 823 (makerat (* (numer x) (numer y)) 824 (* (denom x) (denom y)))) 825(def (divrat x y) 826 (makerat (* (numer x) (denom y)) 827 (* (denom x) (numer y)))) 828(def (equalrat x y) 829 (eq (* (numer x) (denom y)) 830 (* (numer y) (denom x)))) 831 `, 832 scope, 833 ), 834 ).toEqual(0));
markerat number denom
850 it('sicp 117.1', () => expect(evaluate(`(def onehalf (makerat 1 2)) (printrat onehalf)`, scope)).toEqual('1:2')); 851 it('sicp 117.2', () => 852 expect(evaluate(`(def onethird (makerat 1 3)) (printrat (addrat onehalf onethird))`, scope)).toEqual('5:6')); 853 it('sicp 117.3', () => expect(evaluate(`(printrat (mulrat onehalf onethird))`, scope)).toEqual('1:6')); 854 it('sicp 117.4', () => expect(evaluate(`(printrat (addrat onethird onethird))`, scope)).toEqual('6:9')); 855 it('sicp 118.1', () => 856 expect(evaluate(`(def (makerat n d) (let ((g (gcd n d))) (cons (/ n g) (/ d g))))`, scope)).toEqual(0)); 857 it('sicp 118.1', () => expect(evaluate(`(printrat (addrat onethird onethird))`, scope)).toEqual('2:3')); 858 859 let lscope = {}; 860 // pairs with lambda 861 it('sicp 124.1', () => 862 expect( 863 evaluate( 864 ` 865(def (cons x y) 866 (def (dispatch m) 867 (match 868 ((eq m 0) x) 869 ((eq m 1) y) 870 (else (error "argument not 0 or 1: CONS" m))) 871 ) dispatch) 872 (def (car z) (z 0)) 873 (def (cdr z) (z 1)) 874 `, 875 lscope, 876 ), 877 ).toEqual(0)); 878 it('sicp 124.1', () => expect(evaluate(`(car (cons first second))`, lscope)).toEqual('first')); 879 it('sicp 124.2', () => expect(evaluate(`(cdr (cons first second))`, lscope)).toEqual('second')); 880 // lists 881 it('sicp 135.1', () => expect(evaluate(`(list 1 2 3 4)`)).toEqual([1, 2, 3, 4])); 882 it('sicp 137.1', () => expect(evaluate(`(car (list 1 2 3 4))`)).toEqual(1)); 883 it('sicp 137.2', () => expect(evaluate(`(cdr (list 1 2 3 4))`)).toEqual([2, 3, 4])); 884 it('sicp 137.3', () => expect(evaluate(`(car (cdr (list 1 2 3 4)))`)).toEqual(2)); 885 it('sicp 137.4', () => expect(evaluate(`(cons 10 (list 1 2 3 4))`)).toEqual([10, 1, 2, 3, 4])); 886 // listref 887 it('sicp 138.1', () => 888 expect( 889 evaluate( 890 ` 891(def (listref items n) (if (eq n 0) (car items) 892 (listref (cdr items) (- n 1)))) 893(def squares (list 1 4 9 16 25)) 894(listref squares 3)`, 895 scope, 896 ), 897 ).toEqual(16)); 898 // length recursive 899 it('sicp 138.2', () => 900 expect( 901 evaluate( 902 ` 903 (def (length items) 904 (if (isnull items) 0 905 (+ 1 (length (cdr items))))) 906 (def odds (list 1 3 5 7)) 907 (length odds)`, 908 ), 909 ).toEqual(4)); 910 // length iterative 911 it('sicp 139.1', () => 912 expect( 913 evaluate( 914 ` 915 (def (length items) 916 (def (lengthiter a count) 917 (if (isnull a) count 918 (lengthiter (cdr a) (+ 1 count)))) 919 (lengthiter items 0)) 920 (def odds (list 1 3 5 7)) 921 (length odds) 922 `, 923 scope, 924 ), 925 ).toEqual(4)); 926 // append 927 it('sicp 139.1', () => 928 expect( 929 evaluate( 930 ` 931(def (append list1 list2) 932(if (isnull list1) 933 list2 934 (cons (car list1) (append (cdr list1) list2)))) 935 (append squares odds) 936 `, 937 scope, 938 ), 939 ).toEqual([1, 4, 9, 16, 25, 1, 3, 5, 7])); 940 // (define (f x y . z) ⟨body⟩) <- tbd: variable argument count 941 // Mapping over lists 942 943 it('sicp 143.1', () => 944 expect( 945 evaluate( 946 ` 947(def (scalelist items factor) (if (isnull items) nil 948 (cons (* (car items) factor) 949 (scalelist (cdr items) factor)))) 950(scalelist (list 1 2 3 4 5) 10) 951 `, 952 scope, 953 ), 954 ).toEqual([10, 20, 30, 40, 50])); 955 956 it('sicp 143.1', () => 957 expect( 958 evaluate( 959 ` 960 (def (map proc items) (if (isnull items) nil 961 (cons (proc (car items)) 962 (map proc (cdr items))))) 963 (map abs (list -10 2.5 -11.6 17)) 964 `, 965 scope, 966 ), 967 ).toEqual([10, 2.5, 11.6, 17])); 968 it('sicp 143.1', () => expect(evaluate(`(map (fn (x) (* x x)) (list 1 2 3 4))`, scope)).toEqual([1, 4, 9, 16])); 969 it('sicp 143.1', () => 970 expect( 971 evaluate( 972 ` 973(def (scalelist items factor) (map (fn (x) (* x factor)) items)) 974(scalelist (list 1 2 3 4 5) 10) 975`, 976 scope, 977 ), 978 ).toEqual([10, 20, 30, 40, 50])); 979});