But with the define-curry I’ve made here, if you do
(define-curry (foo bar baz bax) (+ bar baz bax))
Not only does the above map work (and give the same (513 523 533)
result). You can curry any of the arguments. All or none or just
some.
(define (((foo bar) baz) bax) (+ bar baz bax)) means that you
predict that you are gonna add on one argument first, and then the
other, and then the other.
Or you might want to take two arguments first and only leave one
argument hanging: (define ((foo bar baz) bax) (+ bar baz bax)) or
you might want to take one argument first and leavet two arguments
hanging: (define ((foo bar) baz bax) (+ bar baz bax))
You have to know before. The procedures aren’t flexible at all.
With (define-curry (foo bar baz bax) (+ bar baz bax)), you can call
foo with any number of arguments and it’ll wait for the rest.
You can even use it like any normal procedure and do (foo 10 200 3)
right away to get 213. Or you can do (foo 10 200) and wait for the
last number, or (foo 10) and wait for the last two numbers. And if
you do, you can even then only give it one and keep waiting even more
on that last number .You get a procedure that’s ready for anything!
That’s what I mean by arbitrary-arity, level-recursive currying.
All those forms evaluate to the same thing! That’s the baller part!
And (((foo) 100 20) 3) also or for that matter (((((foo)) 100)) 20 3).
This is great, all those times I’ve used a procedure and been like
“aw, man, I wish this was curried!”
If it had been curried (using the SRFI-219 style curries), that
would’ve gotten obnoxious quickly too, because I would’ve had to add
in those extra parens everytime I didn’t need the curry feature. I
would’ve had to always write ((((foo) 100) 20) 3) or whatever the
procedure-writer predicted I was gonna need to write.
That’s why this is awesome.
Now to the bonus episode. The define-curry I made is great when
defining new procedures but what about all the backlog of existing
procedures? Like + and print and list. I don’t wanna be bothered
to re-define all of them with define-curry, I want to be able to use
them and curry them as they are. That’s why I made 🍜 (yeah,
combinators and operators can be or contain emoji in Chicken Scheme).
I just prefix any function with 🍜 and it gains one level of arbitrary
arity curry. (🍜 list 1 1 2 3 5) becomes a procedure that waits for
more arguments to add to the list, so
((🍜 list 1 1 2 3 5) 8 13 21 34)
⇒ (1 1 2 3 5 8 13 21 34).
This is worse than the define-curry I made at the top of the post in
the sense that it only gives me one level of calls / parens. If I need
more levels, I need to add more 🍜.
((🍜 (🍜 list 1 1 2 3 5) 8 13) 21 34)
⇒ (1 1 2 3 5 8 13 21 34).
On the other hand, one part of the 🍜 combinator that is better than
my define-curry is that it can handle procedures that themselves are
already arbitrary-arity, like list and + and string-append. The
define-curry only works with procedures that have a specific number
of arguments. (In the case of the foo example, three arguments and
it always adds three numbers.) Also, again, that it works on already
existing procedures, not just newly defined ones.
This is a cool post on multiple levels. As an ocaml fan, it’s fun reading
about currying in Scheme. And kudos for 🍜 as an identifier! Functional programming, food, and puns: three of the good things in life.
Because I didn’t know about it! Post now updated to use 🍛, thank you!♥
Trying to making that change over SSH (which I failed to do, I had to get up and go to the desktop) reminded me that it’s probably better to use some other identifier for this combinator. Maybe just a letter, k or h or c or something. I originally wanted to make read-syntax, some special kind of parentheses or something for this.
Also
The only problem I see is that there are arbitrary arity procedures, and this define-curry would only work for fixed arity.
Yeah. As stated in the post and elaborated in threads here.
https://rosettacode.org/wiki/Currying#PicoLisp
That’s great but that’s not all this is.
The kind of stuff on that Rosetta page would be a simple
What I posted is a macro for arbitrary-arity, level-recursive currying, and (in the bonus episode) an arbitrary-arity currying functional combinator.
How does this differ to the currying syntax that some schemes provide directly in
define
orlambda
(https://srfi.schemers.org/srfi-219/)?Yes, a lot of schemes provide directly in a
lambda
ordefine
the ability to make something like this:That is an amazing construct, I’m into it, I’m happy Scheme can do it.
I made a post here about that type of curry a month ago and a comment about that type of curry an hour ago.
What I’ve made here is more awesome in the following way.
With
(define (((foo bar) baz) bax) (+ bar baz bax))
, you have to predict the arities exactly.Sure, you can do
and get
(513 523 533)
.But with the define-curry I’ve made here, if you do
Not only does the above map work (and give the same
(513 523 533)
result). You can curry any of the arguments. All or none or just some.(define (((foo bar) baz) bax) (+ bar baz bax))
means that you predict that you are gonna add on one argument first, and then the other, and then the other.Or you might want to take two arguments first and only leave one argument hanging:
(define ((foo bar baz) bax) (+ bar baz bax))
or you might want to take one argument first and leavet two arguments hanging:(define ((foo bar) baz bax) (+ bar baz bax))
You have to know before. The procedures aren’t flexible at all.
With
(define-curry (foo bar baz bax) (+ bar baz bax))
, you can callfoo
with any number of arguments and it’ll wait for the rest.You can even use it like any normal procedure and do
(foo 10 200 3)
right away to get 213. Or you can do(foo 10 200)
and wait for the last number, or(foo 10)
and wait for the last two numbers. And if you do, you can even then only give it one and keep waiting even more on that last number .You get a procedure that’s ready for anything!That’s what I mean by arbitrary-arity, level-recursive currying.
That’s why my example was:
All those forms evaluate to the same thing! That’s the baller part! And
(((foo) 100 20) 3)
also or for that matter(((((foo)) 100)) 20 3)
.This is great, all those times I’ve used a procedure and been like “aw, man, I wish this was curried!”
If it had been curried (using the SRFI-219 style curries), that would’ve gotten obnoxious quickly too, because I would’ve had to add in those extra parens everytime I didn’t need the curry feature. I would’ve had to always write
((((foo) 100) 20) 3)
or whatever the procedure-writer predicted I was gonna need to write.That’s why this is awesome.
Now to the bonus episode. The
define-curry
I made is great when defining new procedures but what about all the backlog of existing procedures? Like+
andprint
andlist
. I don’t wanna be bothered to re-define all of them withdefine-curry
, I want to be able to use them and curry them as they are. That’s why I made 🍜 (yeah, combinators and operators can be or contain emoji in Chicken Scheme).I just prefix any function with 🍜 and it gains one level of arbitrary arity curry.
(🍜 list 1 1 2 3 5)
becomes a procedure that waits for more arguments to add to the list, so⇒
(1 1 2 3 5 8 13 21 34)
.This is worse than the
define-curry
I made at the top of the post in the sense that it only gives me one level of calls / parens. If I need more levels, I need to add more 🍜.⇒
(1 1 2 3 5 8 13 21 34)
.On the other hand, one part of the 🍜 combinator that is better than my
define-curry
is that it can handle procedures that themselves are already arbitrary-arity, likelist
and+
andstring-append
. Thedefine-curry
only works with procedures that have a specific number of arguments. (In the case of thefoo
example, three arguments and it always adds three numbers.) Also, again, that it works on already existing procedures, not just newly defined ones.This is a cool post on multiple levels. As an ocaml fan, it’s fun reading about currying in Scheme. And kudos for 🍜 as an identifier! Functional programming, food, and puns: three of the good things in life.
It feels like The Little Schemer for 2021.
I don’t understand why the ramen emoji was chosen when there’s a perfectly good curry with rice emoji 🍛
Because I didn’t know about it! Post now updated to use 🍛, thank you!♥
Trying to making that change over SSH (which I failed to do, I had to get up and go to the desktop) reminded me that it’s probably better to use some other identifier for this combinator. Maybe just a letter, k or h or c or something. I originally wanted to make read-syntax, some special kind of parentheses or something for this.