Some languages natively support design by contract features. F# includes an "assert" function. But this function is quite "imperative": it returns a unit type, which is not very nice in a functional code.
The following "ensure" function is easier to integrate in functional code. For example, it's easier to test return values (postconditions) with this function:
let ensure f x = assert (f x) x let positive x = x >= 0 let rec fibo = function | 0 | 1 -> 1 | n -> fibo (n - 1) + fibo (n - 2) |> ensure positive
In Eiffel and in some other languages, preconditions and postconditions are grouped in the code, in order to make them more visible. It is possible to get a similar result with F#.
Let's define precondition and postcondition functions.
let postcondition cond f x = let res = f x assert (cond res) res let precondition cond f x = assert (cond x) f x
You can then add conditions to existing functions:
let checked_abs = abs |> postcondition positive
Here is a way to add conditions when defining a function. You can put as many conditions as you want, you can even call the famous memoize function:
// note: ^< is right associative // <| may become right associative in a future release of F#. let (^<) = (<|) let rec fibo = precondition positive ^< postcondition positive ^< memoize ^< function | 0 | 1 -> 1 | n -> fibo (n - 1) + fibo (n - 2)
I think this is a good example to show how high-order functions may greatly factor code. There's one limitation with the example: functions have only one argument. But it's easy to find a work around, let's define a curry function:
let curry f x y = f (x, y) let rec foo = curry ^< precondition (fst >> positive) ^< precondition (snd >> positive) ^< postcondition positive ^< fun (x, y) -> // ... foo 4 2
By Laurent Le Brun, Wednesday 26 March 2008 :: [EN] F# articles :: #32



Comments
1. On Monday 3 November 2008 at 13:34, by Vesa Karvonen
Leave a comment
Comments are closed.