SlideShare a Scribd company logo
Making Your Program Spicy
Currying
and
Partial Function Application (PFA)
Dhaval Dalal
@softwareartisan
https://dhavaldalal.wordpress.com
14th Nov 2019
• Refers to the phenomena of rewriting a N-arg function
to a nest of functions, each taking only 1-arg at a time
Currying
// (String, Integer) -> String

String merge(String x, Integer y) {

return x + y.toString();

}

// String -> (Integer -> String)

Function<Integer, String> merge(String x) {

return y -> x + y.toString();

}

// () -> (String -> (Integer -> String))

Function<String, Function<Integer, String>> merge() {

return x -> y -> x + y.toString();

}
// (String -> (Integer -> String))

Function<String, Function<Integer, String>> merge = x -> y -> x + y.toString();

System.out.println(merge("Test#", 1)); // Test#1

System.out.println(merge("Test#").apply(2)); // Test#2

System.out.println(merge().apply("Test#").apply(3)); // Test#3
System.out.println(merge.apply("Test#").apply(4)); // Test#4
Currying
For each arg, there is
another nested function,
that takes a arg and
returns a function taking
the subsequent arg, until
all the args are exhausted.
f : (T, U, V) ↦ R
f′ : T ↦ U ↦ V ↦ R
f = f′
• Curried function is a nested structure, just like Russian
dolls, takes one arg at a time, instead of all the args at once.
Currying
• Function type associates towards right.
• In other words, arrow groups towards right.
Function<String, Function<Integer, String>> merge = 

x ->
y ->
x + y.toString();
x -> y -> x + y.toString();
// is same as
x -> (y -> x + y.toString());
• Function application associates towards left. In
other words, apply() groups towards left.
merge.apply("Test#").apply(1);
// is same as
(merge.apply("Test#")).apply(1);
Why Currying?
• Facilitates arguments to be applied from different
scopes.
Function<Integer, Function<Integer, Integer>> add =
x ->
y ->
x + y;
Function<Integer, Integer> increment = add.apply(1);
increment.apply(2); // 3
Function<Integer, Integer> decrement = add.apply(-1);
decrement.apply(2); // 1
• Helps us reshape and re-purpose the original function
by creating a partially applied function from it
Function<Integer, Function<Integer, Integer>> add =
x ->
y ->
x + y; Scope 1
Scope 2
But, how does that
make programming
spicier?
• Let’s say we have a Customer repository.
• Now, we want to allow authorised calls to repo. So,
Let’s write an authorise function.
class CustomerRepository {

Optional<Customer> findById(Integer id) {

return (id > 0) ? Optional.of(new Customer(id)) 

: Optional.empty();

} 

}
class Authoriser {

public Optional<Customer> authorise(CustomerRepository repo, Request
request) {

System.out.println("Authorizing Request#" + request.id);

// Some auth code here which guards the request.

// On success, the line below is executed.

return repo.findById(Integer.parseInt(request.get("customer_id")));

}

}
• We also have a Request.
• Lets see them in action…
class Request {

public final int id;

private Map<String, String> params = new HashMap<>();



Request(int id) { this.id = id; }

String set(String key, String value) { return params.put(key, value); } 

String get(String key) { return params.get(key); }

}
var authoriser = new Authoriser();

var repo = new CustomerRepository();



var request1 = new Request(1) {{ set("customer_id", "10"); }};



var customer1 = authoriser.authorise(repo, request1);

System.out.println(customer1);



var request2 = new Request(2) {{ set("customer_id", "30"); }};

var customer2 = authoriser.authorise(repo, request2);

System.out.println(customer2);
• Requests vary, however the CustomerRepository is
same.

• Can we avoid repeated injection of the repo?
Solution 1
Optional<Customer> authorise(Request req) {
CustomerRepository repo = new CustomerRepository();
return repo.findById(req.get());
}
Authoriser authoriser = new Authoriser();
Request req1 = new Request();
var customer1 = authoriser.authorise(req1);
Request req2 = new Request();
var customer2 = authoriser.authorise(req2);
• Wrap the authorise function in another function (also
called authorise)
• Requests vary, however the CustomerRepository is
same.

