FYI there's a lesson about this: https://purelyfunctional.tv/lesson/partial/
Currying and partial function application are just about the same thing. Let's say you have a function with three arguments
(defn my-fn-3 [a b c]
It doesn't matter what it does. But let's say we know the first argument already, but we don't know the others. We could keep the argument around in a variable and then use it when we finally know
c. But where do we put the variable? We have to have it in the right scope, etc.
There's another thing we can do, which is to make a new function that already has the
a closed inside it:
(defn my-fn-2 [b c]
(my-fn-3 17 b c))
Notice that we have the first argument already defined, and the other two arguments are passed along. What if we want to do it again?
(defn my-fn-1 [c]
(my-fn-2 "hello" c))
And we can do it again until there are no more arguments.
This pattern is so regular we can write a function that does this for us. In Clojure, it's called
Let's write our own version:
(defn partial* [f x]
(fn [& unknown-args]
(apply f x unknown-args)))
Notice you pass it a function and one known argument. It returns a new function that applies the function to your known argument followed by all the arguments you don't know yet.
This is how you would run it:
(def my-fn-2 (partial* my-fn-3 17))
(def my-fn-1 (partial* my-fn-2 "hello"))
Do take a look at the API docs and ClojureDocs examples. It's more sophisticated than the simple one I wrote above.
Currying is basically the language doing this for you automatically. Haskell does that, for instance. It's actually a really cool principle: you only need functions of one argument. Any function of two arguments
b can be made with a function that takes
a and returns a function that takes
b. Which is the same principle that
I hope that helps!