I am trying to understand the concept of Monad by attempting to write generic version of functions that might be then include side effects to log, change state.
Here is what I came up with: (The code is bit long, but it is there to show how I approached understanding monad - and this approach may not be correct)
data Maybe' a = Nothing' | Just' a deriving Show
sqrt' :: (Floating a, Ord a) => a -> Maybe' a
sqrt' x = if x < 0 then Nothing' else Just' (sqrt x)
inv' :: (Floating a, Ord a) => a -> Maybe' a
inv' x = if x == 0 then Nothing' else Just' (1/x)
log' :: (Floating a, Ord a) => a -> Maybe' a
log' x = if x == 0 then Nothing' else Just' (log x)
sqrtInvLog' :: (Floating a, Ord a) => a -> Maybe' a
sqrtInvLog' x = case (sqrt' x) of
Nothing' -> Nothing'
(Just' y) -> case (inv' y) of
Nothing' -> Nothing'
(Just' z) -> log' z
-- Now attempt to simplify the nested case:
fMaybe' :: (Maybe' a) -> (a -> Maybe' b) -> Maybe' b
fMaybe' Nothing' _ = Nothing'
fMaybe' (Just' x) f = f x
-- using fMaybe':
sqrtInvLog'' :: (Floating a, Ord a) => a -> Maybe' a
sqrtInvLog'' x = (sqrt' x) `fMaybe'` (inv') `fMaybe'` (log')
-- now we can generalize the concept to any type, instead of just Maybe' by defining a Monad =>
class Monad' m where
bind' :: m a -> (a -> m b) -> m b
return' :: a -> m a
instance Monad' Maybe' where
bind' Nothing' _ = Nothing'
bind' (Just' x) f = f x
return' x = Just' x
-- using Monad sqrtInvLog'' can be written as:
sqrtInvLog''' :: (Floating a, Ord a) => a -> Maybe' a
sqrtInvLog''' x = (sqrt' x) `bind'` (inv') `bind'` (log')
-- Further lets attempt to use this for state maintenence and logging, logging:
-- first attempt the specific version:
data ST a = ST (a, Maybe' a) deriving Show
sqrtSt :: (Floating a, Ord a)=> a -> a -> ST a
sqrtSt st x = let r = sqrt' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
invSt :: (Floating a, Ord a)=> a -> a -> ST a
invSt st x = let r = inv' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
logSt :: (Floating a, Ord a)=> a -> a -> ST a
logSt st x = let r = log' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
-- let us first define function which is similar to bind and manipulates the state and invokes the given function:
stBind :: (Floating a, Ord a) => ST a -> (a->a->ST a) -> ST a
stBind (ST (a, Nothing')) _ = ST (a, Nothing')
stBind (ST (s, (Just' y))) f = f s y
sqrtInvLogSt :: (Floating a, Ord a) => a -> a -> ST a
sqrtInvLogSt st x = (sqrtSt st x) `stBind` (invSt) `stBind` (logSt)
-- stBind does not fit the pattern of bind
-- Another version:
sqrtSt' :: (Floating a, Ord a)=> ST a -> ST a
sqrtSt' (ST (st, Nothing')) = ST (st, Nothing')
sqrtSt' (ST (st, (Just' x))) = let r = sqrt' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
invSt' :: (Floating a, Ord a)=> ST a -> ST a
invSt' (ST (st, Nothing')) = ST (st, Nothing')
invSt' (ST (st, (Just' x))) = let r = inv' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
logSt' :: (Floating a, Ord a)=> ST a -> ST a
logSt' (ST (st, Nothing')) = ST (st, Nothing')
logSt' (ST (st, (Just' x))) = let r = log' x in case r of
Nothing' -> ST (st, Nothing')
(Just' y) -> ST (st+y, (Just' y))
-- define stBind' here
stBind' :: (Floating a, Ord a) => ST a -> (ST a->ST a) -> ST a
stBind' (ST (a, Nothing')) _ = ST (a, Nothing')
stBind' stx f = f stx
sqrtInvLogSt' :: (Floating a, Ord a) => ST a->ST a
sqrtInvLogSt' stx = (sqrtSt' stx) `stBind'` (invSt') `stBind'` (logSt')
-- Even this does not fit the pattern of bind,
The function stBind' defined in the end does not fit the pattern of bind'. How can I come up with an implementation in this situation to match the bind operator signature?
At the risk of spoilers, it might be interesting to peak at the definition of the State
monad as it existed before everything became transformer-ified:
newtype State s a = State { runState :: s -> (a, s) }
That is: a stateful action with state s
that produces a value of type a
is a function from the old state s
to a value and a new state, (a, s)
.
Starting from the correct definition for State
should make the remainder of your development easier to puzzle through.