This is the second in a series of posts introducing Functional Programming concepts. Today we're looking at the closely related concepts of Currying and Partial Application.
Some Mystifying Code
Below is a fun piece of code, taken from our React and Redux course.
function logger(store) {
return function(nextMiddleware) {
return function(action) {
const oldValue = store.getState().total;
nextMiddleware(action);
const newValue = store.getState().total;
console.log("Logger: State went from ${oldValue} to ${newValue}");
}
}
}
Or if you prefer it in ES6 format:
const logger = store => nextMiddleware => action => {
const oldValue = store.getState().total;
nextMiddleware(action);
const newValue = store.getState().total;
console.log("Logger: state went from ${oldValue} to ${newValue}");
};
If you remember from the first article in this series Redux is a data store that can be used by JavaScript Web Apps to cache data. Changes in the Redux store are initiated by the arrival of actions, where an action is any JavaScript object with a type property. An additional feature is that Redux allows you to install any number of middleware functions, where a middleware function can intercept incoming actions and perform arbitrary pre or post-processing.
As you can see from this 'hello world' example a middleware function is implemented as a function which takes the Redux store and returns a function that takes the next piece of middleware and returns a function that takes the current action and does something. Obvious really ;-)
To be more explicit:
- You provide a function to Redux that takes the current store
- This should build and return a function that takes the next middleware
- This should build and return a function that takes the action dispatched by the UI
- This performs pre-processing, forwards on the action and performs post-processing
Developers not familiar with functional patterns will wonder why they settled on such a bizarre arrangement. Let me try and break down why any architect would go in this direction by taking a more familiar example from OO, the venerable Command Design Pattern.
Command Pattern V1 - Classic OO
The Command Pattern is one of the most popular Gof4 patterns in the software industry, especially in Web Frameworks from Struts onwards. Here's the simplest example I can think of coded in Scala.
Let's say we want to implement a game and need to avoid an 'if ladder' when it comes to writing the event handling code. So instead of a lengthy and unwieldy conditional we have a table of command objects, keyed against the name of the event type.
class Event {}
abstract class Command {
def execute(e : Event)
}
class StartCommand extends Command {
override def execute(e : Event)= println("starting to play")
}
class StopCommand extends Command {
override def execute(e : Event)= {
println("Bye...")
System.exit(0)
}
}
class SaveCommand extends Command {
override def execute(e : Event)= println("saving current game")
}
class LoadCommand extends Command {
override def execute(e : Event)= println("loading a new game")
}
object NullCommand extends Command {
override def execute(e : Event)= println("WOT?")
}
object Program1 {
def main(args: Array[String]): Unit = {
val commands = Map("start" -> new StartCommand(),
"stop" -> new StopCommand(),
"save" -> new SaveCommand(),
"load" -> new LoadCommand())
while(true) {
val eventName = readLine("What do you want to do?\n")
commands.getOrElse(eventName,NullCommand).execute(new Event())
}
}
}
When an event occurs we simply extract the appropriate command object and invoke its execute
method. There is a special NullCommand
singleton type that can be used to handle all unknown events. Heres some sample output:
What do you want to do?
start
starting to play
What do you want to do?
load
loading a new game
What do you want to do?
save
saving current game
What do you want to do?
wibble
WOT?
What do you want to do?
stop
Bye...
Command Pattern V2 - FP
It may surprise you to discover that the functional version of this code is much shorter and simpler. We can shed the unnecessary scaffolding of classes and use lambdas for simple actions and named functions for complex ones:
object Program2 {
type CmdMap = Map[String, Event => Unit]
def stop(): Unit = {
println("Bye...")
System.exit(0)
}
def main(args: Array[String]): Unit = {
val commands : CmdMap = Map(("start", _ => println("starting to play")),
("stop" , _ => stop()),
("save" , _ => println("saving current game")),
("load" , _ => println("loading a new game")))
while(true) {
val eventName = readLine("What do you want to do?\n")
commands.getOrElse(eventName, (_:Event) => println("WOT?")).apply(new Event())
}
}
}
In general any pattern that uses a hierarchy of types to model tasks can be simplified via FP concepts.
Command Pattern V3: OO with Properties
Now OO stalwarts will be thinking that this is unfair on the pattern. One of the advantages of Command
is that it provides a convenient way to associate state with your event handlers. Let's assume that we need to pass around a Properties
object containing, amongst other things, the users name. We have this at startup time but it wont be readily available when events are dispatched, so the logical choice is to pass into the base class constructor like so:
class Event {}
abstract class Command(private val props : Properties) {
def name() = props.getProperty("name")
def execute(e : Event)
}
class StartCommand(val p : Properties) extends Command(p) {
override def execute(e : Event)= println("starting to play " + name() )
}
class StopCommand(val p : Properties) extends Command(p) {
override def execute(e : Event)= {
println("Bye " + name())
System.exit(0)
}
}
class SaveCommand(val p : Properties) extends Command(p) {
override def execute(e : Event)= println("saving current game " + name())
}
class LoadCommand(val p : Properties) extends Command(p) {
override def execute(e : Event)= println("loading a new game " + name())
}
object NullCommand extends Command(new Properties()) {
override def execute(e : Event)= println("WOT?")
}
object Program3 {
def main(args: Array[String]): Unit = {
val props = new Properties()
props.setProperty("name","Dave")
val commands = Map("start" -> new StartCommand(props),
"stop" -> new StopCommand(props),
"save" -> new SaveCommand(props),
"load" -> new LoadCommand(props))
while(true) {
val eventName = readLine("What do you want to do?\n")
commands.getOrElse(eventName, NullCommand).execute(new Event())
}
}
}
Here's the adjusted output:
What do you want to do?
start
starting to play Dave
What do you want to do?
load
loading a new game Dave
What do you want to do?
save
saving current game Dave
What do you want to do?
wibble
WOT?
What do you want to do?
stop
Bye Dave
Command Pattern V4: FP with Properties
The functional community have a neat solution to this as well, in the form of higher order functions. In the code below you can see that all our event handlers are now named functions that take both a Properties
object and an event. However what we are storing in the table is the result of invoking wrapInProps
.
This takes a properties object and a function of signature (Properties, Event) => Unit
and returns a function of signature (Event) => Unit
. In other words we have simplified a function that takes two inputs into a function that takes only one. In other words we have curried the function.
class Event {}
object Program4 {
type CmdMap = Map[String, Event => Unit]
def wrapUpProps(p : Properties, f : (Properties, Event) => Unit) = {
(e : Event) => f(p,e)
}
def name(p : Properties) = p.getProperty("name")
def start(p : Properties, e : Event) = println("starting to play " + name(p))
def save(p : Properties, e : Event) = println("saving current game " + name(p))
def load(p : Properties, e : Event) = println("loading a new game " + name(p))
def stop(p : Properties, e : Event): Unit = {
println("Bye " + name(p))
System.exit(0)
}
def main(args: Array[String]): Unit = {
val props = new Properties()
props.setProperty("name","Dave")
val commands : CmdMap = Map(("start", wrapUpProps(props,start)),
("stop" , wrapUpProps(props,stop)),
("save" , wrapUpProps(props,save)),
("load" , wrapUpProps(props,load)))
while(true) {
val eventName = readLine("What do you want to do?\n")
commands.getOrElse(eventName, (_:Event) => println("WOT?")).apply(new Event())
}
}
}
Command Pattern V5: OO with Properties and Locales
Let's add an extra level of complexity to see this trick performed one more time. Assume that the event handlers also need a Locale
object that can be used to internationalise messages. It may not be required in many circumstances but we need to make sure its always available. Let's say the Locale isn't available on setup, so the conventional OO solution would be to supply it later via some form of initialisation method:
class Event {}
class Locale {}
abstract class Command(private val props : Properties) {
protected var locale : Locale = null
def init(locale : Locale) = {
this.locale = locale
}
def name() = props.getProperty("name")
def execute(e : Event)
}
class StartCommand(val p : Properties) extends Command(p) {
override def execute(e : Event)= println("starting to play " + name() )
}
class StopCommand(val p : Properties) extends Command(p) {
override def execute(e : Event)= {
println("Bye " + name())
System.exit(0)
}
}
class SaveCommand(val p : Properties) extends Command(p) {
override def execute(e : Event)= println("saving current game " + name())
}
class LoadCommand(val p : Properties) extends Command(p) {
override def execute(e : Event)= println("loading a new game " + name())
}
object NullCommand extends Command(new Properties()) {
override def execute(e : Event)= println("WOT?")
}
object Program5 {
def main(args: Array[String]): Unit = {
val locale = new Locale()
val props = new Properties()
props.setProperty("name","Dave")
val commands = Map("start" -> new StartCommand(props),
"stop" -> new StopCommand(props),
"save" -> new SaveCommand(props),
"load" -> new LoadCommand(props))
commands.values.foreach(_.init(locale))
while(true) {
val eventName = readLine("What do you want to do?\n")
commands.getOrElse(eventName, NullCommand).execute(new Event())
}
}
}
As you can see we add an init
method to the Command
base class and then forEach
over the commands to invoke it before we enter the event handling loop.
Command Pattern V6: FP with Properties and Locales
The functional solution would be to modify our existing wrapper function and create a new one.
Firstly we extend wrapUpProps
so the function input is of type (Properties, Locale, Event) => Unit
and the output of type (Locale,Event) => Unit
. Secondly we add a wrapUpLocale
function that takes a function input of type (Locale,Event) => Unit
and returns one of (Event) => Unit
. Although we are applying both at the same time in main
there is no reason why we couldn't have an intermediate result.
class Event {}
class Locale {}
object Program6 {
type CmdMap = Map[String, Event => Unit]
def wrapUpProps(p : Properties, f : (Properties,Locale,Event) => Unit) = {
(l : Locale, e : Event) => f(p,l,e)
}
def wrapUpLocale(l : Locale, f : (Locale, Event) => Unit) = {
(e : Event) => f(l,e)
}
def name(p : Properties) = p.getProperty("name")
def start(p : Properties, l : Locale, e : Event) = println("starting to play " + name(p))
def save(p : Properties, l : Locale, e : Event) = println("saving current game " + name(p))
def load(p : Properties, l : Locale, e : Event) = println("loading a new game " + name(p))
def stop(p : Properties, l : Locale, e : Event): Unit = {
println("Bye " + name(p))
System.exit(0)
}
def main(args: Array[String]): Unit = {
val locale = new Locale()
val props = new Properties()
props.setProperty("name","Dave")
val commands : CmdMap = Map(("start", wrapUpLocale(locale,wrapUpProps(props,start))),
("stop" , wrapUpLocale(locale,wrapUpProps(props,stop))),
("save" , wrapUpLocale(locale,wrapUpProps(props,save))),
("load" , wrapUpLocale(locale,wrapUpProps(props,load))))
while(true) {
val eventName = readLine("What do you want to do?\n")
commands.getOrElse(eventName, (_:Event) => println("WOT?")).apply(new Event())
}
}
}
Command Pattern V7: FP with Partial Invocation
A more formal definition of currying is that we convert a single function that takes 'n' arguments into a chain of functions, each of which takes a single argument. So the solution above solves our problems but doesn't yet meet the definition. To get there with minimal effort we can use Scala's support for Partial Invocation.
In Scala, a function can be given multiple parameter lists and when invoked only the first list need be provided. The others can be omitted, using underscores as placeholders, which directs the compiler to wrap the invocation up in a generated function. Here's a solution implemented using Partial Invocation. Note the multiple parameter lists on the event handlers and the use of the underscore when creating the command map:
class Event {}
class Locale {}
object Program4 {
type CmdMap = Map[String, Event => Unit]
def name(p : Properties) = p.getProperty("name")
def start(p : Properties)(l : Locale)(e : Event) = println("starting to play " + name(p))
def save(p : Properties)(l : Locale)(e : Event) = println("saving current game " + name(p))
def load(p : Properties)(l : Locale)(e : Event) = println("loading a new game " + name(p))
def stop(p : Properties)(l : Locale)(e : Event): Unit = {
println("Bye " + name(p))
System.exit(0)
}
def main(args: Array[String]): Unit = {
val locale = new Locale()
val props = new Properties()
props.setProperty("name","Dave")
val commands : CmdMap = Map(("start", start(props)(locale)_),
("stop" , stop(props)(locale)_),
("save" , save(props)(locale)_),
("load" , load(props)(locale)_))
while(true) {
val eventName = readLine("What do you want to do?\n")
commands.getOrElse(eventName, (_:Event) => println("WOT?")).apply(new Event())
}
}
}
Command Pattern V8: FP with Partial Invocation and Staged Initialisation
To make our solution equivalent to the OO one let's create an intermediate table of event handlers, where the handlers have been given the Properties
object but not the Locale
. Note that we require a separate type definition TmpMap
to tell the compiler what the type of the functions will be. This means that we cannot accidentally forget to pass in the Locale
object, as could be the case with the OO solution and init
method. To convert one map to another we can use the standard mapValues
function.
class Event {}
class Locale {}
object Program8 {
type TmpMap = Map[String, Locale => Event => Unit]
type CmdMap = Map[String, Event => Unit]
def name(p : Properties) = p.getProperty("name")
def start(p : Properties)(l : Locale)(e : Event) = println("starting to play " + name(p))
def save(p : Properties)(l : Locale)(e : Event) = println("saving current game " + name(p))
def load(p : Properties)(l : Locale)(e : Event) = println("loading a new game " + name(p))
def stop(p : Properties)(l : Locale)(e : Event): Unit = {
println("Bye " + name(p))
System.exit(0)
}
def main(args: Array[String]): Unit = {
val locale = new Locale()
val props = new Properties()
props.setProperty("name","Dave")
val tmp : TmpMap = Map(("start", (start(props)(_))(_)),
("stop" , (stop(props)(_))(_)),
("save" , (save(props)(_))(_)),
("load" , (load(props)(_))(_)))
val commands : CmdMap = tmp.mapValues(f => f(locale))
while(true) {
val eventName = readLine("What do you want to do?\n")
commands.getOrElse(eventName, (_:Event) => println("WOT?")).apply(new Event())
}
}
}
Returning to Our Original Example
To sum up, we have seen how Currying and Partial Invocation are a good choice when:
- We want to invoke a function with multiple inputs
- These inputs will be available at different times
- There is no convenient place to cache the inputs
If we return to the original example of Redux Middleware we can see that all three points apply.
The middleware function:
- Will need the action to do anything useful
- Will require the next middleware to forward on the action
- May potentially need the store itself
However, each of these will be available at different times. The store is always there, the middleware is arranged on setup and actions become available as the store is used. Finally, since Redux is a minimalist framework that integrates with a wide variety of UI's there is no obvious place to cache the inputs until needed.
Conclusions
Hopefully this article has helped clarify some FP terminology, shown how FP concepts compliment OO ones and illustrate how FP concepts and the terminology are being used in emerging frameworks. In the next in the series we will tackle the Jabberwockey of FP concepts - Monads.
If you enjoyed this, why not check out our React and Redux course or one of our Scala courses (Fast-track to Scala or Scala Programming for Java Developers).