-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathautocurry.ss
75 lines (68 loc) · 3.38 KB
/
autocurry.ss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
;; -*- Gerbil -*-
;;; Autocurrying of functions, to enable Categorical Functional Programming in Scheme
;; * Functions defined with fn and defn will be semantically unary (single-argument)
;; * If more than one argument is specified, each argument passed but the last
;; will create a closure that remembers previous arguments and waits for the next.
;; * When the last argument is provided (or when there is no argument),
;; the body will be evaluated in a begin form.
;; * Furthermore, each function defined with defn and each argument received by fn or defn
;; will be autocurrying when called.
;; * Also, a single unparenthesized argument will be treated the same as if were parenthesized,
;; in line with typical lambda-calculus, and differently from Scheme style where it means putting
;; all the arguments (in variable number) in a list. There is only always one single argument.
;; * The %app autocurrying function application form immediately applies each argument
;; to the provided function, and keeps applying in autocurried style to any further argument.
;; Thus: (f x y z) will be evaluated like (((f x) y) z)
;; * If no argument is provided, no function call happens, the naked variable value is passed:
;; Thus: (v) = v = the value bound.
;; * We did not engineer let or any such form make their bound variables autocurrying, but
;; you can use an internal defn within a function definition, lambda or let to achieve that effect.
;;
;; This is very much like calling functions in ML.
;; The current simple macros do not support either optional or keyword arguments,
;; e.g. like OCaml does. You can use regular def's and lambda's and function calls for that purpose.
;; Extending the macros below to support optional and keyword arguments in a way similar to OCaml
;; is left as an exercise to the gentle meta-evaluator.
;;
;; The definitions are simple enough to be read and understood for any required semantic clarification.
#| ;; To fully inhabit that universe:
(defalias %%app %app)
(defalias λ fn) ;; Unicode symbol
(defalias lambda fn) ;; l-a-m-b-d-a
(defalias dfn defn)
OR, when you import, say (only rebinding unicode lambda def and @):
(import (rename-in :clan/autocurry (fn λ) (defn dfn) (%app @))
|#
(export #t)
;; Apply a curried function to a list of argument
(define (%app_ . a)
(cond ((null? a) identity)
((null? (cdr a)) (car a))
((null? (cddr a)) ((car a) (cadr a)))
(else (apply %app ((car a) (cadr a)) (cddr a)))))
;; Macro optimization of the above
(define-syntax %app
(syntax-rules ()
((_) identity)
((_ fun) fun)
((_ fun arg) (fun arg))
((_ fun arg . more) (%app (fun arg) . more))
(_ %app_)))
;; Autocurrying anonymous function definition
(define-syntax fn
(syntax-rules ()
((_ () . body) (begin . body))
((_ (x) . body) (lambda (v) (defn x v) . body))
((_ (x . y) . body) (fn (x) (fn y . body)))
((_ v . body) (fn (v) . body)))) ;; also accept a single var without paren, same as with paren
;; Autocurrying named (potentially recursive) function definition
(define-syntax defn
(syntax-rules ()
((_ (pat . vars) . body)
(defn pat (fn vars . body)))
((_ v . body)
(begin
;; Allow autocurrying self-reference in the definition body as well as afterwards
(define-syntax v (syntax-rules () ((_ . a) (%app tmp . a))
(_ tmp)))
(define tmp (let () . body))))))