You cannot have something named "X" theoretically does not mean you cannot have anything anyone at sometime thought to be "X". See my answermy answer to another question for a feeling of what you can expect to get in the way of a monad pattern in an object oriented language.
What really concerns me is this:
// liftM :: m t -> (t -> u) -> m u -- looks more similar to bind this wayWhy is it called
lift? Because it takes a function in and gives a function out, but in another domain.(t -> u) -> m t -> m ushould be read as(t -> u) -> (m t -> m u), which translates to something likeFunc<Func<T, U>, Func<M<T>, M<U>>>in C#.You should not overwrite local variables, let alone repetitively, let alone in functional-style aspirant code:
game = State<Player>.Lift<GameState, GameState>(game, nextPlayerMove); game = State<Player>.Lift<GameState, GameState>(game, drawBoard); game = State<Player>.Bind<GameState, GameState>(game, findWinner);You don't do
Monadandwhileloop. You should use afoldM.Also noticed
nextPlayerMovemay do IO. In Haskell you would not have a function interleaved with a monad, unless it is a deterministic mathematical function. For example if it used Random numbers or IO you would need a monadic transformer, seeStateThere.
In adopting functional paradigms, you should start with the low hanging fruits. Avoiding mutable state and preferring expressions over statements, etc. And look for opportunities for reification. Aim for making implicit patterns explicit (for example using applicative alternatives from IEnumerable/IQueryable instead of loops) , composability and as much compile time guarantees as possible.