This solution creates the exact syntax you need. Surprising to me, pretty fast. Also, this is apparently a good example of using monads, also known as Expression Calculations .
// Generic let inline mOp1<'a> op sample x = op sample x, sample let inline mOp2<'a> op1 op2 (b, sample) x = op1 b (op2 sample x), sample // Implementation for (=) and (&&) let (==) = mOp1 (=) let (&=) = mOp2 (&&) (=) // Use let ret1 = a == b &= c &= d &= e |> fst
How it works
This approach is a very simplified state monad. The monadic type is a tuple (bool, 'T) . The first component is the logical value of the current calculation, and the second is an approximate value for comparison.
(==) will initialize a monad similar to the Delay statement.
(&=) used for all subsequent comparisons. It is similar to the Bind statement.
We do not need Return , because fst will work very well.
mOp1 and mOp2 are abstractions of logical operations. They allow you to define your own operators. Here are examples of or-equal and and-greater-than :
let (|=) = mOp2 (||) (=) let (.>) = mOp1 (>) let (&>) = mOp2 (&&) (>) // Use let ret2 = a == b |= c |= d |= e |> fst // if any of b,c,d,e equals to a let ret3 = 5 .> 3 &> 4 |> fst // true: 5>3 && 5>4 let ret4 = 5 .> 3 &> 8 &> 4 |> fst // false
Performance
I really liked the beautiful solution from @ildjarn, but building the List pretty slow, so my main goal was performance.
Running a chain of 8 comparisons, 10 million times:
- 04972ms
a=b && a= && ... - 23138ms
List Based - 12367ms monadic
source share