Operators
Definition
Function whose name is a set of symbols
Unary operator:
let (~symbols) = ...Binary operator:
let (symbols) = ...Symbols = combination of
% & * + - . / < = > ? @ ^ | ! $
2 ways of using operators:
As an operator:
1 + 2without the
()prefix position if unary
-1.infix position id binary
1 + 2
As a function:
(+) 1 2with the
()
Standard operators
Also defined in FSharp.Core.
Arithmetic operators:
+,-...Pipeline operators
Composition operators
Piping operators
Binary operators, placed between a simple value and a function
Apply the value to the function = Pass value as argument
Avoid parentheses otherwise required for precedence reason
There are several pipes:
Pipe right
|>: the usual pipePipe left
<|a.k.a. reversed pipePipe right 2
||>Etc.
Pipe right |>
|>Reverse the order between function and value: val |> fn β‘ fn val
Natural "subject-verb" order, like a method call of an object (
obj.M(x))Pipeline: chain function calls, without intermediate variables
Help the type inference - example:
Pipe left <|
<|fn <| expression β‘ fn (expression)
β Usage a little less common than
|>β Minor advantage: avoids parentheses
β Major disadvantage: reads from right to left β Reverses natural English reading direction and execution order
Quid of such expression: x |> fn <| y β
x |> fn <| y βExecuted from left to right: (x |> fn) <| y β‘ (fn x) <| y β‘ fn x y
Goal: use
fnas infixCons: difficult to read because of double reading direction β
π Tip: TO AVOID
Pipe right 2 ||>
||>(x, y) ||> fn β‘ fn x y
To pass 2 arguments at once, in the form of a tuple
Used infrequently, but useful with
foldto pass the initial value (seed) and the list before defining thefolderfunction and help the type inference for a lambdafolder.
βοΈ This operator corresponds to the notion of "uncurrying", i.e. being able to call a curried f function by passing it these 2 parameters in the form of a tuple:
Compose >>
>>Binary operators, placed between two functions β The result of the 1st function is used as an argument for the 2nd function
f >> g β‘ fun x -> g (f x) β‘ fun x -> x |> f |> g
The out/in types must match:
f: 'T -> 'Uandg: 'U -> 'Vβ'UβSignature of the final function:
'T -> 'V.
Reversed Compose <<
<<Rarely used, except to restore a natural reading order.
Example with not (which replaces the ! in Cβ―):
Pipe |> or Compose >> ?
|> or Compose >> ?Compose
let h = f >> g
Functions
Pipe
let result = value |> f
Values
Point-free style
A.k.a Tacit programming
Writing functions without mentioning the parameters (referred here as "points"), just by using function composition (1) or partial application (2).
Pros/Cons βοΈ
β
Pros
Concise style
At function/operation level, by abstracting the parameters
β Cons
Loses the name of the parameter now implicit in the signature β Unimportant if the function remains understandable:
When the parameters name is not significant (e.g.
x)When the combination of parameters type + function name is unambiguous
For private usage - Not recommended for a public API
Limit π
Works poorly with generic functions:
π Fβ― coding conventions > Partial application and point-free programming
Custom operators
2 possibilities:
Operator overload
Creation of a new operator
Operator overload
Usually concerns a specific type β Overload defined within the associated type (as in Cβ―)
Creation of a new operator
Definition rather in a module or associated type
Usual use-case: alias for existing function, used as infix
Symbols allowed in an operator
Unary "tilde" operator
β ~ followed by +, -, +., -., %, %%, &, &&
Unary "snake " operator
β Several ~, e.g. ~~~~
Unary "bang" operator
β ! followed by a combination of !, %, &, *, +, ., /, <, =, >, @, ^, |, ~, ?
β Except != which is binary
Binary operator
β Any combination of !, %, &, *, +, ., /, <, =, >, @, ^, |, ~, ?
β which does not match a unary operator
Usage symbols
All operators are used as is
β Except the unary "tilde" operator: used without the initial ~
Unary tilde
let (~&&) x = β¦
&&x
Unary snake
let (~~~) x = β¦
~~~x
Unary bang
let (!!!) x = β¦
!!!x
Binary
let (<Λ>) x y = β¦
x <Λ> y
β To define an operator beginning or ending with a *, you must put a space between ( and * as well as between * and ) to distinguish from a block of Fβ― comments (* *).
β let ( *+ ) x y = x * y + y β
Operator or function?
Infix operator vs function
π Pros:
Respects the natural reading order (left β right)
Avoids parentheses β
1 + 2 * 3vsmultiply (add 1 2) 3
β οΈ Cons:
A "folkloric" operator (e.g.
@!) will be less comprehensible than a function whose name uses the domain language.
Using an operator as a function
π‘ You can use the partial application of a binary operator:
Examples:
Instead of a lambda: β
(+) 1β‘fun x -> x + 1To define a new function : β
let isPositive = (<) 0β‘let isPositive x = 0 < xβ‘x >= 0
Last updated
Was this helpful?