Here is an half-baked idea how to make monads more functional.<br>It's too wild to be implemented in haskell.<br>But maybe you are interested more in ideas than implementations, <br>so let's start with monad class<br>
<br>class Monad m where<br> return :: a -> m a<br> (>>=) :: m a -> (a -> m b) -> m b<br><br><br>I think monad's methods are misleading, let's rename them<br><br>class Monad m where<br> idM :: a -> m a<br>
(*$) :: (a -> m b) -> m a -> m b<br><br><br>We can see that `return` is a monadic identity and the `bind`<br>is an application in disguise. So now we have two applications.<br>It's standard `($)` and monadic `(*$)`. But they are application.<br>
Well isn't it something like `plusInt` and `plusDouble`?<br>Maybe we can devise single class for application. Let's<br>imagine a special class `App`<br><br>class App ?? where<br> ($) :: ???<br><br>As you can see it's defined so that we can fit<br>
monads and plain functions in this framework. Moreover<br>if we redefine this class than whitespace is redefined<br>automatically! So `($)` really means *white space* in haskell.<br><br>`idM` is interesting too. In standard world we can safely<br>
put `id` in any expression. So when we write <br><br> f = a + b<br><br>we can write<br><br> f = id (a + b)<br><br>or even<br><br> f = id ((id a) + (id b))<br><br>meaning doesn't change. So if we have special class `Id`<br>
<br>class Id f where<br> id :: ???<br><br>Again you can see that monads fit nicely in the type.<br>Why do we need this class? Whenever compiler gets an type mismatch,<br>it tries to apply method from `Id` class, if it's defined ofcourse.<br>
<br>But we have a class called `Category`, `id` belongs to it:<br><br>class Category (~>) where<br> id :: a ~> a<br> (>>) :: (a ~> b) -> (b ~> c) -> (a ~> c)<br><br><br>Let's pretend that `(>>)` is reversed composition `(.)`.<br>
It's interesting to note that there is another formulation<br>of 'Monad' class. It's called Kelisli category.<br><br>class Kelisli m where<br> idK :: a -> m a<br> (>>) :: (a -> m b) -> (b -> m c) -> (a -> m c)<br>
<br>Here again let's forget about monad's `(>>)` for a moment, <br>here it's composiotion. `Kleisli` is equivalent to `Monad`.<br><br>If we can define `Category` instance for `Kleisli`, so that<br>somehow this classes become unified on type level we<br>
can define application in terms of composition like this:<br><br>f $ a = (const a >> f) ()<br><br>And we can get application for monads (or kleislis :) ).<br><br>Implications:<br><br>Maybe someday you wrote a function like this:<br>
<br>foo :: Boo -> Maybe Foo<br>foo x = case x of<br> 1 -> Just ...<br> 2 -> Just ...<br> 3 -> Just ...<br> 4 -> Just ...<br> 5 -> Just ...<br> 6 -> Just ...<br> 7 -> Just ...<br>
_ -> Nothing<br><br>with `idM` rule you can skip all Just's<br><br>You can use white space as monadic bind. So functional application<br>can become monadic on demand. Just switch the types.<br><br><br>Implementation:<br>
<br>I've tried to unify `Category` and `Kleisli` with no luck.<br>Here is a closest sletches:<br><br>simplest sketch requires type functions :(<br><br><br>instance Monad m => Category (\a b -> a -> m b) where<br>
...<br><br><br>the other one too :(<br><br>class Category (~>) where<br> type Dom (~>) :: * -> *<br> type Cod (~>) :: * -> *<br><br> id :: Dom (~>) a -> Cod (~>) a<br> (>>) :: (Dom (~>) a ~> Cod (~>) b) -> (Dom (~>) b ~> Cod (~>) c) -> ...<br>
<br><br>instances<br><br>type Id a = a -- :(<br><br>instance Monad m => Category (a -> m b) where<br> type Dom (a -> m b) = Id<br> type Cod (a -> m b) = m<br><br> ...<br><br><br>