I suggest renaming mapM to liftM to match Haskell naming conventions: http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base4.2.0.1/ControlMonad.html. I’d also like to introduce liftM2:
// Monad m /* m1 m2 */ => (a1 > a2 > r) > m a1 > m a2 > m r
let inline liftM2 m1 m2 f m_a1 m_a2 =
let bind1 m_a1 f = (^m1: (member Bind: ^m_a1 > (^a1 > ^m_r) > ^m_r) m1, m_a1, f)
let unit2 x = (^m2: (member Return: ^b > ^m_r) m2, x)
let bind2 m_a2 f = (^m2: (member Bind: ^m_a2 > (^a2 > ^m_r) > ^m_r) m2, m_a2, f)
bind1 m_a1 (fun a1 > bind2 m_a2 (fun a2 > unit2 (f a1 a2)))
and generalized C# support:
// Monad m => (a > b) > m a > m b
let inline select m f m_a = liftM m (applyFunc f) m_a
// Monad m /* m1 m2 */ => (a1 > m a2) > (a1 > a2 > r) > m r
let inline selectMany m1 m2 selector projector m_a1 =
let bind1 m_a1 f = (^m1: (member Bind: ^m_a1 > (^a1 > ^m_r) > ^m_r) m1, m_a1, f)
bind1 m_a1 (fun a > let m_a2 = applyFunc selector a in
liftM2 m1 m2 (applyFunc2 projector) m_a1 m_a2)
extensions methods could be specialized like following:
[<Extension>]
let inline Select (m, f) = Combinators.select option f m
[<Extension>]
let inline SelectMany (m, s, p) = Combinators.selectMany option option s p m
(this one for the Option monad, not posted yet).
Ideas, conclusions, should I proceed with changes?
