helpful.body.scm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. (define (value->procedure val)
  2. (lambda () val))
  3. (define (list->procedure l)
  4. (lambda (i)
  5. (list-ref l i)))
  6. (define (vector->procedure v)
  7. (lambda (i)
  8. (vector-ref v i)))
  9. (define (string->procedure s)
  10. (lambda (i)
  11. (string-ref s i)))
  12. (define (assq->procedure al)
  13. (lambda (key)
  14. (cdr (assq key al))))
  15. (define (assv->procedure al)
  16. (lambda (key)
  17. (cdr (assv key al))))
  18. (define (assoc->procedure al)
  19. (lambda (key)
  20. (cdr (assoc key al))))
  21. (define (assq-ref al k)
  22. (cdr (assq k al)))
  23. (define (assv-ref al k)
  24. (cdr (assv k al)))
  25. (define (assoc-ref al k)
  26. (cdr (assoc k al)))
  27. (define (print . l)
  28. (for-each display l)
  29. (newline))
  30. (define (each-assoc key alist op)
  31. ;; helper for memoize -- generic assoc for list keys
  32. (if (null? alist)
  33. #f
  34. (if (and (= (length key) (length (caar alist)))
  35. (let loop ((alist-key-in (caar alist))
  36. (input-key-in key))
  37. (cond
  38. ((null? alist-key-in)
  39. #t)
  40. ((op (car alist-key-in) (car input-key-in))
  41. (loop (cdr alist-key-in)
  42. (cdr input-key-in)))
  43. (else
  44. #f))))
  45. (car alist)
  46. (each-assoc key (cdr alist) op))))
  47. (define-syntax memoize
  48. (syntax-rules ()
  49. ((_ op proc)
  50. (let ((cache '()))
  51. (lambda args
  52. (let ((cache-reference (each-assoc args cache op)))
  53. (if cache-reference
  54. (cadr cache-reference)
  55. (let ((result (apply proc args)))
  56. (set! cache (cons (list args result) cache))
  57. result))))))))
  58. (define-syntax memoize-testing
  59. (syntax-rules ()
  60. ((_ op proc)
  61. (let ((cache '()))
  62. (lambda args
  63. (write cache)
  64. (newline)
  65. (let ((cache-reference (each-assoc args cache op)))
  66. (if cache-reference
  67. (cadr cache-reference)
  68. (let ((result (apply proc args)))
  69. (set! cache (cons (list args result) cache))
  70. result))))))))
  71. (define (atom? val)
  72. (not (or (null? val) (pair? val))))
  73. (define (flatten l)
  74. (cond
  75. ((list? l) (apply append (map flatten l)))
  76. (else (list l))))
  77. (define (pair-conjugate p)
  78. (cons (cdr p) (car p)))
  79. (define (complex-conjugate c)
  80. (+ (real-part c) (* 0-i (imag-part c))))
  81. (define (integer->hex n)
  82. (define hex-selection
  83. (assv->procedure
  84. '((0 . #\0) (1 . #\1) (2 . #\2) (3 . #\3) (4 . #\4)
  85. (5 . #\5) (6 . #\6) (7 . #\7) (8 . #\8) (9 . #\9)
  86. (10 . #\a) (11 . #\b) (12 . #\c) (13 . #\d)
  87. (14 . #\e) (15 . #\f))))
  88. (define (build-hex next-num previous-list)
  89. (cons (hex-selection (modulo next-num 16))
  90. previous-list))
  91. (when (or (negative? n) (not (integer? n)))
  92. (error "integer->hex" "Non-negative integer expected"))
  93. (let loop ((in n) (out '()))
  94. (if (= in 0)
  95. (list->string out)
  96. (loop (quotient in 16)
  97. (build-hex in out)))))
  98. (define (integer->bin n)
  99. (define (build-bin next-num previous-list)
  100. (cons (if (even? next-num) #\0 #\1)
  101. previous-list))
  102. (when (or (negative? n) (not (integer? n)))
  103. (error "integer->bin" "Non-negative integer expected"))
  104. (let loop ((in n) (out '()))
  105. (if (= in 0)
  106. (if (null? out)
  107. "0"
  108. (list->string out))
  109. (loop (quotient in 2)
  110. (build-bin in out)))))
  111. (define (hex->integer h)
  112. (define hex-deselection
  113. (assv->procedure
  114. '((#\0 . 0) (#\1 . 1) (#\2 . 2) (#\3 . 3) (#\4 . 4)
  115. (#\5 . 5) (#\6 . 6) (#\7 . 7) (#\8 . 8) (#\9 . 9)
  116. (#\a . 10) (#\b . 11) (#\c . 12) (#\d . 13)
  117. (#\e . 14) (#\f . 15))))
  118. (define (debuild-hex next-char previous-num)
  119. (+ (hex-deselection (char-downcase next-char))
  120. (* 16 previous-num)))
  121. (let loop ((in (string->list h)) (out 0))
  122. (if (null? in)
  123. out
  124. (loop (cdr in)
  125. (debuild-hex (car in) out)))))
  126. (define (bin->integer b)
  127. (define (debuild-bin next-char previous-num)
  128. (+ (if (eqv? next-char #\0) 0 1)
  129. (* previous-num 2)))
  130. (let loop ((in (string->list b)) (out 0))
  131. (if (null? in)
  132. out
  133. (loop (cdr in)
  134. (debuild-bin (car in) out)))))
  135. (define (bin->hex b)
  136. (integer->hex (bin->integer b)))
  137. (define (hex->bin h)
  138. (integer->bin (hex->integer h)))
  139. (define (pad-string-helper input-string desired-size padding-char left?)
  140. (let ((actual-size (string-length input-string)))
  141. (if (< actual-size desired-size)
  142. (if left?
  143. (string-append (make-string (- desired-size actual-size)
  144. padding-char)
  145. input-string)
  146. (string-append input-string
  147. (make-string (- desired-size actual-size)
  148. padding-char)))
  149. input-string)))
  150. (define pad-left
  151. (case-lambda
  152. ((st sz)
  153. (pad-string-helper st sz #\space #t))
  154. ((st sz chr)
  155. (pad-string-helper st sz chr #t))))
  156. (define pad-right
  157. (case-lambda
  158. ((st sz)
  159. (pad-string-helper st sz #\space #f))
  160. ((st sz chr)
  161. (pad-string-helper st sz chr #f))))
  162. (define (color-string->triplet cs)
  163. (define (select-one-hex n)
  164. (hex->integer (string (string-ref cs n)
  165. (string-ref cs n))))
  166. (define (select-two-hexes n)
  167. (hex->integer (string (string-ref cs n)
  168. (string-ref cs (+ n 1)))))
  169. (cond
  170. ((= (string-length cs) 3)
  171. (list (select-one-hex 0)
  172. (select-one-hex 1)
  173. (select-one-hex 2)))
  174. ((= (string-length cs) 6)
  175. (list (select-two-hexes 0)
  176. (select-two-hexes 2)
  177. (select-two-hexes 4)))
  178. (else
  179. (error "color-string->triplet" "String must be of length 3 or 6" cs))))
  180. (define (triplet->color-string trip)
  181. (unless (and (= (length trip) 3)
  182. (<= 0 (list-ref trip 0) 255)
  183. (<= 0 (list-ref trip 1) 255)
  184. (<= 0 (list-ref trip 2) 255)
  185. (integer? (list-ref trip 0))
  186. (integer? (list-ref trip 1))
  187. (integer? (list-ref trip 2)))
  188. (error "triplet->color-string"
  189. "Argument must be a triplet of integers 0 to 255" trip))
  190. (apply string-append (map (lambda (n)
  191. (pad-left (integer->hex n) 2 #\0))
  192. trip)))
  193. (define (test-for-each? proc l . rest)
  194. (let ((test-result (apply map proc l rest)))
  195. (not (memv #f test-result))))
  196. (define (properize p)
  197. (if (pair? (cdr p))
  198. (cons (car p) (properize (cdr p)))
  199. (list (car p) (cdr p))))
  200. (define (improperize p)
  201. (if (pair? (cddr p))
  202. (cons (car p) (improperize (cdr p)))
  203. (cons (car p) (cadr p))))
  204. (define-syntax assert
  205. (syntax-rules ()
  206. ((_ expr)
  207. (unless expr
  208. (error "Assertion failed" 'expr)))))
  209. (define-syntax logging
  210. (syntax-rules ()
  211. ((_ (expr ...))
  212. (begin
  213. (display "LOGGING: ")
  214. (write '(expr ...))
  215. (newline)))
  216. ((_ expr)
  217. (begin
  218. (display "LOGGING: ")
  219. (write 'expr)
  220. (display " = ")
  221. (write expr)
  222. (newline)))
  223. ((_ expr rest ...)
  224. (begin
  225. (logging expr)
  226. (logging rest ...)))))
  227. (define (read-entire-file path)
  228. (define p (open-input-file path))
  229. (let loop ((out '())
  230. (next-char (read-char p)))
  231. (if (eof-object? next-char)
  232. (let ((result (list->string (reverse out))))
  233. (close-input-port p)
  234. result)
  235. (loop (cons next-char out)
  236. (read-char p)))))
  237. (define (join joiner proc a b)
  238. (define (join-on-b a-val)
  239. (let loop ((out '())
  240. (in b))
  241. (if (null? in)
  242. (reverse out)
  243. (loop (if (proc a-val (car in))
  244. (cons (joiner a-val (car in))
  245. out)
  246. out)
  247. (cdr in)))))
  248. (apply append (map join-on-b a)))
  249. (define (op-table proc a b)
  250. (map (lambda (aa)
  251. (map (lambda (bb)
  252. (proc aa bb))
  253. b))
  254. a))
  255. (define (snoc rest new-last)
  256. (append rest (list new-last)))
  257. (define (combine2 joiner l1 l2)
  258. (apply append
  259. (map (lambda (x)
  260. (map (lambda (y)
  261. (joiner x y)) l2)) l1)))
  262. (define (combine . l)
  263. (reduce (lambda (l1 l2)
  264. (combine2 append l1 l2))
  265. '()
  266. l))
  267. (define (symbol-list->string sl)
  268. (apply string-append (map symbol->string sl)))
  269. (define (curry proc)
  270. (lambda (a) (lambda b (apply proc (cons a b)))))
  271. (define (uncurry proc)
  272. (lambda b (apply (proc (car b)) (cdr b))))
  273. (define (papply proc . values)
  274. (lambda args (apply proc (append values args))))
  275. (define left-papply papply)
  276. (define (right-papply proc . values)
  277. (lambda args (apply proc (append args values))))
  278. (define (pmap proc . args)
  279. (papply map (apply papply proc args)))
  280. (define (list-set l i value)
  281. (let loop ((front '())
  282. (back l)
  283. (count 0))
  284. (if (< count i)
  285. (loop (cons (car back) front)
  286. (cdr back)
  287. (+ count 1))
  288. (append (reverse front)
  289. (list value)
  290. (cdr back)))))
  291. (define (concordance test l)
  292. (define (update-concordance test value l)
  293. (define (find-index)
  294. (let loop ((in l) (out 0))
  295. (if (null? in)
  296. (values #f #f)
  297. (if (test (caar in) value)
  298. (values out (car in))
  299. (loop (cdr in) (+ out 1))))))
  300. (define-values (index found-concordance)
  301. (find-index))
  302. (if index
  303. (list-set l index (cons (car found-concordance)
  304. (cons value (cdr found-concordance))))
  305. (cons (list value) l)))
  306. (let loop ((in l) (out '()))
  307. (if (null? in)
  308. (reverse (map (lambda (l) (cons (car l) (length l))) out))
  309. (loop (cdr in) (update-concordance test (car in) out)))))
  310. (define (concord= l) (concordance = l))
  311. (define (concordq l) (concordance eq? l))
  312. (define (concordv l) (concordance eqv? l))
  313. (define (structure-apply to-list)
  314. (lambda (proc arg1 . arg-rest)
  315. (define args (cons arg1 arg-rest))
  316. (let loop ((back args) (front '()))
  317. (if (null? (cdr back))
  318. (apply proc (append (reverse front) (to-list (car back))))
  319. (loop (cdr back) (cons (car back) front))))))
  320. (define vector-apply (structure-apply vector->list))
  321. (define string-apply (structure-apply string->list))
  322. (define (fractional-to-fixed inexact-num digits)
  323. ;; helper for to-fixed
  324. ;; assumes that digits is at least 1
  325. (define num (exact inexact-num))
  326. (define (fetch-digit num place)
  327. (integer->char (+ 48 (modulo (floor (/ num place)) 10))))
  328. (define (rounded-fraction frac-part)
  329. (exact (/ (round (* frac-part (expt 10 digits))) (expt 10 digits))))
  330. (define integral-part (exact (floor num)))
  331. (define fractional-part (rounded-fraction (- num integral-part)))
  332. (if (= 1 fractional-part)
  333. (fractional-to-fixed (+ integral-part 1) digits)
  334. (let loop ((result '(#\.))
  335. (count 0)
  336. (place 1/10))
  337. (if (< count digits)
  338. (loop (cons (fetch-digit fractional-part place) result)
  339. (+ count 1)
  340. (/ place 10))
  341. (string-append (number->string integral-part)
  342. (list->string (reverse result)))))))
  343. (define (to-fixed num digits)
  344. ;; digits must be between 0 and 30
  345. (cond
  346. ((= digits 0)
  347. (number->string (exact (round num))))
  348. ((<= 1 digits 30)
  349. (fractional-to-fixed num digits))
  350. (else
  351. (error "to-fixed" "digits must be between 0 and 30 inclusive"))))
  352. (define (order-of-magnitude num)
  353. (exact (floor (/ (log num) (log 10)))))
  354. (define (to-exponential-with-digits num digits)
  355. (define oom (order-of-magnitude num))
  356. (define coefficient (/ num (expt 10 oom)))
  357. (define rounded-coefficient
  358. (exact (/ (round (* (expt 10 digits) coefficient)) (expt 10 digits))))
  359. (define corrected-coefficient
  360. ;; this is necessary in case the number rounded up
  361. (if (>= rounded-coefficient 10)
  362. (/ rounded-coefficient 10)
  363. coefficient))
  364. (define corrected-oom
  365. (if (>= rounded-coefficient 10)
  366. (+ oom 1)
  367. oom))
  368. (string-append
  369. (fractional-to-fixed corrected-coefficient digits)
  370. "e"
  371. (number->string corrected-oom)))
  372. (define (to-exponential-with-digits-check-digits num digits)
  373. ;; digits must be between 0 and 30
  374. (cond
  375. ((<= 0 digits 30)
  376. (to-exponential-with-digits num digits))
  377. (else
  378. (error "to-exponential" "digits must be between 0 and 30 inclusive"))))
  379. (define (to-exponential-without-digits num)
  380. (define oom (order-of-magnitude num))
  381. (define coefficient (inexact (/ num (expt 10 oom))))
  382. (string-append
  383. (number->string coefficient)
  384. "e"
  385. (number->string oom)))
  386. (define to-exponential
  387. (case-lambda
  388. ((num) (to-exponential-without-digits num))
  389. ((num digits) (to-exponential-with-digits-check-digits num digits))))
  390. (define (pipe init . args)
  391. ;; evaluate init by a sequence of procedures
  392. ;; most useful in conjunction with papply
  393. (let loop ((result init)
  394. (procs args))
  395. (if (null? procs)
  396. result
  397. (loop ((car procs) result)
  398. (cdr procs)))))
  399. (define (list-split pred? l)
  400. (let loop ((in l)
  401. (out '(())))
  402. (if (null? in)
  403. (reverse (cons (reverse (car out)) (cdr out)))
  404. (loop (cdr in)
  405. (if (pred? (car in))
  406. (cons '() (cons (reverse (car out)) (cdr out)))
  407. (cons (cons (car in) (car out))
  408. (cdr out)))))))
  409. (define (string-split pred? s)
  410. (map list->string (list-split pred? (string->list s))))
  411. (define (iden p) p)
  412. (define (inc n) (+ n 1))
  413. (define (dec n) (- n 1))
  414. (define (alist-mapper symbol-map)
  415. (lambda (obj)
  416. (apply append
  417. (map (lambda (kvp)
  418. (let ((from (car kvp))
  419. (to (cdr kvp)))
  420. (let ((from-pair (assq from obj)))
  421. (if from-pair
  422. (list (cons to (cdr from-pair)))
  423. '()))))
  424. symbol-map))))
  425. (define (repeated op n)
  426. (unless (and (integer? n)
  427. (>= n 0))
  428. (error "Expected a non-negative integer but got" n))
  429. (lambda (init)
  430. (let loop ((i n)
  431. (v init))
  432. (if (= i 0)
  433. v
  434. (loop (- i 1)
  435. (op v))))))