srfi-42.test 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. ;;; -*- mode: scheme; coding: utf-8; -*-
  2. ;;; Examples for Eager Comprehensions in [outer..inner|expr]-Convention
  3. ;;; ===================================================================
  4. ;;;
  5. ;;; Copyright (C) 2010, 2012 Free Software Foundation, Inc.
  6. ;;; Copyright (c) 2007 Sebastian Egner
  7. ;;;
  8. ;;; This code is based on the file examples.scm in the reference
  9. ;;; implementation of SRFI-42, provided under the following license:
  10. ;;;
  11. ;;; Permission is hereby granted, free of charge, to any person obtaining
  12. ;;; a copy of this software and associated documentation files (the
  13. ;;; ``Software''), to deal in the Software without restriction, including
  14. ;;; without limitation the rights to use, copy, modify, merge, publish,
  15. ;;; distribute, sublicense, and/or sell copies of the Software, and to
  16. ;;; permit persons to whom the Software is furnished to do so, subject to
  17. ;;; the following conditions:
  18. ;;;
  19. ;;; The above copyright notice and this permission notice shall be
  20. ;;; included in all copies or substantial portions of the Software.
  21. ;;;
  22. ;;; THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
  23. ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  24. ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  25. ;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  26. ;;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  27. ;;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  28. ;;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29. ;;;
  30. (define-module (test-srfi-42)
  31. #:use-module (test-suite lib)
  32. #:use-module (srfi srfi-42))
  33. ; Tools for checking results
  34. ; ==========================
  35. (define (my-equal? x y)
  36. (cond
  37. ((or (boolean? x)
  38. (null? x)
  39. (symbol? x)
  40. (char? x)
  41. (input-port? x)
  42. (output-port? x) )
  43. (eqv? x y) )
  44. ((string? x)
  45. (and (string? y) (string=? x y)) )
  46. ((vector? x)
  47. (and (vector? y)
  48. (my-equal? (vector->list x) (vector->list y)) ))
  49. ((pair? x)
  50. (and (pair? y)
  51. (my-equal? (car x) (car y))
  52. (my-equal? (cdr x) (cdr y)) ))
  53. ((real? x)
  54. (and (real? y)
  55. (eqv? (exact? x) (exact? y))
  56. (if (exact? x)
  57. (= x y)
  58. (< (abs (- x y)) (/ 1 (expt 10 6))) ))) ; will do here
  59. (else
  60. (error "unrecognized type" x) )))
  61. (define-syntax my-check
  62. (syntax-rules (=>)
  63. ((my-check ec => desired-result)
  64. (pass-if (my-equal? ec desired-result)))))
  65. (define my-call-with-input-file call-with-input-file)
  66. (define my-open-output-file open-output-file)
  67. ; ==========================================================================
  68. ; do-ec
  69. ; ==========================================================================
  70. (my-check
  71. (let ((x 0)) (do-ec (set! x (+ x 1))) x)
  72. => 1)
  73. (my-check
  74. (let ((x 0)) (do-ec (:range i 10) (set! x (+ x 1))) x)
  75. => 10)
  76. (my-check
  77. (let ((x 0)) (do-ec (:range n 10) (:range k n) (set! x (+ x 1))) x)
  78. => 45)
  79. ; ==========================================================================
  80. ; list-ec and basic qualifiers
  81. ; ==========================================================================
  82. (my-check (list-ec 1) => '(1))
  83. (my-check (list-ec (:range i 4) i) => '(0 1 2 3))
  84. (my-check (list-ec (:range n 3) (:range k (+ n 1)) (list n k))
  85. => '((0 0) (1 0) (1 1) (2 0) (2 1) (2 2)) )
  86. (my-check
  87. (list-ec (:range n 5) (if (even? n)) (:range k (+ n 1)) (list n k))
  88. => '((0 0) (2 0) (2 1) (2 2) (4 0) (4 1) (4 2) (4 3) (4 4)) )
  89. (my-check
  90. (list-ec (:range n 5) (not (even? n)) (:range k (+ n 1)) (list n k))
  91. => '((1 0) (1 1) (3 0) (3 1) (3 2) (3 3)) )
  92. (my-check
  93. (list-ec (:range n 5)
  94. (and (even? n) (> n 2))
  95. (:range k (+ n 1))
  96. (list n k) )
  97. => '((4 0) (4 1) (4 2) (4 3) (4 4)) )
  98. (my-check
  99. (list-ec (:range n 5)
  100. (or (even? n) (> n 3))
  101. (:range k (+ n 1))
  102. (list n k) )
  103. => '((0 0) (2 0) (2 1) (2 2) (4 0) (4 1) (4 2) (4 3) (4 4)) )
  104. (my-check
  105. (let ((x 0)) (list-ec (:range n 10) (begin (set! x (+ x 1))) n) x)
  106. => 10 )
  107. (my-check
  108. (list-ec (nested (:range n 3) (:range k n)) k)
  109. => '(0 0 1) )
  110. ; ==========================================================================
  111. ; Other comprehensions
  112. ; ==========================================================================
  113. (my-check (append-ec '(a b)) => '(a b))
  114. (my-check (append-ec (:range i 0) '(a b)) => '())
  115. (my-check (append-ec (:range i 1) '(a b)) => '(a b))
  116. (my-check (append-ec (:range i 2) '(a b)) => '(a b a b))
  117. (my-check (string-ec #\a) => (string #\a))
  118. (my-check (string-ec (:range i 0) #\a) => "")
  119. (my-check (string-ec (:range i 1) #\a) => "a")
  120. (my-check (string-ec (:range i 2) #\a) => "aa")
  121. (my-check (string-append-ec "ab") => "ab")
  122. (my-check (string-append-ec (:range i 0) "ab") => "")
  123. (my-check (string-append-ec (:range i 1) "ab") => "ab")
  124. (my-check (string-append-ec (:range i 2) "ab") => "abab")
  125. (my-check (vector-ec 1) => (vector 1))
  126. (my-check (vector-ec (:range i 0) i) => (vector))
  127. (my-check (vector-ec (:range i 1) i) => (vector 0))
  128. (my-check (vector-ec (:range i 2) i) => (vector 0 1))
  129. (my-check (vector-of-length-ec 1 1) => (vector 1))
  130. (my-check (vector-of-length-ec 0 (:range i 0) i) => (vector))
  131. (my-check (vector-of-length-ec 1 (:range i 1) i) => (vector 0))
  132. (my-check (vector-of-length-ec 2 (:range i 2) i) => (vector 0 1))
  133. (my-check (sum-ec 1) => 1)
  134. (my-check (sum-ec (:range i 0) i) => 0)
  135. (my-check (sum-ec (:range i 1) i) => 0)
  136. (my-check (sum-ec (:range i 2) i) => 1)
  137. (my-check (sum-ec (:range i 3) i) => 3)
  138. (my-check (product-ec 1) => 1)
  139. (my-check (product-ec (:range i 1 0) i) => 1)
  140. (my-check (product-ec (:range i 1 1) i) => 1)
  141. (my-check (product-ec (:range i 1 2) i) => 1)
  142. (my-check (product-ec (:range i 1 3) i) => 2)
  143. (my-check (product-ec (:range i 1 4) i) => 6)
  144. (my-check (min-ec 1) => 1)
  145. (my-check (min-ec (:range i 1) i) => 0)
  146. (my-check (min-ec (:range i 2) i) => 0)
  147. (my-check (max-ec 1) => 1)
  148. (my-check (max-ec (:range i 1) i) => 0)
  149. (my-check (max-ec (:range i 2) i) => 1)
  150. (my-check (first-ec #f 1) => 1)
  151. (my-check (first-ec #f (:range i 0) i) => #f)
  152. (my-check (first-ec #f (:range i 1) i) => 0)
  153. (my-check (first-ec #f (:range i 2) i) => 0)
  154. (my-check
  155. (let ((last-i -1))
  156. (first-ec #f (:range i 10) (begin (set! last-i i)) i)
  157. last-i )
  158. => 0 )
  159. (my-check (last-ec #f 1) => 1)
  160. (my-check (last-ec #f (:range i 0) i) => #f)
  161. (my-check (last-ec #f (:range i 1) i) => 0)
  162. (my-check (last-ec #f (:range i 2) i) => 1)
  163. (my-check (any?-ec #f) => #f)
  164. (my-check (any?-ec #t) => #t)
  165. (my-check (any?-ec (:range i 2 2) (even? i)) => #f)
  166. (my-check (any?-ec (:range i 2 3) (even? i)) => #t)
  167. (my-check (every?-ec #f) => #f)
  168. (my-check (every?-ec #t) => #t)
  169. (my-check (every?-ec (:range i 2 2) (even? i)) => #t)
  170. (my-check (every?-ec (:range i 2 3) (even? i)) => #t)
  171. (my-check (every?-ec (:range i 2 4) (even? i)) => #f)
  172. (my-check
  173. (let ((sum-sqr (lambda (x result) (+ result (* x x)))))
  174. (fold-ec 0 (:range i 10) i sum-sqr) )
  175. => 285 )
  176. (my-check
  177. (let ((minus-1 (lambda (x) (- x 1)))
  178. (sum-sqr (lambda (x result) (+ result (* x x)))))
  179. (fold3-ec (error "wrong") (:range i 10) i minus-1 sum-sqr) )
  180. => 284 )
  181. (my-check
  182. (fold3-ec 'infinity (:range i 0) i min min)
  183. => 'infinity )
  184. ; ==========================================================================
  185. ; Typed generators
  186. ; ==========================================================================
  187. (my-check (list-ec (:list x '()) x) => '())
  188. (my-check (list-ec (:list x '(1)) x) => '(1))
  189. (my-check (list-ec (:list x '(1 2 3)) x) => '(1 2 3))
  190. (my-check (list-ec (:list x '(1) '(2)) x) => '(1 2))
  191. (my-check (list-ec (:list x '(1) '(2) '(3)) x) => '(1 2 3))
  192. (my-check (list-ec (:string c "") c) => '())
  193. (my-check (list-ec (:string c "1") c) => '(#\1))
  194. (my-check (list-ec (:string c "123") c) => '(#\1 #\2 #\3))
  195. (my-check (list-ec (:string c "1" "2") c) => '(#\1 #\2))
  196. (my-check (list-ec (:string c "1" "2" "3") c) => '(#\1 #\2 #\3))
  197. (my-check (list-ec (:vector x (vector)) x) => '())
  198. (my-check (list-ec (:vector x (vector 1)) x) => '(1))
  199. (my-check (list-ec (:vector x (vector 1 2 3)) x) => '(1 2 3))
  200. (my-check (list-ec (:vector x (vector 1) (vector 2)) x) => '(1 2))
  201. (my-check
  202. (list-ec (:vector x (vector 1) (vector 2) (vector 3)) x)
  203. => '(1 2 3))
  204. (my-check (list-ec (:range x -2) x) => '())
  205. (my-check (list-ec (:range x -1) x) => '())
  206. (my-check (list-ec (:range x 0) x) => '())
  207. (my-check (list-ec (:range x 1) x) => '(0))
  208. (my-check (list-ec (:range x 2) x) => '(0 1))
  209. (my-check (list-ec (:range x 0 3) x) => '(0 1 2))
  210. (my-check (list-ec (:range x 1 3) x) => '(1 2))
  211. (my-check (list-ec (:range x -2 -1) x) => '(-2))
  212. (my-check (list-ec (:range x -2 -2) x) => '())
  213. (my-check (list-ec (:range x 1 5 2) x) => '(1 3))
  214. (my-check (list-ec (:range x 1 6 2) x) => '(1 3 5))
  215. (my-check (list-ec (:range x 5 1 -2) x) => '(5 3))
  216. (my-check (list-ec (:range x 6 1 -2) x) => '(6 4 2))
  217. (my-check (list-ec (:real-range x 0.0 3.0) x) => '(0. 1. 2.))
  218. (my-check (list-ec (:real-range x 0 3.0) x) => '(0. 1. 2.))
  219. (my-check (list-ec (:real-range x 0 3 1.0) x) => '(0. 1. 2.))
  220. (my-check
  221. (string-ec (:char-range c #\a #\z) c)
  222. => "abcdefghijklmnopqrstuvwxyz" )
  223. (my-check
  224. (begin
  225. (let ((f (my-open-output-file "tmp1")))
  226. (do-ec (:range n 10) (begin (write n f) (newline f)))
  227. (close-output-port f))
  228. (my-call-with-input-file "tmp1"
  229. (lambda (port) (list-ec (:port x port read) x)) ))
  230. => (list-ec (:range n 10) n) )
  231. (my-check
  232. (begin
  233. (let ((f (my-open-output-file "tmp1")))
  234. (do-ec (:range n 10) (begin (write n f) (newline f)))
  235. (close-output-port f))
  236. (my-call-with-input-file "tmp1"
  237. (lambda (port) (list-ec (:port x port) x)) ))
  238. => (list-ec (:range n 10) n) )
  239. ; ==========================================================================
  240. ; The special generators :do :let :parallel :while :until
  241. ; ==========================================================================
  242. (my-check (list-ec (:do ((i 0)) (< i 4) ((+ i 1))) i) => '(0 1 2 3))
  243. (my-check
  244. (list-ec
  245. (:do (let ((x 'x)))
  246. ((i 0))
  247. (< i 4)
  248. (let ((j (- 10 i))))
  249. #t
  250. ((+ i 1)) )
  251. j )
  252. => '(10 9 8 7) )
  253. (my-check (list-ec (:let x 1) x) => '(1))
  254. (my-check (list-ec (:let x 1) (:let y (+ x 1)) y) => '(2))
  255. (my-check (list-ec (:let x 1) (:let x (+ x 1)) x) => '(2))
  256. (my-check
  257. (list-ec (:parallel (:range i 1 10) (:list x '(a b c))) (list i x))
  258. => '((1 a) (2 b) (3 c)) )
  259. (my-check
  260. (list-ec (:while (:range i 1 10) (< i 5)) i)
  261. => '(1 2 3 4) )
  262. (my-check
  263. (list-ec (:until (:range i 1 10) (>= i 5)) i)
  264. => '(1 2 3 4 5) )
  265. ; with generator that might use inner bindings
  266. (my-check
  267. (list-ec (:while (:list i '(1 2 3 4 5 6 7 8 9)) (< i 5)) i)
  268. => '(1 2 3 4) )
  269. ; Was broken in original reference implementation as pointed
  270. ; out by sunnan@handgranat.org on 24-Apr-2005 comp.lang.scheme.
  271. ; Refer to http://groups-beta.google.com/group/comp.lang.scheme/
  272. ; browse_thread/thread/f5333220eaeeed66/75926634cf31c038#75926634cf31c038
  273. (my-check
  274. (list-ec (:until (:list i '(1 2 3 4 5 6 7 8 9)) (>= i 5)) i)
  275. => '(1 2 3 4 5) )
  276. (my-check
  277. (list-ec (:while (:vector x (index i) '#(1 2 3 4 5))
  278. (< x 10))
  279. x)
  280. => '(1 2 3 4 5))
  281. ; Was broken in reference implementation, even after fix for the
  282. ; bug reported by Sunnan, as reported by Jens-Axel Soegaard on
  283. ; 4-Jun-2007.
  284. ; combine :while/:until and :parallel
  285. (my-check
  286. (list-ec (:while (:parallel (:range i 1 10)
  287. (:list j '(1 2 3 4 5 6 7 8 9)))
  288. (< i 5))
  289. (list i j))
  290. => '((1 1) (2 2) (3 3) (4 4)))
  291. (my-check
  292. (list-ec (:until (:parallel (:range i 1 10)
  293. (:list j '(1 2 3 4 5 6 7 8 9)))
  294. (>= i 5))
  295. (list i j))
  296. => '((1 1) (2 2) (3 3) (4 4) (5 5)))
  297. ; check that :while/:until really stop the generator
  298. (my-check
  299. (let ((n 0))
  300. (do-ec (:while (:range i 1 10) (begin (set! n (+ n 1)) (< i 5)))
  301. (if #f #f))
  302. n)
  303. => 5)
  304. (my-check
  305. (let ((n 0))
  306. (do-ec (:until (:range i 1 10) (begin (set! n (+ n 1)) (>= i 5)))
  307. (if #f #f))
  308. n)
  309. => 5)
  310. (my-check
  311. (let ((n 0))
  312. (do-ec (:while (:parallel (:range i 1 10)
  313. (:do () (begin (set! n (+ n 1)) #t) ()))
  314. (< i 5))
  315. (if #f #f))
  316. n)
  317. => 5)
  318. (my-check
  319. (let ((n 0))
  320. (do-ec (:until (:parallel (:range i 1 10)
  321. (:do () (begin (set! n (+ n 1)) #t) ()))
  322. (>= i 5))
  323. (if #f #f))
  324. n)
  325. => 5)
  326. ; ==========================================================================
  327. ; The dispatching generator
  328. ; ==========================================================================
  329. (my-check (list-ec (: c '(a b)) c) => '(a b))
  330. (my-check (list-ec (: c '(a b) '(c d)) c) => '(a b c d))
  331. (my-check (list-ec (: c "ab") c) => '(#\a #\b))
  332. (my-check (list-ec (: c "ab" "cd") c) => '(#\a #\b #\c #\d))
  333. (my-check (list-ec (: c (vector 'a 'b)) c) => '(a b))
  334. (my-check (list-ec (: c (vector 'a 'b) (vector 'c)) c) => '(a b c))
  335. (my-check (list-ec (: i 0) i) => '())
  336. (my-check (list-ec (: i 1) i) => '(0))
  337. (my-check (list-ec (: i 10) i) => '(0 1 2 3 4 5 6 7 8 9))
  338. (my-check (list-ec (: i 1 2) i) => '(1))
  339. (my-check (list-ec (: i 1 2 3) i) => '(1))
  340. (my-check (list-ec (: i 1 9 3) i) => '(1 4 7))
  341. (my-check (list-ec (: i 0.0 1.0 0.2) i) => '(0. 0.2 0.4 0.6 0.8))
  342. (my-check (list-ec (: c #\a #\c) c) => '(#\a #\b #\c))
  343. (my-check
  344. (begin
  345. (let ((f (my-open-output-file "tmp1")))
  346. (do-ec (:range n 10) (begin (write n f) (newline f)))
  347. (close-output-port f))
  348. (my-call-with-input-file "tmp1"
  349. (lambda (port) (list-ec (: x port read) x)) ))
  350. => (list-ec (:range n 10) n) )
  351. (my-check
  352. (begin
  353. (let ((f (my-open-output-file "tmp1")))
  354. (do-ec (:range n 10) (begin (write n f) (newline f)))
  355. (close-output-port f))
  356. (my-call-with-input-file "tmp1"
  357. (lambda (port) (list-ec (: x port) x)) ))
  358. => (list-ec (:range n 10) n) )
  359. ; ==========================================================================
  360. ; With index variable
  361. ; ==========================================================================
  362. (my-check (list-ec (:list c (index i) '(a b)) (list c i)) => '((a 0) (b 1)))
  363. (my-check (list-ec (:string c (index i) "a") (list c i)) => '((#\a 0)))
  364. (my-check (list-ec (:vector c (index i) (vector 'a)) (list c i)) => '((a 0)))
  365. (my-check
  366. (list-ec (:range i (index j) 0 -3 -1) (list i j))
  367. => '((0 0) (-1 1) (-2 2)) )
  368. (my-check
  369. (list-ec (:real-range i (index j) 0 1 0.2) (list i j))
  370. => '((0. 0) (0.2 1) (0.4 2) (0.6 3) (0.8 4)) )
  371. (my-check
  372. (list-ec (:char-range c (index i) #\a #\c) (list c i))
  373. => '((#\a 0) (#\b 1) (#\c 2)) )
  374. (my-check
  375. (list-ec (: x (index i) '(a b c d)) (list x i))
  376. => '((a 0) (b 1) (c 2) (d 3)) )
  377. (my-check
  378. (begin
  379. (let ((f (my-open-output-file "tmp1")))
  380. (do-ec (:range n 10) (begin (write n f) (newline f)))
  381. (close-output-port f))
  382. (my-call-with-input-file "tmp1"
  383. (lambda (port) (list-ec (: x (index i) port) (list x i))) ))
  384. => '((0 0) (1 1) (2 2) (3 3) (4 4) (5 5) (6 6) (7 7) (8 8) (9 9)) )
  385. ; ==========================================================================
  386. ; The examples from the SRFI document
  387. ; ==========================================================================
  388. ; from Abstract
  389. (my-check (list-ec (: i 5) (* i i)) => '(0 1 4 9 16))
  390. (my-check
  391. (list-ec (: n 1 4) (: i n) (list n i))
  392. => '((1 0) (2 0) (2 1) (3 0) (3 1) (3 2)) )
  393. ; from Generators
  394. (my-check
  395. (list-ec (: x (index i) "abc") (list x i))
  396. => '((#\a 0) (#\b 1) (#\c 2)) )
  397. (my-check
  398. (list-ec (:string c (index i) "a" "b") (cons c i))
  399. => '((#\a . 0) (#\b . 1)) )
  400. ; ==========================================================================
  401. ; Little Shop of Horrors
  402. ; ==========================================================================
  403. (my-check (list-ec (:range x 5) (:range x x) x) => '(0 0 1 0 1 2 0 1 2 3))
  404. (my-check (list-ec (:list x '(2 "23" (4))) (: y x) y) => '(0 1 #\2 #\3 4))
  405. (my-check
  406. (list-ec (:parallel (:integers x)
  407. (:do ((i 10)) (< x i) ((- i 1))))
  408. (list x i))
  409. => '((0 10) (1 9) (2 8) (3 7) (4 6)) )
  410. ; ==========================================================================
  411. ; Less artificial examples
  412. ; ==========================================================================
  413. (define (factorial n) ; n * (n-1) * .. * 1 for n >= 0
  414. (product-ec (:range k 2 (+ n 1)) k) )
  415. (my-check (factorial 0) => 1)
  416. (my-check (factorial 1) => 1)
  417. (my-check (factorial 3) => 6)
  418. (my-check (factorial 5) => 120)
  419. (define (eratosthenes n) ; primes in {2..n-1} for n >= 1
  420. (let ((p? (make-string n #\1)))
  421. (do-ec (:range k 2 n)
  422. (if (char=? (string-ref p? k) #\1))
  423. (:range i (* 2 k) n k)
  424. (string-set! p? i #\0) )
  425. (list-ec (:range k 2 n) (if (char=? (string-ref p? k) #\1)) k) ))
  426. (my-check
  427. (eratosthenes 50)
  428. => '(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47) )
  429. (my-check
  430. (length (eratosthenes 100000))
  431. => 9592 ) ; we expect 10^5/ln(10^5)
  432. (define (pythagoras n) ; a, b, c s.t. 1 <= a <= b <= c <= n, a^2 + b^2 = c^2
  433. (list-ec
  434. (:let sqr-n (* n n))
  435. (:range a 1 (+ n 1))
  436. ; (begin (display a) (display " "))
  437. (:let sqr-a (* a a))
  438. (:range b a (+ n 1))
  439. (:let sqr-c (+ sqr-a (* b b)))
  440. (if (<= sqr-c sqr-n))
  441. (:range c b (+ n 1))
  442. (if (= (* c c) sqr-c))
  443. (list a b c) ))
  444. (my-check
  445. (pythagoras 15)
  446. => '((3 4 5) (5 12 13) (6 8 10) (9 12 15)) )
  447. (my-check
  448. (length (pythagoras 200))
  449. => 127 )
  450. (define (qsort xs) ; stable
  451. (if (null? xs)
  452. '()
  453. (let ((pivot (car xs)) (xrest (cdr xs)))
  454. (append
  455. (qsort (list-ec (:list x xrest) (if (< x pivot)) x))
  456. (list pivot)
  457. (qsort (list-ec (:list x xrest) (if (>= x pivot)) x)) ))))
  458. (my-check
  459. (qsort '(1 5 4 2 4 5 3 2 1 3))
  460. => '(1 1 2 2 3 3 4 4 5 5) )
  461. (define (pi-BBP m) ; approx. of pi within 16^-m (Bailey-Borwein-Plouffe)
  462. (sum-ec
  463. (:range n 0 (+ m 1))
  464. (:let n8 (* 8 n))
  465. (* (- (/ 4 (+ n8 1))
  466. (+ (/ 2 (+ n8 4))
  467. (/ 1 (+ n8 5))
  468. (/ 1 (+ n8 6))))
  469. (/ 1 (expt 16 n)) )))
  470. (my-check
  471. (pi-BBP 5)
  472. => (/ 40413742330349316707 12864093722915635200) )
  473. (define (read-line port) ; next line (incl. #\newline) of port
  474. (let ((line
  475. (string-ec
  476. (:until (:port c port read-char)
  477. (char=? c #\newline) )
  478. c )))
  479. (if (string=? line "")
  480. (read-char port) ; eof-object
  481. line )))
  482. (define (read-lines filename) ; list of all lines
  483. (my-call-with-input-file
  484. filename
  485. (lambda (port)
  486. (list-ec (:port line port read-line) line) )))
  487. (my-check
  488. (begin
  489. (let ((f (my-open-output-file "tmp1")))
  490. (do-ec (:range n 10) (begin (write n f) (newline f)))
  491. (close-output-port f))
  492. (read-lines "tmp1") )
  493. => (list-ec (:char-range c #\0 #\9) (string c #\newline)) )
  494. (false-if-exception (delete-file "tmp1"))