srfi-11.scm 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. ;;; srfi-11.scm --- let-values and let*-values
  2. ;; Copyright (C) 2000, 2001, 2002, 2004, 2006 Free Software Foundation, Inc.
  3. ;;
  4. ;; This library is free software; you can redistribute it and/or
  5. ;; modify it under the terms of the GNU Lesser General Public
  6. ;; License as published by the Free Software Foundation; either
  7. ;; version 2.1 of the License, or (at your option) any later version.
  8. ;;
  9. ;; This library is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;; Lesser General Public License for more details.
  13. ;;
  14. ;; You should have received a copy of the GNU Lesser General Public
  15. ;; License along with this library; if not, write to the Free Software
  16. ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. ;;; Commentary:
  18. ;; This module exports two syntax forms: let-values and let*-values.
  19. ;;
  20. ;; Sample usage:
  21. ;;
  22. ;; (let-values (((x y . z) (foo a b))
  23. ;; ((p q) (bar c)))
  24. ;; (baz x y z p q))
  25. ;;
  26. ;; This binds `x' and `y' to the first to values returned by `foo',
  27. ;; `z' to the rest of the values from `foo', and `p' and `q' to the
  28. ;; values returned by `bar'. All of these are available to `baz'.
  29. ;;
  30. ;; let*-values : let-values :: let* : let
  31. ;;
  32. ;; This module is fully documented in the Guile Reference Manual.
  33. ;;; Code:
  34. (define-module (srfi srfi-11)
  35. :use-module (ice-9 syncase)
  36. :export-syntax (let-values let*-values))
  37. (cond-expand-provide (current-module) '(srfi-11))
  38. ;;;;;;;;;;;;;;
  39. ;; let-values
  40. ;;
  41. ;; Current approach is to translate
  42. ;;
  43. ;; (let-values (((x y . z) (foo a b))
  44. ;; ((p q) (bar c)))
  45. ;; (baz x y z p q))
  46. ;;
  47. ;; into
  48. ;;
  49. ;; (call-with-values (lambda () (foo a b))
  50. ;; (lambda (<tmp-x> <tmp-y> . <tmp-z>)
  51. ;; (call-with-values (lambda () (bar c))
  52. ;; (lambda (<tmp-p> <tmp-q>)
  53. ;; (let ((x <tmp-x>)
  54. ;; (y <tmp-y>)
  55. ;; (z <tmp-z>)
  56. ;; (p <tmp-p>)
  57. ;; (q <tmp-q>))
  58. ;; (baz x y z p q))))))
  59. ;; I originally wrote this as a define-macro, but then I found out
  60. ;; that guile's gensym/gentemp was broken, so I tried rewriting it as
  61. ;; a syntax-rules statement.
  62. ;; [make-symbol now fixes gensym/gentemp problems.]
  63. ;;
  64. ;; Since syntax-rules didn't seem powerful enough to implement
  65. ;; let-values in one definition without exposing illegal syntax (or
  66. ;; perhaps my brain's just not powerful enough :>). I tried writing
  67. ;; it using a private helper, but that didn't work because the
  68. ;; let-values expands outside the scope of this module. I wonder why
  69. ;; syntax-rules wasn't designed to allow "private" patterns or
  70. ;; similar...
  71. ;;
  72. ;; So in the end, I dumped the syntax-rules implementation, reproduced
  73. ;; here for posterity, and went with the define-macro one below --
  74. ;; gensym/gentemp's got to be fixed anyhow...
  75. ;
  76. ; (define-syntax let-values-helper
  77. ; (syntax-rules ()
  78. ; ;; Take the vars from one let binding (i.e. the (x y z) from ((x y
  79. ; ;; z) (values 1 2 3)) and turn it in to the corresponding (lambda
  80. ; ;; (<tmp-x> <tmp-y> <tmp-z>) ...) from above, keeping track of the
  81. ; ;; temps you create so you can use them later...
  82. ; ;;
  83. ; ;; I really don't fully understand why the (var-1 var-1) trick
  84. ; ;; works below, but basically, when all those (x x) bindings show
  85. ; ;; up in the final "let", syntax-rules forces a renaming.
  86. ; ((_ "consumer" () lambda-tmps final-let-bindings lv-bindings
  87. ; body ...)
  88. ; (lambda lambda-tmps
  89. ; (let-values-helper "cwv" lv-bindings final-let-bindings body ...)))
  90. ; ((_ "consumer" (var-1 var-2 ...) (lambda-tmp ...) final-let-bindings lv-bindings
  91. ; body ...)
  92. ; (let-values-helper "consumer"
  93. ; (var-2 ...)
  94. ; (lambda-tmp ... var-1)
  95. ; ((var-1 var-1) . final-let-bindings)
  96. ; lv-bindings
  97. ; body ...))
  98. ; ((_ "cwv" () final-let-bindings body ...)
  99. ; (let final-let-bindings
  100. ; body ...))
  101. ; ((_ "cwv" ((vars-1 binding-1) other-bindings ...) final-let-bindings
  102. ; body ...)
  103. ; (call-with-values (lambda () binding-1)
  104. ; (let-values-helper "consumer"
  105. ; vars-1
  106. ; ()
  107. ; final-let-bindings
  108. ; (other-bindings ...)
  109. ; body ...)))))
  110. ;
  111. ; (define-syntax let-values
  112. ; (syntax-rules ()
  113. ; ((let-values () body ...)
  114. ; (begin body ...))
  115. ; ((let-values (binding ...) body ...)
  116. ; (let-values-helper "cwv" (binding ...) () body ...))))
  117. ;
  118. ;
  119. ; (define-syntax let-values
  120. ; (letrec-syntax ((build-consumer
  121. ; ;; Take the vars from one let binding (i.e. the (x
  122. ; ;; y z) from ((x y z) (values 1 2 3)) and turn it
  123. ; ;; in to the corresponding (lambda (<tmp-x> <tmp-y>
  124. ; ;; <tmp-z>) ...) from above.
  125. ; (syntax-rules ()
  126. ; ((_ () new-tmps tmp-vars () body ...)
  127. ; (lambda new-tmps
  128. ; body ...))
  129. ; ((_ () new-tmps tmp-vars vars body ...)
  130. ; (lambda new-tmps
  131. ; (lv-builder vars tmp-vars body ...)))
  132. ; ((_ (var-1 var-2 ...) new-tmps tmp-vars vars body ...)
  133. ; (build-consumer (var-2 ...)
  134. ; (tmp-1 . new-tmps)
  135. ; ((var-1 tmp-1) . tmp-vars)
  136. ; bindings
  137. ; body ...))))
  138. ; (lv-builder
  139. ; (syntax-rules ()
  140. ; ((_ () tmp-vars body ...)
  141. ; (let tmp-vars
  142. ; body ...))
  143. ; ((_ ((vars-1 binding-1) (vars-2 binding-2) ...)
  144. ; tmp-vars
  145. ; body ...)
  146. ; (call-with-values (lambda () binding-1)
  147. ; (build-consumer vars-1
  148. ; ()
  149. ; tmp-vars
  150. ; ((vars-2 binding-2) ...)
  151. ; body ...))))))
  152. ;
  153. ; (syntax-rules ()
  154. ; ((_ () body ...)
  155. ; (begin body ...))
  156. ; ((_ ((vars binding) ...) body ...)
  157. ; (lv-builder ((vars binding) ...) () body ...)))))
  158. (define-macro (let-values vars . body)
  159. (define (map-1-dot proc elts)
  160. ;; map over one optionally dotted (a b c . d) list, producing an
  161. ;; optionally dotted result.
  162. (cond
  163. ((null? elts) '())
  164. ((pair? elts) (cons (proc (car elts)) (map-1-dot proc (cdr elts))))
  165. (else (proc elts))))
  166. (define (undot-list lst)
  167. ;; produce a non-dotted list from a possibly dotted list.
  168. (cond
  169. ((null? lst) '())
  170. ((pair? lst) (cons (car lst) (undot-list (cdr lst))))
  171. (else (list lst))))
  172. (define (let-values-helper vars body prev-let-vars)
  173. (let* ((var-binding (car vars))
  174. (new-tmps (map-1-dot (lambda (sym) (make-symbol "let-values-var"))
  175. (car var-binding)))
  176. (let-vars (map (lambda (sym tmp) (list sym tmp))
  177. (undot-list (car var-binding))
  178. (undot-list new-tmps))))
  179. (if (null? (cdr vars))
  180. `(call-with-values (lambda () ,(cadr var-binding))
  181. (lambda ,new-tmps
  182. (let ,(apply append let-vars prev-let-vars)
  183. ,@body)))
  184. `(call-with-values (lambda () ,(cadr var-binding))
  185. (lambda ,new-tmps
  186. ,(let-values-helper (cdr vars) body
  187. (cons let-vars prev-let-vars)))))))
  188. (if (null? vars)
  189. `(begin ,@body)
  190. (let-values-helper vars body '())))
  191. ;;;;;;;;;;;;;;
  192. ;; let*-values
  193. ;;
  194. ;; Current approach is to translate
  195. ;;
  196. ;; (let*-values (((x y z) (foo a b))
  197. ;; ((p q) (bar c)))
  198. ;; (baz x y z p q))
  199. ;;
  200. ;; into
  201. ;;
  202. ;; (call-with-values (lambda () (foo a b))
  203. ;; (lambda (x y z)
  204. ;; (call-with-values (lambda (bar c))
  205. ;; (lambda (p q)
  206. ;; (baz x y z p q)))))
  207. (define-syntax let*-values
  208. (syntax-rules ()
  209. ((let*-values () body ...)
  210. (begin body ...))
  211. ((let*-values ((vars-1 binding-1) (vars-2 binding-2) ...) body ...)
  212. (call-with-values (lambda () binding-1)
  213. (lambda vars-1
  214. (let*-values ((vars-2 binding-2) ...)
  215. body ...))))))
  216. ; Alternate define-macro implementation...
  217. ;
  218. ; (define-macro (let*-values vars . body)
  219. ; (define (let-values-helper vars body)
  220. ; (let ((var-binding (car vars)))
  221. ; (if (null? (cdr vars))
  222. ; `(call-with-values (lambda () ,(cadr var-binding))
  223. ; (lambda ,(car var-binding)
  224. ; ,@body))
  225. ; `(call-with-values (lambda () ,(cadr var-binding))
  226. ; (lambda ,(car var-binding)
  227. ; ,(let-values-helper (cdr vars) body))))))
  228. ; (if (null? vars)
  229. ; `(begin ,@body)
  230. ; (let-values-helper vars body)))
  231. ;;; srfi-11.scm ends here