Consider the following fishy example wherein we try to
reuse a function with keyword arguments.
(define (fish #:name [name #f]
#:color [color #f]
#:studio [studio #f]
#:eyes [eyes 2])
(~a "The fish " name " is " color ", appears in a movie from " studio " and has " eyes " eyes."))
Let's check see an example:
> (fish #:name "Nemo" #:color "orange" #:studio "Disney")
"The fish Nemo is orange, appears in a movie from Disney and has 2 eyes."
A few examples later one quickly realizes that Disney has
a lot of fish in their movies:
(fish #:name "Nemo" #:color "orange" #:studio "Disney")
(fish #:name "Dory" #:color "blue" #:studio "Disney")
(fish #:name "Marlin" #:color "orange" #:studio "Disney")
(fish #:name "Wanda" #:color "gold" #:studio "MGM")
(fish #:name "Blinky" #:color "orange" #:studio "Fox" #:eyes 3)
No worries, we can quickly define a disney-fish that simply
calls fish using the #:studio keyword and passes other keywords
along. The new disney-fish must accept the same keywords as fish
(except for the studio one), so procedure-reduce-keyword-arity
is needed to restrict the accepted keywords.
(define disney-fish
(let ()
(define (make-disney-fish kws kw-args . rest)
(keyword-apply/sort fish kws kw-args rest #:studio "Disney"))
(define-values (fish-required fish-allowed) (procedure-keywords fish))
(define fish-arity (procedure-arity fish)) ; number of by-position arguments
(procedure-reduce-keyword-arity
(make-keyword-procedure make-disney-fish)
fish-arity
(remove '#:studio fish-required)
(remove '#:studio fish-allowed))))
Now we can write:
(disney-fish #:name "Nemo" #:color "orange")
The new disney-fish accepts only keywords accepted by fish,
so any error reporting works as expected.
But ... the above solution wasn't quick - it took more work than I initially expected.
Am I missing something that makes reusing functions accepting
keyword arguments easier?
/Jens Axel
-- full example --
#lang racket
(require kw-utils/keyword-apply-sort)
(define (fish #:name [name #f]
#:color [color #f]
#:studio [studio #f]
#:eyes [eyes 2])
(~a "The fish " name " is " color ", appears in a movie from " studio " and has " eyes " eyes."))
(fish #:name "Nemo" #:color "orange" #:studio "Disney")
(fish #:name "Dory" #:color "blue" #:studio "Disney")
(fish #:name "Marlin" #:color "orange" #:studio "Disney")
(fish #:name "Blinky" #:color "orange" #:studio "Fox" #:eyes 3)
(define disney-fish
(let ()
(define (make-disney-fish kws kw-args . rest)
(keyword-apply/sort fish kws kw-args rest #:studio "Disney"))
(define-values (fish-required fish-allowed) (procedure-keywords fish))
(define fish-arity (procedure-arity fish)) ; number of by-position arguments
(procedure-reduce-keyword-arity
(make-keyword-procedure make-disney-fish)
fish-arity
(remove '#:studio fish-required)
(remove '#:studio fish-allowed))))
(disney-fish #:name "Nemo" #:color "orange"
#:studio "foo")
; Notes:
; > (disney-fish #:name "Nemo" #:color "orange" #:studio "Disney")
; correctly shows error (#:studio not expected)