Eduardo Cavazos wrote:
Now, it would be nice to be able to say:
(define-typed (abc #(seq "string"))
(nth seq 2))
But that has at least one problem.
So, any suggestions for how to approach 'define-typed'?
Derick Eddington wrote:
Here's a way. It requires coordination with the macros like nth.
(define-syntax nth
(syntax-rules ()
((_ #(expr "list") n)
(list-ref expr n))
((_ #(expr "vector") n)
(vector-ref expr n))
((_ #(expr "string") n)
(string-ref expr n))
((_ spec n)
(spec n))))
(define-syntax define-typed
(lambda (stx)
(syntax-case stx ()
((_ (name #(arg type) ...) . body)
(with-syntax
(((t ...) (generate-temporaries (syntax (arg ...)))))
(syntax
(define (name t ...)
(let-syntax ((arg (make-variable-transformer
(lambda (stx)
(syntax-case stx (set!)
((_ n)
(syntax (nth #(t type) n)))
(_ (identifier? stx)
(syntax t))
((set! _ val)
(syntax (set! t val)))))))
...)
. body))))))))
(define-typed (foo #(s "string") #(l "list"))
(values (nth s 2) (nth l 3)))
(foo "abc" (quote (a b c d)))
=>
#\c
d
Next step is to decouple everything. I.e. be able to have a library
'(sequence-protocol)' with stuff like:
(define-generic nth ...)
(define-generic len ...)
etc ...
These get registered somewhere.
Then other libraries like (sequence-list), (sequence-string), etc. can
flesh out the protocol for specific sequence types. These libraries add
"methods" to the generics. They have the effect of annotating the
generic registries.
Finally, 'define-typed' consults this generic registry to do "the right
thing".
No problemo. ;-)
Ed