What is the best way to wrap a function that accepts keyword arguments with a function that provides defaults for some of those arguments?
Here’s one way:
#lang racket
(define (g x y #:a a #:b b)
(list x y a b))
(define f
(make-keyword-procedure
(λ (kws kw-args . rest)
(keyword-apply g kws kw-args 3 rest #:b 4))))
(f 1 #:a 2)
; '(3 1 2 4)
Ohh, I just saw “default” in your post. I think the above code will not work, since it doesn’t allow overriding the “default” value.
E.g.,
(f 1 #:a 2 #:b 10)
fails with:
keyword-apply: keyword duplicated in list and direct keyword arguments: '#:b
Maybe something like this?
#lang racket
(require kw-utils/kw-hash-lambda
kw-utils/kw-hash)
(define (g x y #:a a #:b b)
(list x y a b))
(define f
(kw-hash-lambda rest-args #:kws kw-hash
(apply/kw-hash g
(hash-update kw-hash '#:b values 4)
rest-args)))
(f 1 2 #:a 3)
; '(1 2 3 4)
(f 1 2 #:a 3 #:b 5)
; '(1 2 3 5)
Why not just the following? (define (g a #:b b #:c c)
(list a b c))
(define (f a #:b [ b 7 ] #:c [ c 8 ])
(g a #:b b #:c c))
Well, the above versions could be abstracted out even further:
#lang racket
(require kw-utils/kw-hash-lambda
kw-utils/kw-hash
racket/hash)
(define with-default
(kw-hash-case-lambda #:kws def-hash
[(f)
(kw-hash-lambda rest-args #:kws kw-hash
(apply/kw-hash f
(hash-union kw-hash def-hash #:combine (λ (a b) a))
rest-args))]))
(define (g x y #:a a #:b b)
(list x y a b))
(define f (with-default g #:b 4))
(f 1 2 #:a 3)
; '(1 2 3 4)
(f 1 2 #:a 3 #:b 5)
; '(1 2 3 5)
which is probably the kind of interface that @aymano.osman wants. No repetition of the args.