Haskell’s function type (->)
, when partially applied: (->) r
…is monadic:
# ghci
GHCi, version 9.0.2: https://www.haskell.org/ghc/ :? for help
ghci> :i ->
type (->) :: * -> * -> *
type (->) = FUN 'Many :: * -> * -> *
-- Defined in ‘GHC.Types’
infixr -1 ->
instance Applicative ((->) r) -- Defined in ‘GHC.Base’
instance Functor ((->) r) -- Defined in ‘GHC.Base’
instance Monad ((->) r) -- Defined in ‘GHC.Base’
instance Monoid b => Monoid (a -> b) -- Defined in ‘GHC.Base’
instance Semigroup b => Semigroup (a -> b) -- Defined in ‘GHC.Base’
ghci> :q
Leaving GHCi.
#
If your code only uses that extra argument for reading, that is usually enough. But if writing is also required, you’ll need a specific variant of ((->) r)
which is sequential. Assuming WriteOut
is intended for writing:
{-# LANGUAGE BangPatterns, FlexibleInstances #-}
instance {-# OVERLAPPING #-} Monad ((->) WriteOut) where
m >>= k = \ wr -> let !x = m wr in k x wr
instance {-# OVERLAPPING #-} Applicative ((->) WriteOut) where
pure x = \ wr -> x
f' <*> x' = \ wr -> let !f = f' wr in
let !x = x' wr in
f x
instance {-# OVERLAPPING #-} Functor ((->) WriteOut) where
fmap f m = \ wr -> let !x = m wr in f x
…and if needed, a type synonym can help to avoid repetitive keystrokes:
type WrOut a = WriteOut -> a
Those long argument lists can then be used more monadically…