lists.scm 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. ;;; Lists
  2. ;;; Copyright (C) 2024 Igalia, S.L.
  3. ;;;
  4. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  5. ;;; you may not use this file except in compliance with the License.
  6. ;;; You may obtain a copy of the License at
  7. ;;;
  8. ;;; http://www.apache.org/licenses/LICENSE-2.0
  9. ;;;
  10. ;;; Unless required by applicable law or agreed to in writing, software
  11. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  12. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. ;;; See the License for the specific language governing permissions and
  14. ;;; limitations under the License.
  15. ;;; Commentary:
  16. ;;;
  17. ;;; Lists.
  18. ;;;
  19. ;;; Code:
  20. (library (hoot lists)
  21. (export length
  22. list-ref list-set! list-tail
  23. list?
  24. make-list
  25. reverse append list-copy
  26. map for-each fold
  27. acons
  28. sort)
  29. (import (only (hoot primitives) %append)
  30. (hoot apply)
  31. (hoot cond-expand)
  32. (hoot inline-wasm)
  33. (hoot match)
  34. (hoot numbers)
  35. (hoot pairs)
  36. (hoot syntax)
  37. (hoot values))
  38. (define (not x) (if x #f #t))
  39. (define (length l)
  40. (let lp ((len 0) (l l))
  41. (if (null? l) len (lp (1+ len) (cdr l)))))
  42. (define (list-ref l n)
  43. (let lp ((l l) (n n))
  44. (if (zero? n)
  45. (car l)
  46. (lp (cdr l) (1- n)))))
  47. (define (list-set! l n x)
  48. (let lp ((l l) (n n))
  49. (if (zero? n)
  50. (set-car! l x)
  51. (lp (cdr l) (1- n)))))
  52. (define (list-tail l n)
  53. (let lp ((l l) (n n))
  54. (if (zero? n)
  55. l
  56. (lp (cdr l) (1- n)))))
  57. (define (list? l)
  58. (let lp ((l l))
  59. (match l
  60. (() #t)
  61. ((_ . l) (lp l))
  62. (_ #f))))
  63. (define (make-list n init)
  64. (let lp ((n n) (out '()))
  65. (if (zero? n)
  66. out
  67. (lp (1- n) (cons init out)))))
  68. (define (reverse l)
  69. (let lp ((out '()) (l l))
  70. (match l
  71. (() out)
  72. ((head . tail) (lp (cons head out) tail)))))
  73. (define append
  74. (case-lambda
  75. (() '())
  76. ((x) x)
  77. ((x y) (%append x y))
  78. ((x y . z) (%append x (apply append y z)))))
  79. (define (list-copy l)
  80. (append l '()))
  81. (define (fold f seed l)
  82. (let lp ((seed seed) (l l))
  83. (match l
  84. (() seed)
  85. ((x . l) (lp (f x seed) l)))))
  86. ;; Temp definitions!
  87. (define map
  88. (case-lambda
  89. ((f l)
  90. (let lp ((l l))
  91. (match l
  92. (() '())
  93. ((x . l) (cons (f x) (lp l))))))
  94. ((f l1 l2)
  95. (let lp ((l1 l1) (l2 l2))
  96. (match l1
  97. (() '())
  98. ((x . l1)
  99. (match l2
  100. (() '())
  101. ((y . l2)
  102. (cons (f x y) (lp l1 l2))))))))
  103. ((f l1 . rest)
  104. (let lp ((l1 l1) (rest rest))
  105. (match l1
  106. (()
  107. ;; Assert the other lists are empty.
  108. (let lp ((rest rest))
  109. (match rest
  110. (() '())
  111. ((() . rest) (lp rest)))))
  112. ((x . l1)
  113. (cons (apply f x (map car rest))
  114. (lp l1 (map cdr rest)))))))))
  115. (define for-each
  116. (case-lambda
  117. ((f l)
  118. (let lp ((l l))
  119. (unless (null? l)
  120. (f (car l))
  121. (lp (cdr l)))))
  122. ((f l1 l2)
  123. (let lp ((l1 l1) (l2 l2))
  124. (match l1
  125. (() (values))
  126. ((x . l1)
  127. (match l2
  128. (() (values))
  129. ((y . l2)
  130. (f x y)
  131. (lp l1 l2)))))))
  132. ((f l1 . rest)
  133. (let lp ((l1 l1) (rest rest))
  134. (match l1
  135. (()
  136. ;; Assert the other lists are empty.
  137. (let lp ((rest rest))
  138. (match rest
  139. (() (values))
  140. ((() . rest) (lp rest)))))
  141. ((x . l1)
  142. (apply f x (map car rest))
  143. (lp l1 (map cdr rest))))))))
  144. (define (acons x y z) (cons (cons x y) z))
  145. (define (sort items <)
  146. (define (split k items)
  147. (if (zero? k)
  148. (values '() items)
  149. (match items
  150. ((x . rest)
  151. (call-with-values (lambda () (split (1- k) rest))
  152. (lambda (left right)
  153. (values (cons x left) right)))))))
  154. (define (merge left right)
  155. (match left
  156. (() right)
  157. ((a . rest-left)
  158. (match right
  159. (() left)
  160. ((b . rest-right)
  161. (if (< b a)
  162. (cons b (merge left rest-right))
  163. (cons a (merge rest-left right))))))))
  164. (define (mergesort items k)
  165. (match items
  166. ((_) items)
  167. (_
  168. (let ((k/2 (quotient k 2)))
  169. (call-with-values (lambda () (split k/2 items))
  170. (lambda (left right)
  171. (let ((left (mergesort left k/2))
  172. (right (mergesort right (- k k/2))))
  173. (merge left right))))))))
  174. (match items
  175. (() '())
  176. (_ (mergesort items (length items)))))
  177. (cond-expand
  178. (guile-vm)
  179. (hoot
  180. (%inline-wasm
  181. '(func (param $append (ref $proc))
  182. (global.set $append-primitive (local.get $append)))
  183. (lambda (x z)
  184. (let lp ((x x))
  185. (if (null? x)
  186. z
  187. (cons (car x) (lp (cdr x))))))))))