Introduction
If you need share a specific behaviour with functional programming, Currying is the answer. Created by Haskell Curry currying basically is a technique to transform a multiple arguments or n-tuple argument function in a chain of single arguments functions.
f:( x ∗ y ) → z to ( f ):x → ( y → z )
Function signature
Let understanding what is →
, ( x ∗ y )
, Domain and Range. The tuple or ( x ∗ y )
is a product of two types or a composing between two types, arrow function or →
is used to indicate a map of a set into another set, in other words indicate the argument and return, Domain is the argument of a function and Range is a result of a function.
Look below the example:
f: x → y
The function above has x
as Domain and y
as Range and that is read as from x
to y
, so the function f
has x
as argument and y
as result. Now look another example with a tuple as Domain:
f: ( x ∗ y ) → z
Symbol/Name | Means |
---|---|
→ | returns |
Domain | argument type |
Range | result type |
( x ∗ y ) | Tuple |
Look the same examples with F#:
multiply: int → int
let multiply a b = a * b
multiply 5 3
multiply: ( int ∗ int ) → int
let multiply (a,b) = a * b
multiply (5,3)
Explaining Currying
The ideia is share the sum behavior, so we will create two functions. First the sum
function, that function will receive two int type, first
and second
, as arguments and return a int type value, first
+ second
. Last we will create addOne
function, that function will receive just one int argument calledsecond
and add 1 to this argument. That way we will share the sum
behavior to addOne
function.
Regular sum function
sum: ( int ∗ int ) → int
let sum (first , second) = first + second
let addOne second = sum (1, second)
addOne 2
|> printf "regular function result: %d"
That is a regular function with a tuple as argument and it only can applied with both values.
Curried sum function
sum: int → int → int or sum: int → (int → int)
let sum first = //main function
let subFunction second = first + second
subFunction
let addOne = sum 1 // int -> int
addOne 2
|> printf "curried sum result: %d"
What we did
We created two functions, the main function, int → (int → int)
, has one int type argument called first
and return sub-function, that function, int → int
, has one int type argument called second
and in your body has the arguments sum.
How this works
The main function receive a value as parameter and "hold it" in your inner scope, this main function return a single parameter sub-function and that sub-function sum main function parameter with your own parameter. That is only possible because the sub-function is inside main function inner scope, that way it can access all main function variables, that is called closure.
Basically when you create a function all your environment is stored too, it works look like a lexical/static scope if scope is a part of code lexical/static scope is a free or bounded variable scope access range. See an example below:
let lexicalExample =
let a = 2 // <- lexical scope start
let multiply b = a * b
let a = 3 // <- lexical scope end
multiply 5
lexicalExample
The example above when variable a
is created a lexical/static scope is created too and the function multiply
is created inside that lexical/static scope, that way the multiply
function can use the a
value. When a
variable is recreated another lexical/static scope is create but this not change the a
value used by multiply
function because this function was created inside last lexical/static scope.
Now when we talk about lexical closure the concept is the same, but with one difference the scope is created when the function is created, so the all function arguments is accessible for anything inside function scope.
Currying on FSharp
Use currying with FSharp is easy because all multi arguments functions is curried by default, so not is necessary create it manually. Look it below:
let sum first second = first + second
let addOne = sum 1 // int -> int
addOne 2
|> printf "implicit curried sum result: %d"
The result is the same than first function and we can simplify this further. Look it:
let addOne = (+) 1 // int -> int
addOne 2
|> printf "simplify curried sum result: %d"
The sum operator is a infix notation and a multi argument too so is by default curried.
(+): int → int → int
The use of currying
With currying we are able to partial apply a function, in others words we fix the first of N arguments of a function and reuse the resulted function. That technique possibility us to share a behavior without create a new function and with lightweight syntax. A good examples of curried function is Seq.reduce
and |>
, look it below:
[1;2;3;4]
|> Seq.reduce (+)
|> printf "sum of all list itens: %d"
Explaining the expression
First we need understanding what is the operator |>
or forward pipe operator. Basically the forward pipe operator is a infix notation where the operator apply left value to right function.
f: a → (a → b) → b
let (|>) a b = b a
The Seq.reduce
function have two arguments, first (int → int → int)
and last a seq\<int\>
. If you are a good observer can see the signature int → int → int
is the same signature than (+)
operator, so we partial apply (+)
operator to Seq.reduce
and after apply [1;2;3;4]
to Seq.reduce (+)
.
The same expression can be write with a different way look it below:
let sumAll = Seq.reduce (+) // seq<int> -> int
sumAll [1;2;3;4]
|> printf "sum of all of integer list : %d"
This is the same of last expression but creating a new function sumAll: seq<int> → int
partially applying (+)
to Seq.reduce
. That way we can share the behavior of sum all itens of a list.
Conclusion
The currying is a great technique to share behavior, basically transform a n-tuple argument function to a chain of functions with one argument using lexical closure. Use currying in Fsharp is easy because all multi arguments is curried by default.
References
- Currying wikipedia
- Partial application vs. Curriyng
- Funtional Programming: Currying vs. Partial application
- Curried functions
- Partial application
- Currying
- What are the practical advantages of currying?
- Currying Haskell doc.
- A real world Currying example
- Partial application wikipedia
- mathematical symbols
- domain range codomain
Ending
If you wanna read this post with a cool way visit my repository on github tower-of-windsock and if you see any error, typo or have any question just write here I'll happy to answer you.
Top comments (0)