The third article in the series Code Jugalbandi in HealthyCode Magazine. This time we are exploring Functional Programming with Currying and Partial Function Application melody. What is Code Jugalbandi? Check out http://codejugalbandi.org, follow us on @CodeJugalbandi.
1. Healthy Code
March - 2015
10
In 2013, Dhaval Dalal was inspired by Jugalbandi, an Indian classical music
form in which musicians have an improvised musical conversation, each using a
different instrument, while exploring a shared musical theme together akin to Jazz
in some ways. Dhaval thought, “What if we could have a conversation about some
programming concepts in this way? Instead of musical instruments, what if we use
different programming languages?”
Code
Jugalbandi
Article
Ryan and Dhaval
2. Healthy Code
March - 2015
11
Creator and Listener
We met regularly with over a period of several months,
exploring some key issues related to Functional
Programming(FP).ThisculminatedinaliveCodeJugalbandi
at the Functional Conference in Bengaluru, 2014. During
the FP Code Jugalbandi, we explored nine themes, which
becamemelodies. Similar to the musical Jugalbandi, there
are two roles: creator and listener. We called the creator of
the melody Bramha and the one who listens and responds
with a different instrument, Krishna. In the last Code
Jugalbandi Article, we looked at the melody, the Sequencing
problem. This time we will look at Currying and Partial
Function Application (PFA).
Currying in Groovy
BRAMHA: Imagine, I have an HTTP request for a customer
in our web application and we want to authorize the
request.I’ll use Groovy here to do that.
def req1 = [‘id’: 1]
def customer = authorizer(repo, req1)
println customer.name
BRAMHA: Let’s write down the customer repository
quickly.
class CustomerRepository {
def findBy(Integer id) {
if(id > 0) {
[id: id, name: “Cust Name #$id”]
}
else {
throw new RuntimeException(‘cust not found’)
}
}
}
BRAMHA: and I’ll write authorizer as a closure that
consumes two parameters, repository and request.
def authorizer = { rep, req -> rep.findBy(req.id) }
BRAMHA: Now let’s say that, before I can request the
customer, I need to make sure that the user is authorized to
access it.
def repo = new CustomerRepository()
def req1 = [‘id’: 1]
def req2 = [‘id’: 2]
def cust1 = authorizer(repo, req1)
def cust2 = authorizer(repo, req2)
BRAMHA: If you look at the above. I’m repeatedly
injecting CustomerRepository reference when calling
authorizer. Could I somehow convert this authorizer to just
accept request; the parameter that varies while fixing the
repository? This is where I’ll resort to currying the repository.
def auth = authorizer.curry(repo)
def cust1 = auth(req1)
def cust2 = auth(req2)
BRAMHA: I’ve re-shaped the authorizer to a single argument
function from a two-argument function. Along similar lines
I’ll write an authenticator that takes in an authorizer and http-
request and re-shape it to just accept request.
def authenticator = { rep, req -> rep(req) }
def auth = authenticator.curry(authorizer.
curry(repo))
def cust1 = auth(req1)
BRAMHA: We used currying to re-shape the functions so
that we can chain them and the request can flow through
each of them.
BRAMHA: Let me show you some Scala code that does the
same thing.
Currying in Scala
case class Customer(id: Int, name: String)
class CustomerRepository {
def findBy(id: Int): Option[Customer] =
if (id > 0)
Some(Customer(id, s”Customer Name #
This led to the first Code Jugalbandi between us. Code Jugalbandi inspired and fuelled
our learning by focussing on dialogue and exploration. More languages in the room
meant more perspectives too. Exploring a paradigm through many languages gave us a
better map of the territory than any single language could. Above all, Code Jugalbandi
was a playful way to learn together!
3. Healthy Code
March - 2015
12
KRISHNA: With partial function application, and currying,
for that matter, the order of arguments matter! e.g. what if
we wanted to fix the second argument instead of the first?
(def new-ada (partial new-person title “Ada”))
(new-ada “Ms” “Lovelace”)
KRISHNA: But this doesn’t make sense, because we
somehow need to have a placeholder for the first param,
which we don’t want to partially apply. So, when we’re
partially applying argument to a function, it works from left
to right. We can’t only apply the third argument and not also
the first and second arguments. We can wire in values for the
arguments, from left to right.
We can’t wire in only the second param, but I can always
achieve this with a lambda:
(def new-ada
(fn [title lname]
(new-person title “Ada” lname)))
(new-ada “Ms” “Lovelace”)
KRISHNA: Fortunately, Clojure has a macro to synthesise
this kind of “ad-hoc” partial function application:
(def new-ada-f
#(new-person %1 “Ada” %2))
(new-ada-f “Ms” “Lovelace”)
KRISHNA: I’m sure Scala has this kind of thing too, right?
Partial Function Application in Scala
BRAMHA: Sure, let me show this in Scala. I do partial
functionapplicationonnew_personbyputtinginplaceholders
for its second and third parameters, and just bind title
def new_person(title: String, fname: String, lname:
String) = s”$title $fname $lname”
val new_ms = new_person(“Ms”, _: String, _: String)
new_ms(“Ada”, “Lovelace”)
BRAMHA This time, I do partial function application
on fname by putting in placeholders for its first and last
parameters.
val new_ada = new_person(_: String, “Ada”, _:
String) new_ada(“Ms”, “Lovelace”
KRISHNA: Scala’s syntax is definitely superior to Clojure’s
in the sense that regular and ad-hoc partial function
application is unified.
BRAMHA: Also, in Scala, if you have a function in curried
form, that is, a function of one argument at a time, it’s trivial
to convert it to the uncurried form, and vice versa.
$id”))
else
None
}
type Request = Map[String, Int]
def authenticator(f: Request => Option[Customer])
(req: Request): Option[Customer] = f(req)
def authorizer(rep: CustomerRepository)(req:
Request): Option[Customer] = req.get(“id”).
flatMap(id => rep.findBy(id))
val authorize = authorizer _
val authenticate = authenticator _
val auth = authenticate(authorize(new Customer
Repository))
val req1 = Map(“id” -> 1)
val cust1 = auth(req1)
BRAMHA: If you observe the above code, unlike Groovy,
I don’t invoke any special method to do currying, by using
multi-parameter functions, Scala gives you currying for free.
All I do here is convert the methods authorizer and
authenticator to function type using partial function
application by using underscore(). This gives me _
authorize, having type CustomerRepository (Request
Option[Customer])functionobject.Italsogivesmeauthenticate,
having type (Request Option[Customer]) (Request
Option[Customer]) function object.
Itheninjecttherepositoryinauthorizeandbecauseofcurrying
it then gets re-shaped into a function that goes from Request
Option[Customer]. This type then directly aligns as input
parameter to the authenticate function.
Partial Function Application in Clojure
KRISHNA: Let’s look at partial function application in
Clojure and start with this function with three arguments.
(defn new-person [title f-name l-name]
{ :title title,
:f-name f-name,
:l-name l-name
})
(new-person “Ms” “Ada” “Lovelace”)
KRISHNA: What if I wanted to partially apply the title to
this function?
(def new-ms (partial new-person “Ms”))
(new-ms “Ada” “Lovelace”)
KRISHNA: I’ve reshaped the function by wiring in the first
argument.
4. Healthy Code
March - 2015
13
val fUncurried = Function.uncurried(f)
val fCurried = fUncurried.curried
Currying in Haskell
KRISHNA In Haskell, functions are curried by default, you
don’t have any special syntax like Scala.
make_person :: String -> String -> String -> String
make_person s fname lname = s ++ fname ++ lname
main = putStrLn (make_person “Ms” “Ada” “Lovelace”)
-- above is same as
main = putStrLn ((make_person “Ms”) “Ada” “Lovelace”)
-- is same as
main = putStrLn (((make_person “Ms”) “Ada”)
“Lovelace”)
BRAMHA: Groovy also offers right curry - rcurry and curry
a particular parameter at a position - ncurry, but I think they
are more like PFArather than actual currying that we usually
see from left to right.
Reflections
KRISHNA This shows the difference between Currying and
PFA. With PFA, we are just dealing with regular functions
of multiple arguments; essentially fixing a few arguments
and returning a function with fewer arguments. However,
Currying refers to functions that take only one argument
at a time! You can think of a Curried function as a nested
structure, just like Russian dolls: for each argument, there
is another nested function, that takes that argument and
returns a function taking the subsequent arg, and so on, until
all the arguments are exhausted.
BRAMHA: In FP, we can achieve Dependency Injection
(DI) by passing functions around and thereby injecting
behaviour. But currying and PFA also offer a way to achieve
DI: for a function that takes either functions as arguments or
just regular parameters, when we curry such an argument,
we are injecting dependency.Also, depending on the context,
we can change the concrete dependency. For example, when
the context is driving design through tests, we can inject
a MockCustomerRepository, whereas in production we would
inject the real CustomerRepository.
KRISHNA: Yes, that’s why it’s quite commonly used in web
frameworks to inject locale and other contextual information
when creating a request.
BRAMHA: In a language that deals well with PFA, you
won’t really miss currying, because you’ll use PFA where
you would have used currying.
Also, “ad-hoc PFA” is practically more powerful than
currying in some ways. With currying, you have to curry
strictly from left to right, with PFA you can do ad-hoc
application of args.
KRISHNA: Currying and PFA gives us a way to reshape -
and repurpose - our functions for different use cases, without
having to explicitly “wrap” the old function with a different
argument list.
References
Learn more from http://codejugalbandi.org
Ryan is a software developer,
coach and advisor, based in Cape
Town. He has been working with
code for more than 15 years. Ryan
assists individuals and teams
to manage the evolution and
complexity of their software
systems. Ryan is a passionate
learner and enjoys facilitating
learning in others.
Dhavalahands-ondeveloperand
mentor, believes that software
development is first an art and
then a craft. For him writing
software brings his creativity
to the fore. His interests are in
architecting applications ground
up, estabilishing environments,
transitioning and orienting
teams to Agile way of working
by embedding himself within
teams.
You can follow them on Twitter @
CodeJugalbandi