• Can we avoid repeated injection of the repo?
Solution 1
Optional<Customer> authorise(Request req) {
CustomerRepository repo = new CustomerRepository();
return repo.findById(req.get());
}
Authoriser authoriser = new Authoriser();
Request req1 = new Request();
var customer1 = authoriser.authorise(req1);
Request req2 = new Request();
var customer2 = authoriser.authorise(req2);
But
newification
locally like
this is
untestable!
• Wrap the authorise function in another function (also
called authorise)
Solution 2
class Authoriser {
public
Function<Request, Optional<Customer>> authorise(CustomerRepository repo) {
return req -> {
//Some auth code here which guards the request.
repo.findById(req.get());
}
}
}
var repo = new CustomerRepository();
Function<Request, Optional<Customer>> curriedAuthorise = authorise(repo);
Request req1 = new Request();
var customer1 = curriedAuthorise.apply(req1);
Request req2 = new Request();
var customer2 = curriedAuthorise.apply(req2);
• Re-shape authorise to accept only one fixed
parameter - CustomerRepository
Need some more
spice?
interface Transaction { }
interface ApprovalStrategy {
boolean approve(List<Transaction> ts);
//…
}
class Clearing {
private final ApprovalStrategy as;
Clearing(ApprovalStrategy as) {
this.as = as;
}
public boolean approve(List<Transaction> ts) {
return as.approve(ts);
}
}
//main
ApprovalStrategy singleMakerChecker = new SingleMakerChecker();
Clearing clearing = new Clearing(singleMakerChecker);
clearing.approve(ts);
Regular DI
Curried DI
interface Transaction { }
interface ApprovalStrategy {
boolean approve(List<Transaction> ts);
//…
}
class Clearing {
public
Function<List<Transaction>, Boolean> approve(ApprovalStrategy as) {
return ts -> as.approve(ts);
}
}
//main
Clearing clearing = new Clearing();
// ApprovalStrategy can now be injected from different contexts,
// one for production and a different one - say mock for testing,
// Just like in case of Regular DI.
clearing.approve(new SingleMakerChecker()).apply(ts);
Making Our Own Curry
<T, U, R>
Function<T, Function<U, R>> curry(BiFunction<T, U, R> fn) {
return t -> u -> fn.apply(t, u);
}
// Function with all args applied at the same time.
BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
// Curried Function - one arg at a time.
Function<Integer, Function<Integer, Integer>> cAdd = curry(add);
Function<Integer, Integer> increment = cAdd.apply(1);
increment.apply(2); // 3
Function<Integer, Integer> decrement = cAdd.apply(-1);
decrement.apply(2); // 1
It would be nice if
Java8 provided this
out-of-box on
BiFunction
Scala calls
this curried
Uncurry or Tuple it!
<T, U, R>
BiFunction<T, U, R> uncurry(Function<T, Function<U, R>> fn) {
return (t, u) -> fn.apply(t).apply(u);
}
// Curried Function - one arg at a time.
Function<Integer, Function<Integer, Integer>> add = x -> y -> x + y;
// Function with all args applied at the same time.
BiFunction<Integer, Integer, Integer> ucAdd = uncurry(add);
ucAdd.apply(2, 3); // 5
It would be nice if
Java8 provided this
out-of-box on
Function
Scala calls
this uncurried
Currying in Scala
scala> def merge1(x: String, y: Int) = x + y.toString
merge1: (x: String, y: Int)String
scala> val merge1F = merge1 _
merge1F: (String, Int) => String
scala> def merge2(x: String)(y: Int) = x + y.toString

scala> val merge2F = merge2 _
merge2F: String => (Int => String)
scala> val mergeTest = merge2F("Test#")
mergeTest: Int => String
scala> mergeTest(1)
res1: Test#1
scala> mergeTest(2)
res2: Test#2
• Scala uses special syntax for currying - It does not use
tupled arguments, instead uses multiple function call
syntax in the definition to denote a curried function.
Curry Uncurry
scala> def merge1(x: String, y: Int) = x + y.toString
merge1: (x: String, y: Int)String
scala> val merge1F = merge1 _
merge1F: (String, Int) => String
scala> val merge1FCurried = merge1F.curried
merge1FCurried: String => (Int => String)
scala> def merge2(x: String)(y: Int) = x + y.toString

scala> val merge2F = merge2 _
merge2F: String => (Int => String)
scala> val merge2FUncurried = Function.uncurried(merge2F)
merge2FUncurried: (String, Int) => String
Scala
PFA in Scala
// Partially Applied Function or Partial Function Application (PFA)

def greet(salutation: String, fname: String, lname: String)
= s"$salutation. $fname $lname"

println(greet("Mr", "Dhaval", "Dalal")) // Mr Dhaval Dalal
def new_ms = greet("Ms", _: String, _: String)
// (String, String) => String

println(new_ms("Ada", "Lovelace")) // Ms Ada Lovelace



def new_drew = greet(_: String, _: String, "Drew")

(String, String) => String
println(new_drew("Ms", "Nancy")) // Ms Nancy Drew
• Supply a value to partially apply the function and to
leave out the arguments unapplied, use underscore “_”

• Note: PFA is different from Partial Function
Re-shaping Third Party
Library Functions
• In third-party libraries we may never be able to
modify the code. 

• Use Currying/PFA to simplify the callers interface.
def power(n: Double) = Math.pow(_: Double, n)

val square = power(2)

println(square(2)) // 4.0



val cube = power(3)

println(cube(2)) // 8.0
Currying in Haskell
greet :: String -> String -> String -> String

greet salutation fname lname = salutation ++ ". " ++ fname ++ " " ++ lname



main :: IO ()

main = do

print $ greet "Mr" "Dhaval" "Dalal" -- Mr Dhaval Dalal

let greet_mr = greet "Mr"

print (greet_mr "Joe" "Shmo") -- Mr Joe Shmo

let greet_mr_joe = greet "Mr" "Joe"

print (greet_mr_joe "Sober") -- Mr Joe Sober

print "Done!"
• In Haskell, all the functions are curried by default,
you don’t need special syntax for that.

