Addendum

Memoization

πŸ’‘ Idea: reduce the calculation time of a function

❓ How to: cache results β†’ next call with same arguments, return cached result

πŸ‘‰ In practice : function memoizeN from library FSharpPlus

⚠️ Caution : As with any optimization, use it when you need it and check (measure) that it works without any additional inconvenience.

☝ Not to be confused with lazy expression...

Lazy expression

Syntax sugar to create a .NET Lazy<'T> object from an expression

  • Expression not evaluated immediately but on 1st request (Thunk)

  • Interesting for improving performance without overcomplexifying the code

let printAndForward x = printfn $"{x}"; x

let a = lazy (printAndForward "a")

let b = printAndForward "b"
// > b

printfn $"{a.Value} and {b}"
// > a
// > a and b

printfn $"{a.Value} and c"
// > a and c

Lazy active pattern

Extracts the value from a Lazy object

Organizing functions

3 ways to organize functions = 3 places to declare them:

  • Module: function declared within a module πŸ“

  • Nested : function declared inside a value or inside another function

    • πŸ’‘ Encapsulate helpers used just locally

    • ☝ Parent function parameters accessible to function nested

  • Method : function defined as a method in a type...

Methods

  • Defined with the member keyword rather than let

  • Choice of the self-identifier: this, me, self, _...

  • Choice of the parameters style:

    • Tuplified: OOP style

    • Curried: FP style

Method Examples

Function vs Method

Feature
Function
Method

Naming convention

camelCase

PascalCase

Currying

βœ… yes

βœ… if not tuplified nor overridden

Named parameters

❌ no

βœ… if tuplified

Optional parameters

❌ no

βœ… if tuplified

Overload

❌ no

βœ… if tuplified

Parameter inference (declaration)

βž– Possible

βž– yes for this, possible for the other parameters

Argument inference (usage)

βœ… yes

❌ no, object type annotation needed

High-order function argument

βœ… yes

βž– yes with shorthand member, no with lambda otherwise

inline supported

βœ… yes

βœ… yes

Recursive

βœ… yes with rec

βœ… yes

Function vs Delegate

We can define a delegate in F# with the syntax: type Fn = delegate of args: Args -> Return

πŸ‘‰ A delegate adds a thin layer on top of a function signature, like an object with a single method Invoke:

  • Pros: we can use named arguments when invoking the delegate

  • Cons:

    • extra work to wrap the function (or the method) in the delegate and to execute the function by calling the Invoke(...) method

    • cumbersome syntax when there are several parameters, to differentiate between tuple and curried parameters:

      • Tuple: type MyFn = delegate of (int * int) -> int

      • Curried: type MyFn = delegate of int * int -> int

Interop with the BCL

void method

A .NET void method is seen in Fβ™― as returning unit.

Conversely, an Fβ™― function returning unit is compiled into a void method.

Equivalent C# based on SharpLab:

Calling a BCL method with N arguments

A .NET method with several arguments is "pseudo-tuplified":

  • All arguments must be specified (1)

  • Partial application of parameters is not supported (2)

  • Calls don't work with a real Fβ™― tuple ⚠️ (3)

out Parameter - In Cβ™―

out used to have multiple output values from a method β†’ Ex : Int32.TryParse, Dictionary<,>.TryGetValue :

out Parameter - In Fβ™―

Output can be consumed as a tuple πŸ‘

Instantiate a class with new?

Calling an overloaded method

  • Compiler may not understand which overload is being called

  • Tips: call with named argument

Last updated

Was this helpful?