Concepts
Currying
Definition
Consists in transforming :
a function taking N parameters
Func<T1, T2, ...Tn, TReturn>
in C♯into a chain of N functions taking 1 parameter
Func<T1, Func<Tn, ...Func<Tn, TReturn>>
Partial application
Calling a function with fewer arguments than its number of parameters.
Possible thanks to currying
Returns a function taking the remaining number of arguments as parameters.
Loss of parameter names (
content: string
becomes juststring
)Signature of a function value, hence the parentheses (
(string -> string)
)
Syntax of F♯ functions
Parameters separated by spaces:
Indicates that functions are curried
Hence the
->
in the signature between parameters
IntelliSense with Ionide
💡 In VsCode with Ionide, IntelliSense provides a more readable description of functions, putting each argument in a new line:
.NET compilation of a curried function
☝ A curried function is compiled differently depending on how it's called!
Basically, it is compiled as a method with tuple-parameters → Viewed as a regular method when consumed in C♯
When partially applied, the function is compiled as a pseudo
Delegate
class extendingFSharpFunc<int, int>
with anInvoke
method that encapsulates the 1st supplied arguments.
Unified function design
unit
type and currying make it possible to design functions simply as:
Takes a single parameter of any type
including
unit
for a “parameterless” functionincluding another (callback) function
Returns a single value of any type
including
unit
for a “return nothing” functionincluding another function
👉 Universal signature of a function in F♯: 'T -> 'U
.
Parameters order
Between C♯ and F♯, the parameter concerning the main object (the this
in case of a method) is not placed in the same place:
In a method extension C♯, the
this
object is the 1st parameter.E.g.
items.Select(x => x)
In F♯, the main object is rather the last parameter: (it's called the data-last style)
E.g.
List.map (fun x -> x) items
The data-last style favors :
Pipeline:
items |> List.map square |> List.sum
Partial application:
let sortDesc = List.sortBy (fun i -> -i)
Composition of partially applied functions up to param “data”.
(List.map square) >> List.sum
⚠️ There can be some friction .NET/BCL methods because the BCL is also data-first driven. The solution is to wrap the method in a new curried function having parameters sorted in an order more F♯ piping friendly.
💡 Tips
Prefer to put 1st the most static parameters = those likely to be predefined by partial applications.
E.g.: “dependencies” that would be injected into an object in C♯.
👉 Partial application is a way to implement the dependency injection in F♯.
Last updated
Was this helpful?