• It does not have Partially Applied Functions.
Currying in Haskell
Prelude> :type (*)
(*) :: Num a => a -> a -> a
Prelude> multiply2 = (*2)
Prelude> :type multiply2
multiplyBy2 :: Num a => a -> a
Prelude> multiply2 3
6
• Even operators are
curried by default.
Prelude> :type filter
filter :: (a -> Bool) -> [a] -> [a]
Prelude> even = x -> x `mod` 2 == 0
Prelude> filterEvens = filter even
Prelude> :type filterEvens
filterEvens :: Integral a => [a] -> [a]
Prelude> filterEvens [0..10]
[2,4,6,8,10]
Prelude> filterOdds = filter (not . even)
Prelude> filterOdds [0..10]
[1,3,5,7,9]
• Yet another
example…
PFA in Clojure
(defn new-person [salutation f-name l-name]

(println salutation f-name l-name))



(new-person "Mr." "Dhaval" "Dalal") ; Mr Dhaval Dalal
(def new-ms (partial new-person "Ms"))

(new-ms "Ada" "Lovelace") ; Ms Ada Lovelace
• Lets partially apply title to this function…
• Lets now partially apply title and first-name
(def new-ms-ada (partial new-person "Ms" "Ada"))

(new-ms-ada "Lovelace") ; Ms Ada Lovelace
PFA in Clojure
• What if we want to fix the third arg - last name
instead of the 1st?
(def new-dalal (partial new-person salutation f-name "Dalal"))

