https://github.com/technologicat/spicy
Automatic currying for Racket
https://github.com/technologicat/spicy
curry currying example racket racket-lang
Last synced: 3 months ago
JSON representation
Automatic currying for Racket
- Host: GitHub
- URL: https://github.com/technologicat/spicy
- Owner: Technologicat
- License: lgpl-3.0
- Created: 2018-04-11T22:42:45.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2018-09-04T10:26:28.000Z (almost 7 years ago)
- Last Synced: 2025-01-20T06:14:07.130Z (5 months ago)
- Topics: curry, currying, example, racket, racket-lang
- Language: Racket
- Size: 15.6 KB
- Stars: 6
- Watchers: 3
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# spicy: Automatic currying for Racket
```racket
#lang spicy(define (map f)
(foldr (compose cons f) empty))(module+ main
(define a '(1 2 3))
(define (f x) (* x x))
(map f a))
```Compare **not** spicy:
```racket
#lang racket(define (->1 f) (λ (a b) (values (f a) b)))
(define (map f . args)
(apply curry foldr (compose cons (->1 f)) empty args))(module+ main
(define a '(1 2 3))
(define (f x) (* x x))
(map f a))
```For fewer parentheses, combine spicy with [sweet-exp](https://docs.racket-lang.org/sweet/):
```racket
#lang sweet-exp spicydefine map(f)
foldr (compose cons f) emptymodule+ main
define a '(1 2 3)
define (f x) (* x x)
map f a
```To spice locally, `spicy/sauce`:
```racket
#lang sweet-exp racketrequire spicy/sauce
module+ main
with-curry
define mymap-local(f)
foldr (compose cons f) empty
mymap-local
λ (x) {x * x}
'(1 2 3)
;
splicing-with-curry
define mymap(f)
foldr (compose cons f) empty
;; now autocurry is off
(mymap (λ (x) {x * x}))
'(1 2 3)
```## Examples
Some more simple examples, based on those in [Hughes (1984): Why functional programming matters](http://www.cse.chalmers.se/~rjmh/Papers/whyfp.pdf) and racketified.
- [Spicy, with traditional s-expressions](example_sexp.rkt)
- [Spicy, with sweet expressions](example_sweet.rkt)
- [Not spicy](example_nonspicy.rkt)For details, take the [tour](tour.rkt).
## Human-readable rules
- All function applications are curried. Currying is applied from the left.
- Keyword arguments can be passed in the initial call, just like when currying manually in Racket.
- Any arguments over max-arity are *passed through on the right*, by constructing a multiple-values object.
- This makes the above example possible, although the arities of `f` and `cons` are different.
- If the application also returns a multiple-values, the remaining arguments (if any) are appended into it.
- If the application produces only one value, which is another curried procedure, it is applied to the remaining arguments.
- See the [tour](tour.rkt) for where this is useful.
- The auto-curried procedure immediately switches to the mode where *any acceptable arity* triggers a call.
- In contrast, currying manually in Racket always curries at least once (if a higher arity exists).
- Hence some variadic functions (notably e.g. `+`, `*`) cannot be auto-curried in `spicy`, since they accept any arity ≥ 0.
- Curry manually to revert to Racket's usual processing: `+ 1` → 1, but `curry + 1` → `#`.
- It will still use the customized `curry` function from `spicy`, but skips the automatic mode switching.## Installation
- Copy the files anywhere you want.
- Open a terminal in the `spicy/` subfolder.
- `raco pkg install`To uninstall, `raco pkg remove spicy`.
## How it works
Essentially, a custom `#%app` macro to rewrite function applications at compile time, a customized `curry`, and [four lines of code](spicy/main.rkt) to package that as a language that borrows everything else from Racket.
Also, the [`compose`](https://docs.racket-lang.org/reference/procedures.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._compose%29%29) function is overridden by a curry-aware version, which spices its arguments.
## Disclaimer
Primarily meant for teaching purposes. Tested only on toy examples.
Not completely seamless, and cannot be. Automatic currying and variadic functions do not play well together; also, dynamic typing implies that the system won't notice if you miss an argument somewhere - which may make your code hard to debug. For discussion on the topic, see e.g. [here](https://stackoverflow.com/questions/11218905/is-it-possible-to-implement-auto-currying-to-the-lisp-family-languages), [here](http://paqmind.com/blog/currying-in-lisp/) and [here](https://stackoverflow.com/questions/31373507/rich-hickeys-reason-for-not-auto-currying-clojure-functions).
## License
[GNU LGPL 3.0](https://www.gnu.org/licenses/lgpl-3.0.html).
Contains a customized version of Racket's [`curry`](https://docs.racket-lang.org/reference/procedures.html#%28def._%28%28lib._racket%2Ffunction..rkt%29._curry%29%29), which is [used under](https://download.racket-lang.org/license.html) GNU LGPL 3.0.
## Dependencies
- [sweet-exp](https://docs.racket-lang.org/sweet/) is currently used by the implementation in [spicy/expander.rkt](spicy/expander.rkt).