Considering associate meta information to functions. Closures are at your service but the question I had is if we could make it more functional. The idea is that at each time the value of a handle is unique and cloning is done through copying. Also we would like this to work for higher order functions. I think that the following approach is quite interesting and fun.
Lets define a f-define for associating extra information to a function:
(define-Syntax-rule (f-lambda (f ...) (a ... . as) code ...)
(lambda (f ... a ...)
(call-with-values (lambda () code ...)
(lambda x
(values f ... x)))))
(define-syntax-rule (f-define (f fs ...) (arg ...) ((a p : c)...)
code ...)
(define f
(let lp ((a p) ...)
(define lam (f-lambda (f fs ...) (arg ...) code ...))
(lambda (n . args)
(case n
((get) (list a ...))
((reset) (lp p ...))
((call)
(apply
(lambda (fs ... arg ...)
(lam (lp c ...) fs ... arg ...))
args)))))))
The api is as follows f
is the function name. fs ...
is associated f-define functions used for higher order functions, arg ...
is the usual arguments to the function, a
is a meta variable, p
is it's initial value and c
is the updating code. Here is an example:
(f-define (f) (x) ((sx 0 : (+ sx x))
(sxx 0 : (+ sxx (* x x))))
(+ x 10))
the actual function will add 10 to x
along the usage sx
e.g. the sum of x
and sxx
the sum of squares will be collected.
whenever we call a f-defined function we do so with the f-call mechanism. e.g.
(define-syntax f-call
(lambda (x)
(syntax-case x ()
((_ (f fs ...) arg ...)
(with-syntax (((fsu ...) (generate-temporaries #'(fs ...))))
#'(call-with-values
(lambda ()
(f 'run fs ... arg ...))
(lambda (fu fsu ... . a)
(set! f fu)
(set! fs fsu) ...
(apply values a))))))))
The semantics is that all funciton arguments we update the value of them an the updated version of the function comes in the return values. We also set! the place holder of the function in order save typing (although this means that you typically break delimeted continuations). here is a higher order function:
(f-define (f-map f) (l) ((i 0 : (+ i 1)))
(if (pair? l)
(cons (f-call (f) (car l)) (f-call (f-map f) (cdr l)))
'()))
We see how we specify not one function but a list of functions in the first argument - this to indicate that f here should follow the return as a values semantics and update the placeholder. Let's add a few helpers more. This f-map
meta is the number of times it has been called.
(define (f-get f) (f 'get))
(define-syntax-rule (f-reset f) (set! f (f 'reset)))
f-get
get the meta and f-reset
restore the function to the initial state. Here is an output of the use. Notice how easy it is to clone. Just define a new place holder.
(f-call (f) 1)
(f-call (f) 2)
(pk '(f : 1 2) (f-get f))
--> ((f : 1 2) (3 5))
(define g f)
(f-call (f) 3)
(pk '(f : 1 2 3) (f-get f))
--> ((f : 1 2 3) (6 14))
(pk '(g : (f : 1 2)) (f-get g))
--> ((g : (f : 1 2)) (3 5))
(f-call (g) 3)
(pk '(g : (f : 1 2) 3) (f-get g))
--> ((g : (f : 1 2) 3) (6 14))
(f-reset g)
(pk '(g : reset) (f-get g))
--> ((g : reset) (0 0))
(f-call (f-map g) '(1 2))
(pk 'f-map-1 (f-get f-map))
--> (f-map-1 (3))
(pk '(g : 1 2) (f-get g))
--> ((g : 1 2) (3 5))
(f-call (f-map g) '(3 4))
(pk 'f-map-2 (f-get f-map))
--> (f-map-2 (6))
(pk '(g : 1 2 3 4) (f-get g))
--> ((g : 1 2 3 4) (10 30))