You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
define/curry - Defines an automatically currying procedure #5
;; Define a procedure like this:
(define/curry (insert-between mid left right)
(string-join (list left mid right) ""))
;; To use it like this:
(definedash-between (insert-between "-"))
(dash-between "left""right") ; "left-right";; Or currying wherever necessary:
(((insert-between "-") "left") "right") ; "left-right"
Before and After
This code-cleaning macro reduces some boilerplate necessary to define a curried function. Code like this:
(defineinsert-between
(curry
(λ (mid left right)
(string-join (list left mid right) ""))))
Is simplified to this, identical in form to defining a regular procedure:
(define/curry (insert-between mid left right)
(string-join (list left mid right) ""))
I wrote an earlier version of this macro when implementing some Haskell code in Racket, and thought it was useful enough to share!
Hi, Rotor! Thanks! Yes, I'm aware of that syntax. However as far as I understand it, that syntax doesn't allow you to do something like this. All of the following are equivalent:
Hi, Rotor! Thanks! Yes, I'm aware of that syntax. However as far as I understand it, that syntax doesn't allow you to do something like this. All of the following are equivalent:
@Fictitious-Rotor I updated with a link to the curry function's docs so that it doesn't look like my macro is doing any magic, and extended the example code a tiny bit. 👍
Small suggestion: move the syntax class to the toplevel. It'll have to go inside a (begin-for-syntax ....) and you will probably need to add for-syntax requires.
Annoying plumbing suggestion: use syntax/loc or quasisyntax/loc so that errors for things like (insert-between 1 2 3 4) point to the define/curry line instead of pointing to the lambda in the macro body.
Hi, @bennn! Thanks! I tried your suggestions. As for syntax/loc (which I didn't know about before, so that was cool to learn), I didn't notice any change adding it, and without it it seems to behave well, so I guess this is a case in which it's not needed? Like this:
(require (for-syntax syntax/parse))
(begin-for-syntax
(define-syntax-class name-params
#:description "name and parameters clause"
(pattern (name:id params:id ...+)
#:fail-when (check-duplicate-identifier
(syntax->list #'(params ...)))
"duplicate parameter name")))
(define-syntax (define/curry stx)
(syntax-parse stx
[(_ np:name-params body ...+)
#'(definenp.name
(curry (λ (np.params ...)
body ...)))]))
(define/curry (insert-between mid left right)
(string-join (list left mid right) ""))
(insert-between 2334444) ; This line gets highlighted with an error
Yeah you're right… I tried using syntax/loc but the behavior was the same. Maybe I'm just not using it right though. I tried surrounding both the define and the curry parts. I'll try again later using those functions, as it does seem like a useful thing in general to know for API ergonomics.
Activity
agj commentedon Jul 11, 2021
I'm not very experienced writing Racket or macros, so any improvement suggestions are welcome. 😊
[-]define/curry[/-][+]`define/curry` - Defines an automatically currying procedure[/+]Fictitious-Rotor commentedon Jul 12, 2021
This is a great little macro! Did you know, however, that there's another form for
definethat can achieve this?The docs show that the
headform in the grammar is recursive :)agj commentedon Jul 12, 2021
Hi, Rotor! Thanks! Yes, I'm aware of that syntax. However as far as I understand it, that syntax doesn't allow you to do something like this. All of the following are equivalent:
Fictitious-Rotor commentedon Jul 12, 2021
Oh wow you're totally right!
Perhaps you should add some of those examples to your original post!
agj commentedon Jul 13, 2021
@Fictitious-Rotor I updated with a link to the
curryfunction's docs so that it doesn't look like my macro is doing any magic, and extended the example code a tiny bit. 👍bennn commentedon Jul 15, 2021
Looks great!
Small suggestion: move the syntax class to the toplevel. It'll have to go inside a
(begin-for-syntax ....)and you will probably need to addfor-syntaxrequires.Annoying plumbing suggestion: use
syntax/locorquasisyntax/locso that errors for things like(insert-between 1 2 3 4)point to thedefine/curryline instead of pointing to the lambda in the macro body.agj commentedon Jul 16, 2021
Hi, @bennn! Thanks! I tried your suggestions. As for
syntax/loc(which I didn't know about before, so that was cool to learn), I didn't notice any change adding it, and without it it seems to behave well, so I guess this is a case in which it's not needed? Like this:(require (for-syntax syntax/parse)) (begin-for-syntax (define-syntax-class name-params #:description "name and parameters clause" (pattern (name:id params:id ...+) #:fail-when (check-duplicate-identifier (syntax->list #'(params ...))) "duplicate parameter name"))) (define-syntax (define/curry stx) (syntax-parse stx [(_ np:name-params body ...+) #'(define np.name (curry (λ (np.params ...) body ...)))])) (define/curry (insert-between mid left right) (string-join (list left mid right) "")) (insert-between 2 3 3 4 4 44) ; This line gets highlighted with an errorbennn commentedon Jul 16, 2021
Oh, that's great that the line with the function call gets highlighted.
When I run on the command line, though, it prints the function and says that function is defined on line 17 (inside the
define-syntax)Maybe a better way to phrase it is: get
(displayln insert-between)and(displayln (object-name insert-between))to print the right line.If the definition of
insert-betweenis in a different module than the macro, I think the name will be even more confusing.agj commentedon Jul 17, 2021
Yeah you're right… I tried using
syntax/locbut the behavior was the same. Maybe I'm just not using it right though. I tried surrounding both thedefineand thecurryparts. I'll try again later using those functions, as it does seem like a useful thing in general to know for API ergonomics.bennn commentedon Jul 22, 2021
Hint: the
λis what needs a locagj commentedon Aug 20, 2021
@bennn Sorry for taking so long! I got a bit busy and distracted, but I tried your hint just now and it worked great! Thanks for the tip.
add define/curry
add define/curry
add define/curry