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 )
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
y , so the function
x as argument and
y as result. Now look another example with a tuple as Domain:
f: ( x ∗ y ) → z
|( 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)
The ideia is share the sum behavior, so we will create two functions. First the
sum function, that function will receive two int type,
second, as arguments and return a int type value,
second. Last we will create
addOne function, that function will receive just one int argument called
second and add 1 to this argument. That way we will share the
sum behavior to
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
|>, 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
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
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
Seq.reduce. That way we can share the behavior of sum all itens of a list.
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.
- Currying wikipedia
- Partial application vs. Curriyng
- Funtional Programming: Currying vs. Partial application
- Curried functions
- Partial application
- What are the practical advantages of currying?
- Currying Haskell doc.
- A real world Currying example
- Partial application wikipedia
- mathematical symbols
- domain range codomain
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)