Some potential and difficulties in the use of lenses in MonadState - haskell

What follows is a series of examples/exercises upon Lenses (by Edward Kmett) in MonadState, based on the solution of Petr Pudlak to my previous question.
In addition to demonstrate some uses and the power of the lenses, these examples show how difficult it is to understand the type signature generated by GHCi. There is hope that in the future things will improve?
{-# LANGUAGE TemplateHaskell, RankNTypes #-}
import Control.Lens
import Control.Monad.State
---------- Example by Petr Pudlak ----------
-- | An example of a universal function that modifies any lens.
-- It reads a string and appends it to the existing value.
modif :: Lens' a String -> StateT a IO ()
modif l = do
s <- lift getLine
l %= (++ s)
-----------------------------------------------
The following comment type signatures are those produced by GHCi.
The other are adaptations from those of Peter.
Personally, I am struggling to understand than those produced by GHCi, and I wonder: why GHCi does not produce those simplified?
-------------------------------------------
-- modif2
-- :: (Profunctor p, MonadTrans t, MonadState s (t IO)) =>
-- (Int -> p a b) -> Setting p s s a b -> t IO ()
modif2 :: (Int -> Int -> Int) -> Lens' a Int -> StateT a IO ()
modif2 f l = do
s<- lift getLine
l %= f (read s :: Int)
---------------------------------------
-- modif3
-- :: (Profunctor p, MonadTrans t, MonadState s (t IO)) =>
-- (String -> p a b) -> Setting p s s a b -> t IO ()
modif3 :: (String -> Int -> Int) -> Lens' a Int -> StateT a IO ()
modif3 f l = do
s <- lift getLine
l %= f s
-- :t modif3 (\n -> (+) (read n :: Int)) == Lens' a Int -> StateT a IO ()
---------------------------------------
-- modif4
-- :: (Profunctor p, MonadTrans t, MonadState s (t IO)) =>
-- (t1 -> p a b) -> (String -> t1) -> Setting p s s a b -> t IO ()
modif4 :: (Bool -> Bool -> Bool) -> (String -> Bool) -> Lens' a Bool -> StateT a IO ()
modif4 f f2 l = do
s <- lift getLine
l %= f (f2 s)
-- :t modif4 (&&) (\s -> read s :: Bool) == Lens' a Bool -> StateT a IO ()
---------------------------------------
-- modif5
-- :: (Profunctor p, MonadTrans t, MonadState s (t IO)) =>
-- (t1 -> p a b) -> (String -> t1) -> Setting p s s a b -> t IO ()
modif5 :: (b -> b -> b) -> (String -> b) -> Lens' a b -> StateT a IO ()
modif5 f f2 l = do
s<- lift getLine
l %= f (f2 s)
-- :t modif5 (&&) (\s -> read s :: Bool) == Lens' a Bool -> StateT a IO ()
---------------------------------------
-- modif6
-- :: (Profunctor p, MonadState s m) =>
-- (t -> p a b) -> (t1 -> t) -> t1 -> Setting p s s a b -> m ()
modif6 :: (b -> b -> b) -> (c -> b) -> c -> Lens' a b -> StateT a IO ()
modif6 f f2 x l = do
l %= f (f2 x)
-- :t modif6 (&&) (\s -> read s :: Bool) "True" == MonadState s m => Setting (->) s s Bool Bool -> m ()
-- :t modif6 (&&) (\s -> read s :: Bool) "True"
---------------------------------------
-- modif7
-- :: (Profunctor p, MonadState s IO) =>
-- (t -> p a b) -> (String -> t) -> Setting p s s a b -> IO ()
modif7 :: (b -> b -> b) -> (String -> b) -> Lens' a b -> StateT a IO ()
modif7 f f2 l = do
s <- lift getLine
l %= f (f2 s)
-- :t modif7 (&&) (\s -> read s :: Bool) ==
-- :t modif7 (+) (\s -> read s :: Int) ==
---------------------------------------
p7a :: StateT Int IO ()
p7a = do
get
modif7 (+) (\s -> read s :: Int) id
test7a = execStateT p7a 10 -- if input 30 then result 40
---------------------------------------
p7b :: StateT Bool IO ()
p7b = do
get
modif7 (||) (\s -> read s :: Bool) id
test7b = execStateT p7b False -- if input "True" then result "True"
---------------------------------------
data Test = Test { _first :: Int
, _second :: Bool
}
deriving Show
$(makeLenses ''Test)
dataTest :: Test
dataTest = Test { _first = 1, _second = False }
monadTest :: StateT Test IO String
monadTest = do
get
lift . putStrLn $ "1) modify \"first\" (Int requested)"
lift . putStrLn $ "2) modify \"second\" (Bool requested)"
answ <- lift getLine
case answ of
"1" -> do lift . putStr $ "> Write an Int: "
modif7 (+) (\s -> read s :: Int) first
"2" -> do lift . putStr $ "> Write a Bool: "
modif7 (||) (\s -> read s :: Bool) second
_ -> error "Wrong choice!"
return answ
testMonadTest :: IO Test
testMonadTest = execStateT monadTest dataTest

As a family in the ML tradition, Haskell is specifically designed so that every toplevel binding has a most general type, and the Haskell implementation can and has to infer this most general type. This ensures that you can reuse the binding in as much places as possible. In a way, this means that type inference is never wrong, because whatever type you have in mind, type inference will figure out the same type or a more general type.
why GHCi does not produce those simplified?
It figures out the more general types instead. For example, you mention that GHC figures out the following type for some code:
modif2 :: (Profunctor p, MonadTrans t, MonadState s (t IO)) =>
(Int -> p a b) -> Setting p s s a b -> t IO ()
This is a very general type, because every time I use modif2, I can choose different profunctors p, monad transformers t and states s. So modif2 is very reusable. You prefer this type signature:
modif2 :: (Int -> Int -> Int) -> Lens' a Int -> StateT a IO ()
I agree that this is more readable, but also less generic: Here you decided that p has to be -> and t has to be StateT, and as a user of modif2, I couldn't change that.
There is hope that in the future things will improve?
I'm sure that Haskell will continue to mandate most general types as the result of type inference. I could imagine that in addition to the most general type, ghci or a third-party tool could show you example instantiations. In this case, it would be nice to declare somehow that -> is a typical profunctor. I'm not aware of any work in this direction, though, so there is not much hope, no.

Let's look at your first example:
modif :: Lens' a String -> StateT a IO ()
modif l = do
s <- lift getLine
l %= (++ s)
This type is simple, but it has also has a shortcoming: You can only use your function passing a Lens. You cannot use your function when you have an Iso are a Traversal, even though this would make perfect sense! Given the more general type that GHCi inferes, you could for example write the following:
modif _Just :: StateT (Maybe String) IO ()
which would append the read value only if that state was a Just, or
modif traverse :: StateT [String] IO ()
which would append the read value to all elements in the list. This is not possible with the simple type you gave, because _Just and traverse are not lenses, but only Traversals.

Related

Haskell: [IO ()] to IO ()

Haskell wiki has the following question:
https://en.wikibooks.org/wiki/Haskell/Higher-order_functions
for :: a -> (a -> Bool) -> (a -> a) -> (a -> IO ()) -> IO ()
for i p f job = -- ???
I was able to come up with the following implementation:
generate :: a -> (a->Bool) -> (a->a) -> [a]
generate s cnd incr = if (cnd s) then [] else [s] ++ generate (incr s) cnd incr
-- collapse :: [IO ()] -> IO ()
-- collapse (x:xs) = x ++ collapse xs
-- does not work ^^^^^^
for::a->(a->Bool)->(a->a)->(a->IO())->IO()
for s cnd incr ioFn = map (ioFn) (generate s cnd incr)
Ofcourse map (ioFn) (generate s cnd incr) results in [IO ()]. I am not sure how this can be transformed to IO ()
I need something like foldl but the one that works with [IO ()] instead of [a].
The function you are looking for is:
sequence_ :: (Foldable t, Monad m) => t (m a) -> m ()
But we can actually just replace map, such that we do not need an extra function. You can use mapM_ :: Monad m => (a -> m b) -> [a] -> m () here instead of map, so:
for :: a -> (a -> Bool) -> (a -> a) -> (a -> IO ()) -> IO()
for s cnd incr ioFn = mapM_ ioFn (generate s cnd incr)
This thus will apply the function ioFun on all elements of generate s cnd incr, and eventually return the unit ().

How to derive a state monad from first principles?

I am trying to come up with an implementation of State Monad derived from examples of function composition. Here I what I came up with:
First deriving the concept of Monad:
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)
We can have function that composes these functions as follows:
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
This could be simplified by factoring out the case statement and function application:
fMaybe' :: (Maybe' a) -> (a -> Maybe' b) -> Maybe' b
fMaybe' Nothing' _ = Nothing'
fMaybe' (Just' x) f = f x
-- Applying 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' implementation, sqrtInvLog'' can be written as:
sqrtInvLog''' :: (Floating a, Ord a) => a -> Maybe' a
sqrtInvLog''' x = (sqrt' x) \bind'` (inv') `bind'` (log')`
Trying to apply the concept to maintain state, I defined something as shown below:
data St a s = St (a,s) deriving Show
sqrtLogInvSt' :: (Floating a, Ord a) => St a a -> St (Maybe' a) a
sqrtLogInvSt' (St (x,s)) = case (sqrt' x) of
Nothing' -> St (Nothing', s)
(Just' y) -> case (log' y) of
Nothing' -> St (Nothing', s+y)
(Just' z) -> St (inv' z, s+y+z)
It is not possible to define a monad using the above definition as bind needs to be defined as taking in a single type "m a".
Second attempt based on Haskell's definition of State Monad:
newtype State s a = State { runState :: s -> (a, s) }
First attempt to define function that is built using composed functions and maintains state:
fex1 :: Int->State Int Int
fex1 x = State { runState = \s->(r,(s+r)) } where r = x `mod` 2`
fex2 :: Int->State Int Int
fex2 x = State { runState = \s-> (r,s+r)} where r = x * 5
A composed function:
fex3 x = (runState (fex2 y)) st where (st, y) = (runState (fex1 x)) 0
But the definition newtype State s a = State { runState :: s -> (a, s) } does not fit the pattern of m a -> (a -> m b) -> m b of bind
An attempt could be made as follows:
instance Monad' (State s) where
bind' st f = undefined
return' x = State { runState = \s -> (x,s) }
bind' is undefined above becuase I did not know how I would implement it.
I could derive why monads are useful and apply it the first example (Maybe') but cannot seem to apply it to State. It will be useful to understand how I could derive the State Moand using concepts defined above.
Note that I have asked a similar question earlier: Haskell - Unable to define a State monad like function using a Monad like definition but I have expanded here and added more details.
Your composed function fex3 has the wrong type:
fex3 :: Int -> (Int, Int)
Unlike with your sqrtInvLog' example for Maybe', State does not appear in the type of fex3.
We could define it as
fex3 :: Int -> State Int Int
fex3 x = State { runState = \s ->
let (y, st) = runState (fex1 x) s in
runState (fex2 y) st }
The main difference to your definition is that instead of hardcoding 0 as the initial state, we pass on our own state s.
What if (like in your Maybe example) we wanted to compose three functions? Here I'll just reuse fex2 instead of introducing another intermediate function:
fex4 :: Int -> State Int Int
fex4 x = State { runState = \s ->
let (y, st) = runState (fex1 x) s in
let (z, st') = runState (fex2 y) st in
runState (fex2 z) st' }
SPOILERS:
The generalized version bindState can be extracted as follows:
bindState m f = State { runState = \s ->
let (x, st) = runState m s in
runState (f x) st }
fex3' x = fex1 x `bindState` fex2
fex4' x = fex1 x `bindState` fex2 `bindState` fex2
We can also start with Monad' and types.
The m in the definition of Monad' is applied to one type argument (m a, m b). We can't set m = State because State requires two arguments. On the other hand, partial application is perfectly valid for types: State s a really means (State s) a, so we can set m = State s:
instance Monad' (State s) where
-- return' :: a -> m a (where m = State s)
-- return' :: a -> State s a
return' x = State { runState = \s -> (x,s) }
-- bind' :: m a -> (a -> m b) -> m b (where m = State s)
-- bind' :: State s a -> (a -> State s b) -> State s b
bind' st f =
-- Good so far: we have two arguments
-- st :: State s a
-- f :: a -> State s b
-- We also need a result
-- ... :: State s b
-- It must be a State, so we can start with:
State { runState = \s ->
-- Now we also have
-- s :: s
-- That means we can run st:
let (x, s') = runState st s in
-- runState :: State s a -> s -> (a, s)
-- st :: State s a
-- s :: s
-- x :: a
-- s' :: s
-- Now we have a value of type 'a' that we can pass to f:
-- f x :: State s b
-- We are already in a State { ... } context, so we need
-- to return a (value, state) tuple. We can get that from
-- 'State s b' by using runState again:
runState (f x) s'
}
Have a look to this. Summing and extending a bit.
If you have a function
ta -> tb
and want to add "state" to it, then you should pass that state along, and have
(ta, ts) -> (tb, ts)
You can transform this by currying it:
ta -> ts -> (tb, ts)
If you compare this with the original ta -> tb, we obtain (adding parentheses)
ta -> (ts -> (tb, ts))
Summing up, if a function returns tb from ta (i.e. ta -> tb), a "stateful"
version of it will return (ts -> (tb, ts)) from ta (i.e. ta -> (ts -> (tb, ts)))
Therefore, a "stateful computation" (just one function, or either a chain of functions dealing with state) must return/produce this:
(ts -> (tb, ts))
This is the typical case of a stack of ints.
[Int] is the State
pop :: [Int] -> (Int, [Int]) -- remove top
pop (v:s) -> (v, s)
push :: Int -> [Int] -> (int, [Int]) -- add to the top
push v s -> (v, v:s)
For push, the type of push 5 is the same than type of pop :: [Int] -> (Int, [Int]).
So we would like to combine/join this basic operations to get things as
duplicateTop =
v <- pop
push v
push v
Note that, as desired, duplicateTop :: [Int] -> (Int, [Int])
Now: how to combine two stateful computations to get a new one?
Let's do it (Caution: this definition is not the same that the
used for the bind of monad (>>=) but it is equivalent).
Combine:
f :: ta -> (ts -> (tb, ts))
with
g :: tb -> (ts -> (tc, ts))
to get
h :: ta -> (ts -> (tc, ts))
This is the construction of h (in pseudo-haskell)
h = \a -> ( \s -> (c, s') )
where we have to calculate (c, s') (the rest in the expressions are just parameters a and s). Here it is how:
-- 1. run f using a and s
l1 = f a -- use the parameter a to get the function (ts -> (tb, ts)) returned by f
(b, s1) = l1 s -- use the parameter s to get the pair that l1 returns ( :: (tb, ts) )
-- 2. run g using f output, b and s1
l2 = g b -- use b to get the function (ts -> (tb, ts)) returned by g
(c, s') = l2 s1 -- use s1 to get the pair that l2 returns ( :: (tc, ts) )

Modify state using a monadic function with lenses

My question is quite similar to How to modify using a monadic function with lenses? The author asked if something like this exists
overM :: (Monad m) => Lens s t a b -> (a -> m b) -> s -> m t
The answer was mapMOf
mapMOf :: Profunctor p =>
Over p (WrappedMonad m) s t a b -> p a (m b) -> s -> m t
I'm trying to implement a function that modifies state in MonadState using a monadic function:
modifyingM :: MonadState s m => ASetter s s a b -> (a -> m b) -> m ()
Example without modifingM:
{-# LANGUAGE TemplateHaskell #-}
module Main where
import Control.Lens (makeLenses, use, (.=))
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.State.Lazy (StateT(StateT), execStateT)
data GameObject = GameObject
{ _num :: Int
} deriving (Show)
data Game = Game
{ _objects :: [GameObject]
} deriving (Show)
makeLenses ''Game
makeLenses ''GameObject
defaultGame = Game {_objects = map GameObject [0 .. 3]}
action :: StateT Game IO ()
action = do
old <- use objects
new <- lift $ modifyObjects old
objects .= new
modifyObjects :: [GameObject] -> IO [GameObject]
modifyObjects objs = return objs -- do modifications
main :: IO ()
main = do
execStateT action defaultGame
return ()
This example works. Now I'd like to extract the code from action to a generic solution modifingM:
{-# LANGUAGE TemplateHaskell #-}
module Main where
import Control.Lens (makeLenses, use, (.=), ASetter)
import Control.Monad.State.Class (MonadState)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.State.Lazy (StateT(StateT), execStateT)
data GameObject = GameObject
{ _num :: Int
} deriving (Show)
data Game = Game
{ _objects :: [GameObject]
} deriving (Show)
makeLenses ''Game
makeLenses ''GameObject
defaultGame = Game {_objects = map GameObject [0 .. 3]}
modifyingM :: MonadState s m => ASetter s s a b -> (a -> m b) -> m ()
modifyingM l f = do
old <- use l
new <- lift $ f old
l .= new
action :: StateT Game IO ()
action = modifyingM objects modifyObjects
modifyObjects :: [GameObject] -> IO [GameObject]
modifyObjects objs = return objs -- do modifications
main :: IO ()
main = do
execStateT action defaultGame
return ()
This results in compile time errors:
Main.hs:26:14: error:
• Couldn't match type ‘Data.Functor.Identity.Identity s’
with ‘Data.Functor.Const.Const a s’
Expected type: Control.Lens.Getter.Getting a s a
Actual type: ASetter s s a b
• In the first argument of ‘use’, namely ‘l’
In a stmt of a 'do' block: old <- use l
In the expression:
do { old <- use l;
new <- lift $ f old;
l .= new }
• Relevant bindings include
f :: a -> m b (bound at app/Main.hs:25:14)
l :: ASetter s s a b (bound at app/Main.hs:25:12)
modifyingM :: ASetter s s a b -> (a -> m b) -> m ()
(bound at app/Main.hs:25:1)
Main.hs:31:10: error:
• Couldn't match type ‘IO’ with ‘StateT Game IO’
Expected type: StateT Game IO ()
Actual type: IO ()
• In the expression: modifyingM objects modifyObjects
In an equation for ‘action’:
action = modifyingM objects modifyObjects
What's the problem?
Edit 1: Assign new instead of old value.
Edit 2: Added example with solution of #Zeta that does not compile.
Edit 3: Remove example of second edit. It didn't compile due to wrong imports (see comment).
You're using use on a ASetter, but use takes a Getter:
use :: MonadState s m => Getting a s a -> m a
(.=) :: MonadState s m => ASetter s s a b -> b -> m ()
Unfortunately, ASetter and Getting are not the same:
type Getting r s a = (a -> Const r a ) -> s -> Const r s
type ASetter s t a b = (a -> Identity b) -> s -> Identity t
We need to switch between Const and Identity arbitrarily. We need a Lens:
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
Note that there is no f on the left-hand side. Next, we note that your lift is not necessary. After all, f already works in our target monad m; you had to use lift previously because modifyObjects was in IO and action was in StateT Game IO, but here we just have a single m:
modifyingM :: MonadState s m => Lens s s a a -> (a -> m b) -> m ()
modifyingM l f = do
old <- use l
new <- f old
l .= old
That works! But it's likely wrong, since you probably want to set the new value in l .= old. If that's the case, we have to make sure that old and new have the same type:
-- only a here, no b
-- v v v v
modifyingM :: MonadState s m => Lens s s a a -> (a -> m a) -> m ()
modifyingM l f = do
old <- use l
new <- f old
l .= new
Keep in mind that you need to lift modifyObjects though:
action :: StateT Game IO ()
action = modifyingM objects (lift . modifyObjects)
We could stop here, but just for some fun, let us have a look again at Lens:
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
For any a -> f b you give me, I'll give you a new s -> f t. So if we just plug something in your objects, we have
> :t \f -> objects f
\f -> objects f
:: Functor f => (GameObject -> f GameObject) -> Game -> f Game
Therefore, we just need some MonadState s m => (s -> m s) -> m () function, but that's easy to achieve:
import Control.Monad.State.Lazy (get, put) -- not the Trans variant!
modifyM :: MonadState s m => (s -> m s) -> m ()
modifyM f = get >>= f >>= put
Note that you need to use Control.Monad.State from mtl instead of Control.Monad.Trans.State. The latter only defines put :: Monad m => s -> StateT s m () and get :: Monad m => StateT s m s, but you want to use the MonadState variant from mtl.
If we put all things together, we see that modifyingM can be written as:
modifyingM :: MonadState s m => Lens s s a a -> (a -> m a) -> m ()
modifyingM l f = modifyM (l f)
Alternatively, we use the can use the lens functions, although that does not give us the insight that we can use l f:
modifyingM :: MonadState s m => Lens s s a a -> (a -> m a) -> m ()
modifyingM l f = use l >>= f >>= assign l

Missing Monadstate instance

I am attempting to build a slackbot using this library: https://hackage.haskell.org/package/slack-api, just to learn a little bit more haskell, and hopefully, finally understand monads -_-.
I then have the following types:
data BotState = BotState
{
_appState :: AppState
}
makeLenses ''BotState
type AppState = HM.Map String ChannelState
emptyState :: AppState
emptyState = HM.empty
data ChannelState = ChannelState
{ _counter :: Int}
type Bot = Slack.Slack BotState
and I run my bot with:
initApp = lookupEnv "SLACK_API_TOKEN" >>=
\apiToken -> case apiToken of
Nothing -> throwM ApiTokenMissingException
Just t -> void $ Slack.runBot (Slack.SlackConfig t) runApp $ BotState emptyState
where:
runApp :: Slack.Event -> Bot ()
runApp m#(Slack.Message cid uid body _ _ _) = sendMessage cid "GAH I CAN HAZ CHZBURGHER!"
This runs fine, now I wish to add the ability to update the system state (by incrementing the counter, or in other ways).
so I add a modifyState function to my Bot:
modifyState :: (AppState -> AppState) -> Bot ()
modifyState f = uses Slack.userState $ view appState >>=
\state -> modifying Slack.userState $ set appState $ f state
This breaks with:
No instance for (Control.Monad.State.Class.MonadState
(Slack.SlackState BotState) ((->) BotState))
arising from a use of ‘modifying’
In the expression: modifying Slack.userState
In the expression:
modifying Slack.userState $ set appState $ f state
In the second argument of ‘(>>=)’, namely
‘\ state -> modifying Slack.userState $ set appState $ f state’
Which makes sense given the signature for modifying:
modifying :: MonadState s m => ASetter s s a b -> (a -> b) -> m ()
However, upon looking at the documentation for Slack.userState:
userState :: forall s s. Lens (SlackState s) (SlackState s) s s Source
And then:
data SlackState s
... Constructor ...
Instances
Show s => Show (SlackState s)Source
MonadState (SlackState s) (Slack s)Source
So then why isn't the BotState already an instance of MonadState? How could I fix this?
$ operator has fixity 0, while >>= has fixity 1, so code like this would work:
main :: IO ()
main = do
putStrLn "hello world" >>= \_ -> putStrLn "hi"
But not this one:
main :: IO ()
main = do
putStrLn $ "hello world" >>= \_ -> putStrLn "hi"
It's being interpreted as:
main :: IO ()
main = do
putStrLn ("hello world" >>= \_ -> putStrLn "hi")
To see fixity info, use ghci's :info command:
:info $
($) ::
forall (r :: ghc-prim-0.5.0.0:GHC.Types.RuntimeRep) a (b :: TYPE
r).
(a -> b) -> a -> b
-- Defined in ‘GHC.Base’
infixr 0 $
:info >>=
class Applicative m => Monad (m :: * -> *) where
(>>=) :: m a -> (a -> m b) -> m b
...
-- Defined in ‘GHC.Base’
infixl 1 >>=
Also, if you're not sure, good old parentheses are always here for the rescue :)

Using fmap with a maybe when a function uses IO

I have a function that I want to use a Maybe val with. Usually I would do func <$> val. But now suppose that func uses the IO monad. func <$> val will return a Maybe (IO ()). So instead I had to define a new operator:
(<$$>) :: Monad m => (a -> m b) -> Maybe a -> m ()
(<$$>) func (Just val) = func val >> return ()
(<$$>) func Nothing = return ()
So now I can write func <$$> val, but is there a better way to do it?
mapM_ from Data.Foldable is probably the best match:
Prelude Data.Foldable> :set -XScopedTypeVariables
Prelude Data.Foldable> :t \f (a :: Maybe a) -> Data.Foldable.mapM_ f a
\f (a :: Maybe a) -> Data.Foldable.mapM_ f a
:: Monad m => (a -> m b) -> Maybe a -> m ()
If you'd like a more specialised type there's also maybe:
Prelude> :t \f -> maybe (return ()) (f $)
\f -> maybe (return ()) (f $)
:: Monad m => (a -> m ()) -> Maybe a -> m ()
Your <$$> is traverse_ from Data.Foldable.
Is a one-liner always better? Here's how purity of undefined can be useful:
(<$$>) g x = maybe (return undefined) g x >> return ()
Example:
Prelude> print <$$> (Just 1)
1
Prelude> print <$$> Nothing
Prelude>
If you have a lot of this in your code, it might be worth employing the MaybeT transformer:
(\func val -> liftIO . func =<< MaybeT (return val) )
:: (a -> IO b) -> Maybe b -> MaybeT IO b
That doesn't immediately bring you any further than plain IO (Maybe ()), but it composes nicely.

Resources