You can emulate short-circuiting nicely with lazy values and active patterns:
//not sure why function Lazy.force is recognized in VS but not in FSI
//need to use member Force()
let (|Force|) (l:Lazy<_>) =
let encodeValue x y = function ...
match (encodeValue left value), lazy(encodeValue right value) with
| (true, encoded), _ -> (true, encoded + "1")
| _ , Force(true, encoded) -> (true, encoded + "0")
| (false, _) , Force(false, _) -> (false, "")
| _ -> failwith "Error"
Lazy values are calculated 0 or 1 times: if you never call
Force() on them they will never be calculated. The first time you call
Force() they are calculated and the result saved for every other time you call
(|Force|) here is a complete active pattern, a really neat feature which allows you to implement custom pattern match structures of sorts.
Notice as @Brian pointed out that you need to use
_ in the lazy value position where short-circuiting is possible. If
(true, encoded) matches then the lazy, expensive calculation is never forced. Then for each other case multiple matches using the
(|Force|) active pattern will only use the result from the first incident.
@Daniel pointed out that F# already has an active pattern that does exactly what
(|Force|) does: http://msdn.microsoft.com/en-us/library/ee340223.aspx