curry.sls 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #!r6rs
  2. ;;; Copyright © 2016 Federico Beffa
  3. ;;;
  4. ;;; This program is free software; you can redistribute it and/or modify it
  5. ;;; under the terms of the GNU General Public License as published by
  6. ;;; the Free Software Foundation; either version 3 of the License, or (at
  7. ;;; your option) any later version.
  8. ;;;
  9. ;;; This program is distributed in the hope that it will be useful, but
  10. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;;; GNU General Public License for more details.
  13. ;;;
  14. ;;; You should have received a copy of the GNU General Public License
  15. ;;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Code
  17. (library (mit curry)
  18. (export lambda* define*)
  19. (import (rnrs)
  20. (only (chezscheme) gensym? enumerate syntax-error list-head
  21. last-pair void))
  22. ;; allow #:optional, #:rest and . formals.
  23. ;; ((lambda* (a #:optional (b (+ a 1)) #:rest c) (cons* a b c)) 1)
  24. ;; => (1 2)
  25. (define-syntax lambda*
  26. (lambda (x)
  27. (define (keyword-id? kn p)
  28. (if (and (pair? p) (identifier? (car p))
  29. (gensym? (syntax->datum (car p)))
  30. (equal? (symbol->string (syntax->datum (car p))) kn))
  31. #t #f))
  32. (define (keyword-id-index kn ls)
  33. (let ((element (find (lambda (p) (keyword-id? kn p))
  34. (map (lambda (e i) (cons e i))
  35. ls (enumerate ls)))))
  36. (if element (cdr element) #f)))
  37. ;; return 3 lists with required, optional and rest formal
  38. ;; parameter identifiers.
  39. (define (split-formals ls)
  40. (let ((opt-idx (keyword-id-index "optional" ls))
  41. (rest-idx (keyword-id-index "rest" ls)))
  42. (cond
  43. ((and opt-idx rest-idx)
  44. (when (< rest-idx opt-idx)
  45. (syntax-error 'lambda* "#:optional keyword must precede #:rest one"))
  46. (let ((o+r (list-tail ls (+ 1 opt-idx))))
  47. (values (list-head ls opt-idx)
  48. (list-head o+r (- rest-idx (+ 1 opt-idx)))
  49. (list-tail o+r (- (+ 1 rest-idx) (+ 1 opt-idx))))))
  50. ((and (not opt-idx) (not rest-idx))
  51. (values ls '() '()))
  52. ((and opt-idx (not rest-idx))
  53. (values (list-head ls opt-idx)
  54. (list-tail ls (+ 1 opt-idx))
  55. '()))
  56. ((and (not opt-idx) rest-idx)
  57. (values (list-head ls rest-idx)
  58. '()
  59. (list-tail ls (+ 1 rest-idx))))
  60. (else
  61. (syntax-error 'lambda* "wrong formals format")))))
  62. (define (last ls)
  63. (car (last-pair ls)))
  64. (define (remove-last ls)
  65. (list-head ls (- (length ls) 1)))
  66. ;; add the a value to the list of let bindings used to hold the
  67. ;; default values of optional formal parameters.
  68. (define (add-default fl d-vals)
  69. (syntax-case fl ()
  70. (i (identifier? #'i) (append (list #`(i #,(list #'void))) d-vals))
  71. ((i v) (identifier? #'i) (append (list #'(i v)) d-vals))))
  72. ;; extract the identifier of an optional formal parameter
  73. (define (formals-identifiers fls)
  74. (map (lambda (fl)
  75. (syntax-case fl ()
  76. (i (identifier? #'i) #'i)
  77. ((i v) (identifier? #'i) #'i)))
  78. fls))
  79. ;; returns the default value of an optional formal parameter
  80. (define (formals-defaults fls)
  81. (map (lambda (fl)
  82. (syntax-case fl ()
  83. (i (identifier? #'i) (list #'void))
  84. ((i v) (identifier? #'i) #'v)))
  85. fls))
  86. ;; return the 'rest' formal parameter defined in one of the two
  87. ;; possible ways: using the #:rest keyword, or the '.' notation.
  88. (define (rest-formal rest-fl dot-fl)
  89. (when (and (not (null? rest-fl)) (not (null? dot-fl)))
  90. (syntax-error 'lambda* "#:rest keyword not allowed with . notation"))
  91. (when (> (length rest-fl) 1)
  92. (syntax-error 'lambda* "multiple #:rest or . formals"))
  93. (cond
  94. ((not (null? rest-fl)) (car rest-fl))
  95. ((not (null? dot-fl)) dot-fl)
  96. (else '())))
  97. (syntax-case x ()
  98. ((k (f ... . r) b1 b2 ...)
  99. (let ((formals #'(f ...))
  100. (dot-fl #'r)) ; when bound a synbol, when not bound '()
  101. (let-values (((req-fls opt-fls rest-fl) (split-formals formals)))
  102. ;; rest-fl is a one (or more, we check the length later)
  103. ;; element list when bound and the empty list when not
  104. ;; bound
  105. #`(case-lambda
  106. ((#,@req-fls #,@(formals-identifiers opt-fls) . #,(rest-formal rest-fl dot-fl))
  107. b1 b2 ...)
  108. #,@(let loop ((o-fls opt-fls)
  109. (d-vals (if (null? (rest-formal rest-fl dot-fl))
  110. '()
  111. #`((#,(rest-formal rest-fl dot-fl) '())))))
  112. (if (null? o-fls)
  113. #`(((#,@req-fls)
  114. (let #,d-vals
  115. b1 b2 ...)))
  116. #`(((#,@req-fls #,@(formals-identifiers o-fls))
  117. (let #,d-vals
  118. b1 b2 ...))
  119. #,@(loop (remove-last o-fls)
  120. (add-default (last o-fls) d-vals))))))))))))
  121. ;; Allows curried definitions with optional parameters of the form:
  122. ;; (define* (((fbe a) b) #:optional (c 3)) (list a b c))
  123. ;; (((fbe 1) 2)) => (1 2 3)
  124. (define-syntax define*
  125. (lambda (x)
  126. (syntax-case x ()
  127. ((_ v e) (identifier? #'v) #'(define v e))
  128. ((_ formals b1 b2 ...)
  129. (let loop ((fls #'formals) (body #'(b1 b2 ...)))
  130. (let ((fls-datum (syntax->datum fls)))
  131. (if (and (pair? fls-datum) (symbol? (car fls-datum)))
  132. (with-syntax (((var . fls) fls))
  133. #`(define var (lambda* fls #,@body)))
  134. (syntax-case fls ()
  135. ((fs-a . fs-b)
  136. (loop #'fs-a
  137. #`((lambda* fs-b #,@body))))))))))))
  138. )