(new-dalal "Mr" “Dhaval")
; The above code won't compile
• This is because we need placeholder for 1st and 2nd
args, which we don’t want to apply., we can’t directly
apply the 3rd argument. 

• In Clojure, with partial function application the order of
arguments matters. Its from left to right. This is just
like currying.

• So, what do we do?
Lambda to the rescue
• We wrap this in a lambda!
(def new-dalal (fn [sal fname]

(new-person sal fname "Dalal")))
(new-dalal "Mr." "Dhaval") ; Mr. Dhaval Dalal
• Doing this by hand every time is tedious!

• Fortunately, Clojure has a macro to synthesise this
kind of "ad-hoc" partial function application
(def new-dalal #(new-person %1 %2 "Dalal")) ; Mr. Dhaval Dalal

(new-dalal "Mr." "Dhaval") ; Mr. Dhaval Dalal
(def new-ada #(new-person %1 "Ada" %2))

(new-ada "Ms." "Lovelace") ; Ms Ada Lovelace

(new-ada "Mrs." "???") ; Mrs. Ada ???
Currying in Groovy
def filterList = { filter, list -> list.findAll(filter) }

def even = { it % 2 == 0 }

def evens = filterList.curry(even)

println evens(0..10) // [0, 2, 4, 6, 8, 10]



def not = { !it }

def odds = filterList.curry(even >> not) // even andThen not

println odds(0..10) // [1, 3, 5, 7, 9]
• In Groovy, we need to explicitly call the curry
method on closure!
• It curries from left to right
def merge = { x, y, z ->

println "arg0: x = $x"

println "arg1: y = $y"

println "arg2: z = $z"

"$x$y$z"

}

println merge.curry(10)('Hello', new Date()) // 10Hello<Date>

println merge.curry(10, 'Hello')(new Date()) // 10Hello<Date>
Currying in Groovy
• And if you need to curry from right-to-left, use rcurry()
def merge = { x, y, z ->

println "arg0: x = $x"

println "arg1: y = $y"

println "arg2: z = $z"

"$x$y$z"

}

println merge.rcurry(10)('Hello', new Date()) // Hello<Date>10

println merge.rcurry(10, 'Hello')(new Date()) // <Date>10Hello
• And for currying at a index, use ncurry()
println merge.ncurry(1, new Date())(10, 'Hello') //10<Date>Hello

println merge.ncurry(0, new Date(), 'Hello')(10) //<Date>Hello10
Reflections
• You curry strictly from left-to-right.

• We don’t have to provide all the arguments to the
function at one go! This is partially applying the function. 

• In other words, Currying enables Partial Function
Application, a.k.a - Partially Applied Function (PFA).

• "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

• 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.
References
• Code Jugalbandi (http://codejugalbandi.org)

• Exploring Functional Programming - Ryan Lemmer and
Dhaval Dalal

• https://github.com/CodeJugalbandi/FunctionalProgramming/
tree/master/melodies/currying

• Healthy Code Magazine Code Jugalbandi Article 

• https://www.slideshare.net/DhavalDalal/3-code-
jugalbandicurryingpfahealthycodemagazinemar2015
Thank - You!
https://github.com/DhavalDalal/FunctionalConference-2019-Currying-PFA-Demo

More Related Content

What's hot (20)

PDF
JavaScript Functions
Colin DeCarlo
 
PDF
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Mario Fusco
 
PDF
Lambdas and Streams Master Class Part 2
José Paumard
 
PDF
Booting into functional programming
Dhaval Dalal
 
PPT
Swiss army knife Spring
Mario Fusco
 
PPTX
LinkedIn TBC JavaScript 100: Functions
Adam Crabtree
 
PDF
If You Think You Can Stay Away from Functional Programming, You Are Wrong
Mario Fusco
 
PDF
Functional Javascript
guest4d57e6
 
PDF
Pragmatic functional refactoring with java 8
RichardWarburton
 
PDF
Lambda and Stream Master class - part 1
José Paumard
 
PPTX
Java 7, 8 & 9 - Moving the language forward
Mario Fusco
 
PDF
Refactoring to Java 8 (Devoxx BE)
Trisha Gee
 
PDF
Object Design - Part 1
Dhaval Dalal
 
PPT
JavaScript Functions
Brian Moschel
 
PDF
Reactive Programming for a demanding world: building event-driven and respons...
Mario Fusco
 
PDF
Leveraging Completable Futures to handle your query results Asynchrhonously
David Gómez García
 
PPTX
Java script advance-auroskills (2)
BoneyGawande
 
PPTX
Clean code slide
Anh Huan Miu
 
PDF
Sneaking inside Kotlin features
Chandra Sekhar Nayak
 
PDF
Java9 Beyond Modularity - Java 9 más allá de la modularidad
David Gómez García
 
JavaScript Functions
Colin DeCarlo
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Mario Fusco
 
Lambdas and Streams Master Class Part 2
José Paumard
 
Booting into functional programming
Dhaval Dalal
 
Swiss army knife Spring
Mario Fusco
 
LinkedIn TBC JavaScript 100: Functions
Adam Crabtree
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
Mario Fusco
 
Functional Javascript
guest4d57e6
 
Pragmatic functional refactoring with java 8
RichardWarburton
 
Lambda and Stream Master class - part 1
José Paumard
 
Java 7, 8 & 9 - Moving the language forward
Mario Fusco
 
Refactoring to Java 8 (Devoxx BE)
Trisha Gee
 
Object Design - Part 1
Dhaval Dalal
 
JavaScript Functions
Brian Moschel
 
Reactive Programming for a demanding world: building event-driven and respons...
Mario Fusco
 
Leveraging Completable Futures to handle your query results Asynchrhonously
David Gómez García
 
Java script advance-auroskills (2)
BoneyGawande
 
Clean code slide
Anh Huan Miu
 
Sneaking inside Kotlin features
Chandra Sekhar Nayak
 
Java9 Beyond Modularity - Java 9 más allá de la modularidad
David Gómez García
 

Similar to Currying and Partial Function Application (PFA) (20)

PDF
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
Dhaval Dalal
 
PDF
Pragmatic functional refactoring with java 8 (1)
RichardWarburton
 
PDF
Functional Programming for OO Programmers (part 2)
Calvin Cheng
 
PDF
Functional programming java
Maneesh Chaturvedi
 
PDF
Learning Functional Programming Without Growing a Neckbeard
Kelsey Gilmore-Innis
 
PDF
Pragmatic Functional Refactoring with Java 8
Codemotion
 
PPTX
Functional programming in javascript
Boris Burdiliak
 
PDF
Immutability and pure functions
sparkfabrik
 
PPTX
Taxonomy of Scala
shinolajla
 
PDF
Functional Programming with Groovy
Arturo Herrero
 
PPTX
Thinking Functionally with JavaScript
Luis Atencio
 
PDF
Functional Programming inside OOP? It’s possible with Python
Carlos V.
 
ODP
Functional programming
S M Asaduzzaman
 
PPTX
Curry functions in Javascript
Anand Kumar
 
PDF
Functional JS for everyone - 4Developers
Bartek Witczak
 
PDF
Functional Programming in JavaScript
Will Livengood
 
PDF
this
偉格 高
 
PDF
Functional Programming with JavaScript
WebF
 
PDF
Design Patterns in the 21st Century - Samir Talwar
JAXLondon2014
 
PDF
Design patterns in the 21st Century
Samir Talwar
 
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
Dhaval Dalal
 
Pragmatic functional refactoring with java 8 (1)
RichardWarburton
 
Functional Programming for OO Programmers (part 2)
Calvin Cheng
 
Functional programming java
Maneesh Chaturvedi
 
Learning Functional Programming Without Growing a Neckbeard
Kelsey Gilmore-Innis
 
Pragmatic Functional Refactoring with Java 8
Codemotion
 
Functional programming in javascript
Boris Burdiliak
 
Immutability and pure functions
sparkfabrik
 
Taxonomy of Scala
shinolajla
 
Functional Programming with Groovy
Arturo Herrero
 
Thinking Functionally with JavaScript
Luis Atencio
 
Functional Programming inside OOP? It’s possible with Python
Carlos V.
 
Functional programming
S M Asaduzzaman
 
Curry functions in Javascript
Anand Kumar
 
Functional JS for everyone - 4Developers
Bartek Witczak
 
Functional Programming in JavaScript
Will Livengood
 
Functional Programming with JavaScript
WebF
 
Design Patterns in the 21st Century - Samir Talwar
JAXLondon2014
 
Design patterns in the 21st Century
Samir Talwar
 
Ad

More from Dhaval Dalal (20)

PDF
Sri-Aurobindos-Integral-Education-Principles.pdf
Dhaval Dalal
 
PDF
Test Pyramid in Microservices Context
Dhaval Dalal
 
PDF
Code Retreat
Dhaval Dalal
 
PDF
Json Viewer Stories
Dhaval Dalal
 
PDF
Value Objects
Dhaval Dalal
 
PDF
Mars rover-extension
Dhaval Dalal
 
PDF
How Is Homeopathy Near To Yoga?
Dhaval Dalal
 
PDF
Approaching ATDD/BDD
Dhaval Dalal
 
PDF
Paradigms Code jugalbandi
Dhaval Dalal
 
PDF
Data Reconciliation
Dhaval Dalal
 
PDF
CodeRetreat
Dhaval Dalal
 
PDF
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
Dhaval Dalal
 
PDF
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
Dhaval Dalal
 
PDF
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
Dhaval Dalal
 
PDF
The tao-of-transformation-workshop
Dhaval Dalal
 
PDF
Grooming with Groovy
Dhaval Dalal
 
PDF
Language portfolio
Dhaval Dalal
 
PDF
Code jugalbandi
Dhaval Dalal
 
PDF
A case-for-graph-db
Dhaval Dalal
 
PDF
Transition contours
Dhaval Dalal
 
Sri-Aurobindos-Integral-Education-Principles.pdf
Dhaval Dalal
 
Test Pyramid in Microservices Context
Dhaval Dalal
 
Code Retreat
Dhaval Dalal
 
Json Viewer Stories
Dhaval Dalal
 
Value Objects
Dhaval Dalal
 
Mars rover-extension
Dhaval Dalal
 
How Is Homeopathy Near To Yoga?
Dhaval Dalal
 
Approaching ATDD/BDD
Dhaval Dalal
 
Paradigms Code jugalbandi
Dhaval Dalal
 
Data Reconciliation
Dhaval Dalal
 
CodeRetreat
Dhaval Dalal
 
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
Dhaval Dalal
 
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
Dhaval Dalal
 
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
Dhaval Dalal
 
The tao-of-transformation-workshop
Dhaval Dalal
 
Grooming with Groovy
Dhaval Dalal
 
Language portfolio
Dhaval Dalal
 
Code jugalbandi
Dhaval Dalal
 
A case-for-graph-db
Dhaval Dalal
 
Transition contours
Dhaval Dalal
 
Ad

Recently uploaded (20)

PDF
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
PPTX
ChiSquare Procedure in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
PPTX
AEM User Group: India Chapter Kickoff Meeting
jennaf3
 
PPTX
Tally software_Introduction_Presentation
AditiBansal54083
 
PPTX
Home Care Tools: Benefits, features and more
Third Rock Techkno
 
PDF
Generic or Specific? Making sensible software design decisions
Bert Jan Schrijver
 
PPTX
Empowering Asian Contributions: The Rise of Regional User Groups in Open Sour...
Shane Coughlan
 
PDF
4K Video Downloader Plus Pro Crack for MacOS New Download 2025
bashirkhan333g
 
PPTX
Help for Correlations in IBM SPSS Statistics.pptx
Version 1 Analytics
 
PDF
AI + DevOps = Smart Automation with devseccops.ai.pdf
Devseccops.ai
 
PDF
iTop VPN With Crack Lifetime Activation Key-CODE
utfefguu
 
PPTX
OpenChain @ OSS NA - In From the Cold: Open Source as Part of Mainstream Soft...
Shane Coughlan
 
PDF
NEW-Viral>Wondershare Filmora 14.5.18.12900 Crack Free
sherryg1122g
 
PDF
Digger Solo: Semantic search and maps for your local files
seanpedersen96
 
PPTX
Agentic Automation Journey Series Day 2 – Prompt Engineering for UiPath Agents
klpathrudu
 
PDF
Automate Cybersecurity Tasks with Python
VICTOR MAESTRE RAMIREZ
 
PPTX
Customise Your Correlation Table in IBM SPSS Statistics.pptx
Version 1 Analytics
 
PDF
TheFutureIsDynamic-BoxLang witch Luis Majano.pdf
Ortus Solutions, Corp
 
PDF
Technical-Careers-Roadmap-in-Software-Market.pdf
Hussein Ali
 
PDF
[Solution] Why Choose the VeryPDF DRM Protector Custom-Built Solution for You...
Lingwen1998
 
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
ChiSquare Procedure in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
AEM User Group: India Chapter Kickoff Meeting
jennaf3
 
Tally software_Introduction_Presentation
AditiBansal54083
 
Home Care Tools: Benefits, features and more
Third Rock Techkno
 
Generic or Specific? Making sensible software design decisions
Bert Jan Schrijver
 
Empowering Asian Contributions: The Rise of Regional User Groups in Open Sour...
Shane Coughlan
 
4K Video Downloader Plus Pro Crack for MacOS New Download 2025
bashirkhan333g
 
Help for Correlations in IBM SPSS Statistics.pptx
Version 1 Analytics
 
AI + DevOps = Smart Automation with devseccops.ai.pdf
Devseccops.ai
 
iTop VPN With Crack Lifetime Activation Key-CODE
utfefguu
 
OpenChain @ OSS NA - In From the Cold: Open Source as Part of Mainstream Soft...
Shane Coughlan
 
NEW-Viral>Wondershare Filmora 14.5.18.12900 Crack Free
sherryg1122g
 
Digger Solo: Semantic search and maps for your local files
seanpedersen96
 
Agentic Automation Journey Series Day 2 – Prompt Engineering for UiPath Agents
klpathrudu
 
Automate Cybersecurity Tasks with Python
VICTOR MAESTRE RAMIREZ
 
Customise Your Correlation Table in IBM SPSS Statistics.pptx
Version 1 Analytics
 
TheFutureIsDynamic-BoxLang witch Luis Majano.pdf
Ortus Solutions, Corp
 
Technical-Careers-Roadmap-in-Software-Market.pdf
Hussein Ali
 
[Solution] Why Choose the VeryPDF DRM Protector Custom-Built Solution for You...
Lingwen1998
 

Currying and Partial Function Application (PFA)

  • 1. Making Your Program Spicy Currying and Partial Function Application (PFA) Dhaval Dalal @softwareartisan https://dhavaldalal.wordpress.com 14th Nov 2019
  • 2. • Refers to the phenomena of rewriting a N-arg function to a nest of functions, each taking only 1-arg at a time Currying // (String, Integer) -> String
 String merge(String x, Integer y) {
 return x + y.toString();
 }
 // String -> (Integer -> String)
 Function<Integer, String> merge(String x) {
 return y -> x + y.toString();
 }
 // () -> (String -> (Integer -> String))
 Function<String, Function<Integer, String>> merge() {
 return x -> y -> x + y.toString();
 } // (String -> (Integer -> String))
 Function<String, Function<Integer, String>> merge = x -> y -> x + y.toString();
 System.out.println(merge("Test#", 1)); // Test#1
 System.out.println(merge("Test#").apply(2)); // Test#2
 System.out.println(merge().apply("Test#").apply(3)); // Test#3 System.out.println(merge.apply("Test#").apply(4)); // Test#4
  • 3. Currying For each arg, there is another nested function, that takes a arg and returns a function taking the subsequent arg, until all the args are exhausted. f : (T, U, V) ↦ R f′ : T ↦ U ↦ V ↦ R f = f′ • Curried function is a nested structure, just like Russian dolls, takes one arg at a time, instead of all the args at once.
  • 4. Currying • Function type associates towards right. • In other words, arrow groups towards right. Function<String, Function<Integer, String>> merge = 
 x -> y -> x + y.toString(); x -> y -> x + y.toString(); // is same as x -> (y -> x + y.toString()); • Function application associates towards left. In other words, apply() groups towards left. merge.apply("Test#").apply(1); // is same as (merge.apply("Test#")).apply(1);
  • 5. Why Currying? • Facilitates arguments to be applied from different scopes. Function<Integer, Function<Integer, Integer>> add = x -> y -> x + y; Function<Integer, Integer> increment = add.apply(1); increment.apply(2); // 3 Function<Integer, Integer> decrement = add.apply(-1); decrement.apply(2); // 1 • Helps us reshape and re-purpose the original function by creating a partially applied function from it Function<Integer, Function<Integer, Integer>> add = x -> y -> x + y; Scope 1 Scope 2
  • 6. But, how does that make programming spicier?
  • 7. • Let’s say we have a Customer repository. • Now, we want to allow authorised calls to repo. So, Let’s write an authorise function. class CustomerRepository {
 Optional<Customer> findById(Integer id) {
 return (id > 0) ? Optional.of(new Customer(id)) 
 : Optional.empty();
 } 
 } class Authoriser {
 public Optional<Customer> authorise(CustomerRepository repo, Request request) {
 System.out.println("Authorizing Request#" + request.id);
 // Some auth code here which guards the request.
 // On success, the line below is executed.
 return repo.findById(Integer.parseInt(request.get("customer_id")));
 }
 }
  • 8. • We also have a Request. • Lets see them in action… class Request {
 public final int id;
 private Map<String, String> params = new HashMap<>();
 
 Request(int id) { this.id = id; }
 String set(String key, String value) { return params.put(key, value); } 
 String get(String key) { return params.get(key); }
 } var authoriser = new Authoriser();
 var repo = new CustomerRepository();
 
 var request1 = new Request(1) {{ set("customer_id", "10"); }};
 
 var customer1 = authoriser.authorise(repo, request1);
 System.out.println(customer1);
 
 var request2 = new Request(2) {{ set("customer_id", "30"); }};
 var customer2 = authoriser.authorise(repo, request2);
 System.out.println(customer2);
  • 9. • Requests vary, however the CustomerRepository is same. • Can we avoid repeated injection of the repo? Solution 1 Optional<Customer> authorise(Request req) { CustomerRepository repo = new CustomerRepository(); return repo.findById(req.get()); } Authoriser authoriser = new Authoriser(); Request req1 = new Request(); var customer1 = authoriser.authorise(req1); Request req2 = new Request(); var customer2 = authoriser.authorise(req2); • Wrap the authorise function in another function (also called authorise)
  • 10. • Requests vary, however the CustomerRepository is same. • Can we avoid repeated injection of the repo? Solution 1 Optional<Customer> authorise(Request req) { CustomerRepository repo = new CustomerRepository(); return repo.findById(req.get()); } Authoriser authoriser = new Authoriser(); Request req1 = new Request(); var customer1 = authoriser.authorise(req1); Request req2 = new Request(); var customer2 = authoriser.authorise(req2); But newification locally like this is untestable! • Wrap the authorise function in another function (also called authorise)
  • 11. Solution 2 class Authoriser { public Function<Request, Optional<Customer>> authorise(CustomerRepository repo) { return req -> { //Some auth code here which guards the request. repo.findById(req.get()); } } } var repo = new CustomerRepository(); Function<Request, Optional<Customer>> curriedAuthorise = authorise(repo); Request req1 = new Request(); var customer1 = curriedAuthorise.apply(req1); Request req2 = new Request(); var customer2 = curriedAuthorise.apply(req2); • Re-shape authorise to accept only one fixed parameter - CustomerRepository
  • 13. interface Transaction { } interface ApprovalStrategy { boolean approve(List<Transaction> ts); //… } class Clearing { private final ApprovalStrategy as; Clearing(ApprovalStrategy as) { this.as = as; } public boolean approve(List<Transaction> ts) { return as.approve(ts); } } //main ApprovalStrategy singleMakerChecker = new SingleMakerChecker(); Clearing clearing = new Clearing(singleMakerChecker); clearing.approve(ts); Regular DI
  • 14. Curried DI interface Transaction { } interface ApprovalStrategy { boolean approve(List<Transaction> ts); //… } class Clearing { public Function<List<Transaction>, Boolean> approve(ApprovalStrategy as) { return ts -> as.approve(ts); } } //main Clearing clearing = new Clearing(); // ApprovalStrategy can now be injected from different contexts, // one for production and a different one - say mock for testing, // Just like in case of Regular DI. clearing.approve(new SingleMakerChecker()).apply(ts);
  • 15. Making Our Own Curry <T, U, R> Function<T, Function<U, R>> curry(BiFunction<T, U, R> fn) { return t -> u -> fn.apply(t, u); } // Function with all args applied at the same time. BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y; // Curried Function - one arg at a time. Function<Integer, Function<Integer, Integer>> cAdd = curry(add); Function<Integer, Integer> increment = cAdd.apply(1); increment.apply(2); // 3 Function<Integer, Integer> decrement = cAdd.apply(-1); decrement.apply(2); // 1 It would be nice if Java8 provided this out-of-box on BiFunction Scala calls this curried
  • 16. Uncurry or Tuple it! <T, U, R> BiFunction<T, U, R> uncurry(Function<T, Function<U, R>> fn) { return (t, u) -> fn.apply(t).apply(u); } // Curried Function - one arg at a time. Function<Integer, Function<Integer, Integer>> add = x -> y -> x + y; // Function with all args applied at the same time. BiFunction<Integer, Integer, Integer> ucAdd = uncurry(add); ucAdd.apply(2, 3); // 5 It would be nice if Java8 provided this out-of-box on Function Scala calls this uncurried
  • 17. Currying in Scala scala> def merge1(x: String, y: Int) = x + y.toString merge1: (x: String, y: Int)String scala> val merge1F = merge1 _ merge1F: (String, Int) => String scala> def merge2(x: String)(y: Int) = x + y.toString
 scala> val merge2F = merge2 _ merge2F: String => (Int => String) scala> val mergeTest = merge2F("Test#") mergeTest: Int => String scala> mergeTest(1) res1: Test#1 scala> mergeTest(2) res2: Test#2 • Scala uses special syntax for currying - It does not use tupled arguments, instead uses multiple function call syntax in the definition to denote a curried function.
  • 18. Curry Uncurry scala> def merge1(x: String, y: Int) = x + y.toString merge1: (x: String, y: Int)String scala> val merge1F = merge1 _ merge1F: (String, Int) => String scala> val merge1FCurried = merge1F.curried merge1FCurried: String => (Int => String) scala> def merge2(x: String)(y: Int) = x + y.toString
 scala> val merge2F = merge2 _ merge2F: String => (Int => String) scala> val merge2FUncurried = Function.uncurried(merge2F) merge2FUncurried: (String, Int) => String Scala
  • 19. PFA in Scala // Partially Applied Function or Partial Function Application (PFA)
 def greet(salutation: String, fname: String, lname: String) = s"$salutation. $fname $lname"
 println(greet("Mr", "Dhaval", "Dalal")) // Mr Dhaval Dalal def new_ms = greet("Ms", _: String, _: String) // (String, String) => String
 println(new_ms("Ada", "Lovelace")) // Ms Ada Lovelace
 
 def new_drew = greet(_: String, _: String, "Drew")
 (String, String) => String println(new_drew("Ms", "Nancy")) // Ms Nancy Drew • Supply a value to partially apply the function and to leave out the arguments unapplied, use underscore “_” • Note: PFA is different from Partial Function
  • 20. Re-shaping Third Party Library Functions • In third-party libraries we may never be able to modify the code. • Use Currying/PFA to simplify the callers interface. def power(n: Double) = Math.pow(_: Double, n)
 val square = power(2)
 println(square(2)) // 4.0
 
 val cube = power(3)
 println(cube(2)) // 8.0
  • 21. Currying in Haskell greet :: String -> String -> String -> String
 greet salutation fname lname = salutation ++ ". " ++ fname ++ " " ++ lname
 
 main :: IO ()
 main = do
 print $ greet "Mr" "Dhaval" "Dalal" -- Mr Dhaval Dalal
 let greet_mr = greet "Mr"
 print (greet_mr "Joe" "Shmo") -- Mr Joe Shmo
 let greet_mr_joe = greet "Mr" "Joe"
 print (greet_mr_joe "Sober") -- Mr Joe Sober
 print "Done!" • In Haskell, all the functions are curried by default, you don’t need special syntax for that. • It does not have Partially Applied Functions.
  • 22. Currying in Haskell Prelude> :type (*) (*) :: Num a => a -> a -> a Prelude> multiply2 = (*2) Prelude> :type multiply2 multiplyBy2 :: Num a => a -> a Prelude> multiply2 3 6 • Even operators are curried by default. Prelude> :type filter filter :: (a -> Bool) -> [a] -> [a] Prelude> even = x -> x `mod` 2 == 0 Prelude> filterEvens = filter even Prelude> :type filterEvens filterEvens :: Integral a => [a] -> [a] Prelude> filterEvens [0..10] [2,4,6,8,10] Prelude> filterOdds = filter (not . even) Prelude> filterOdds [0..10] [1,3,5,7,9] • Yet another example…
  • 23. PFA in Clojure (defn new-person [salutation f-name l-name]
 (println salutation f-name l-name))
 
 (new-person "Mr." "Dhaval" "Dalal") ; Mr Dhaval Dalal (def new-ms (partial new-person "Ms"))
 (new-ms "Ada" "Lovelace") ; Ms Ada Lovelace • Lets partially apply title to this function… • Lets now partially apply title and first-name (def new-ms-ada (partial new-person "Ms" "Ada"))
 (new-ms-ada "Lovelace") ; Ms Ada Lovelace
  • 24. PFA in Clojure • What if we want to fix the third arg - last name instead of the 1st? (def new-dalal (partial new-person salutation f-name "Dalal"))
 (new-dalal "Mr" “Dhaval") ; The above code won't compile • This is because we need placeholder for 1st and 2nd args, which we don’t want to apply., we can’t directly apply the 3rd argument. • In Clojure, with partial function application the order of arguments matters. Its from left to right. This is just like currying. • So, what do we do?
  • 25. Lambda to the rescue • We wrap this in a lambda! (def new-dalal (fn [sal fname]
 (new-person sal fname "Dalal"))) (new-dalal "Mr." "Dhaval") ; Mr. Dhaval Dalal • Doing this by hand every time is tedious! • Fortunately, Clojure has a macro to synthesise this kind of "ad-hoc" partial function application (def new-dalal #(new-person %1 %2 "Dalal")) ; Mr. Dhaval Dalal
 (new-dalal "Mr." "Dhaval") ; Mr. Dhaval Dalal (def new-ada #(new-person %1 "Ada" %2))
 (new-ada "Ms." "Lovelace") ; Ms Ada Lovelace
 (new-ada "Mrs." "???") ; Mrs. Ada ???
  • 26. Currying in Groovy def filterList = { filter, list -> list.findAll(filter) }
 def even = { it % 2 == 0 }
 def evens = filterList.curry(even)
 println evens(0..10) // [0, 2, 4, 6, 8, 10]
 
 def not = { !it }
 def odds = filterList.curry(even >> not) // even andThen not
 println odds(0..10) // [1, 3, 5, 7, 9] • In Groovy, we need to explicitly call the curry method on closure! • It curries from left to right def merge = { x, y, z ->
 println "arg0: x = $x"
 println "arg1: y = $y"
 println "arg2: z = $z"
 "$x$y$z"
 }
 println merge.curry(10)('Hello', new Date()) // 10Hello<Date>
 println merge.curry(10, 'Hello')(new Date()) // 10Hello<Date>
  • 27. Currying in Groovy • And if you need to curry from right-to-left, use rcurry() def merge = { x, y, z ->
 println "arg0: x = $x"
 println "arg1: y = $y"
 println "arg2: z = $z"
 "$x$y$z"
 }
 println merge.rcurry(10)('Hello', new Date()) // Hello<Date>10
 println merge.rcurry(10, 'Hello')(new Date()) // <Date>10Hello • And for currying at a index, use ncurry() println merge.ncurry(1, new Date())(10, 'Hello') //10<Date>Hello
 println merge.ncurry(0, new Date(), 'Hello')(10) //<Date>Hello10
  • 28. Reflections • You curry strictly from left-to-right. • We don’t have to provide all the arguments to the function at one go! This is partially applying the function. • In other words, Currying enables Partial Function Application, a.k.a - Partially Applied Function (PFA). • "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 • 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.
  • 29. References • Code Jugalbandi (http://codejugalbandi.org) • Exploring Functional Programming - Ryan Lemmer and Dhaval Dalal • https://github.com/CodeJugalbandi/FunctionalProgramming/ tree/master/melodies/currying • Healthy Code Magazine Code Jugalbandi Article • https://www.slideshare.net/DhavalDalal/3-code- jugalbandicurryingpfahealthycodemagazinemar2015