Is it possible to implement an MFunctor instance for RVarT?
So far I've come up with the following:
{-# LANGUAGE RankNTypes #-}
import Data.RVar -- from rvar
import Control.Monad.Trans.Class (lift) -- from transformers
hoistRVarT :: Monad m => (forall t. n t -> m t) -> RVarT n a -> RVarT m a
hoistRVarT f rv = sampleRVarTWith (lift . f) rv
However this can not be used as a definition of hoist for MFunctor, due to the Monad constraint on m incurred by lift. The problem is, that I couldn't find another way to lift the the resulting monad into RVarT without lift. But I think conceptually it should be possible, since RVarT should be similar to StateT and there is an MFunctor instance for StateT. The problem is that I couldn't find anything in the API of rvar or random-fu which exposed such functionality.
RVarT m a is a newtype for PromptT Prim m a, where PromptT is defined in Control.Monad.Prompt. PromptT Prim m a is a newtype for Prompt (Lift Prim m) a. This, in turn, is a newtype for
forall b. (a -> b) -> (forall x. Lift Prim m x -> (x -> b) -> b) -> b
You can unwrap the whole thing with unsafeCoerce:
fromRVarT :: RVarT m a -> (a -> b) -> (forall x. Lift Prim m x -> (x -> b) -> b) -> b
fromRVarT = unsafeCoerce
toRVarT :: (forall b. (a -> b) -> (forall x. Lift Prim m x -> (x -> b) -> b) -> b) -> RVarT m a
toRVarT = unsafeCoerce
Prim isn't exported, but since you shouldn't need to touch it in the first place, and you're assembling and disassembling the whole thing with unsafeCoerce, you can just define:
data Prim a
You can write an MFunctor instance for Lift:
instance MFunctor (Lift f) where
hoist _ (Effect p) = Effect p
hoist phi (Lift m) = Lift (phi m)
And then you can unwrap the RVarT, hoist all the Lifts passed to its prompting function, and wrap it again:
instance MFunctor RVarT where
hoist phi rv = toRVarT $ \done prm -> fromRVarT rv done (\l -> prm $ hoist phi l)
I found a trick that works for this and similar cases if you do not need to be able to actually use a value RVarT m without a monad instance for m. It works by deferring the application of the natural transformation until we actually need to get out a value. It would still be nice if there was a proper instance.
{-# LANGUAGE RankNTypes, ExistentialQuantification #-}
import Data.RVar
import Control.Monad.Trans.Class (lift)
import Control.Monad.Morph
import Control.Monad (ap)
hoistRVarT :: Monad m => (forall t. n t -> m t) -> RVarT n a -> RVarT m a
hoistRVarT f = sampleRVarTWith (lift . f)
data RVarTFun m a = forall n. RVarTFun
{ transformation :: forall t. n t -> m t
, rvart :: RVarT n a }
-- You can only get a value out if you have a monad for m.
getRVarTFun :: Monad m => RVarTFun m a -> RVarT m a
getRVarTFun (RVarTFun t ma) = hoistRVarT t ma
wrapRVarTFun :: RVarT m a -> RVarTFun m a
wrapRVarTFun = RVarTFun id
-- Actually the result is slightly stronger than MFunctor because we don't need
-- a Monad on n.
hoistRVarTFun :: (forall t. n t -> m t) -> RVarTFun n a -> RVarTFun m a
hoistRVarTFun f (RVarTFun t nx) = RVarTFun (f . t) nx
instance MFunctor RVarTFun where
hoist = hoistRVarTFun
A more general implementation of this can be found here.
Related
I'm learning Monad Transformers, and one of the exercises asks to implement the Monad instance for StateT.
I want to test that my implementation admits to the Monad laws using the validity package, which is like the checkers package.
Problem is, my Arbitrary instance doesn't compile. I saw this question, but it doesn't quite do what I want because the test basically duplicates the implementation and doesn't check the laws.
There's also this question, but it's unanswered, and I've already figured out how to test Monad Transformers not involving functions (like MaybeT).
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE InstanceSigs #-}
module Ch11.MonadT (StT (..)) where
import Control.Monad.Trans.State (StateT (..))
newtype StT s m a = StT (s -> m (a, s))
deriving
(Functor, Applicative)
via StateT s m
instance (Monad m) => Monad (StT s m) where
return :: a -> StT s m a
return = pure
(>>=) :: StT s m a -> (a -> StT s m b) -> StT s m b
StT x >>= f = StT $ \s -> do
(k, s') <- x s
let StT y = f k
y s'
(>>) :: StT s m a -> StT s m b -> StT s m b
(>>) = (*>)
My test:
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeApplications #-}
module Ch11.MonadTSpec (spec) where
import Ch11.MonadT (StT (..))
import Test.Hspec
import Test.QuickCheck
import Test.Validity.Monad
spec :: Spec
spec = do
monadSpecOnArbitrary #(StTArbit Int [] Int)
-- create wrapper to avoid orphan instance error
newtype StTArbit s m a = StTArbit (StT s m a)
deriving
(Functor, Applicative, Monad)
instance (Arbitrary s, Function s, Arbitrary1 m, Arbitrary a) => Arbitrary (StTArbit s m a) where
arbitrary = do
f <- arbitrary :: Fun s (m (a, s))
StTArbit . StT <$> f
Error:
• Couldn't match type: (a0, s0)
with: s -> m (a, s)
Expected: Gen (s -> m (a, s))
Actual: Gen (a0, s0)
• In the second argument of ‘(<$>)’, namely ‘f’
In a stmt of a 'do' block: StTArbit . StT <$> f
OP here, this is what I ended up doing.
-- https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/explicit_forall.html
{-# LANGUAGE ExplicitForAll #-}
-- https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/type_applications.html
{-# LANGUAGE TypeApplications #-}
module Ch11.MonadTSpec (spec) where
import Ch11.MonadT (StT (..), runStT)
import Data.Function as F
import Test.Hspec
import Test.Hspec.QuickCheck
import Test.QuickCheck
spec :: Spec
spec = do
describe "Monad (StT Int [])" $ do
describe "satisfies Monad laws" $ do
-- the types are in the same order as in `forall`
prop "right identity law" (prop_monadRightId #Int #Int #[])
prop "left identity law" (prop_monadLeftId #Int #Int #Int #[])
prop "associative law" (prop_monadAssoc #Int #Int #Int #Int #[])
{- HLINT ignore -}
{-
the types in `forall` are specified in the order of dependency.
since `m` needs `a` and `s`, those appear before `m` in the list.
-}
-- (x >>= return) == x
prop_monadRightId ::
forall a s m.
(Monad m, Eq (m (a, s)), Show (m (a, s))) =>
s ->
Fun s (m (a, s)) ->
Property
prop_monadRightId s f = ((===) `F.on` go) (m >>= return) m
where
m = StT $ applyFun f
go st = runStT st s
-- (return x >>= f) == (f x)
prop_monadLeftId ::
forall a b s m.
(Monad m, Eq (m (b, s)), Show (m (b, s))) =>
a ->
s ->
Fun (a, s) (m (b, s)) ->
Property
prop_monadLeftId a s f = ((===) `F.on` go) (return a >>= h) m
where
g = applyFun2 f
m = StT $ g a
h = StT . g
go st = runStT st s
-- ((x >>= f) >>= g) == (x >>= (\x' -> f x' >>= g))
prop_monadAssoc ::
forall a b c s m.
(Monad m, Eq (m (b, s)), Show (m (b, s)), Eq (m (c, s)), Show (m (c, s))) =>
s ->
Fun s (m (a, s)) ->
Fun (a, s) (m (b, s)) ->
Fun (b, s) (m (c, s)) ->
Property
prop_monadAssoc s h f g =
((===) `F.on` go)
((m >>= f') >>= g')
(m >>= (\x -> f' x >>= g'))
where
m = StT $ applyFun h
f' = StT . applyFun2 f
g' = StT . applyFun2 g
go st = runStT st s
I think you want pure, not (<$>). (But I haven't checked with my local compiler, so I'm not sure.) You probably also have to turn your Fun into an actual function.
arbitrary = do
f <- arbitrary
pure (StTArbit . StT . applyFun $ f)
I'd also point out that there's not much point to making a newtype here. I guess it avoids an orphan instance warning? But you've defined the type you're writing an instance for yourself, presumably even in the same package, so it seems pretty benign; if it's part of a separate cabal component that people can't depend on, like a test suite, even more so.
The GHC implementation of Data.Reflection from the reflection package uses a trick involving unsafeCoerce that takes advantage of the way GHC compiles typeclasses using dictionary passing. The implementation is short, so I can reproduce it in its entirety here:
class Reifies s a | s -> a where
reflect :: proxy s -> a
newtype Magic a r = Magic (forall (s :: *). Reifies s a => Proxy s -> r)
reify :: forall a r. a -> (forall (s :: *). Reifies s a => Proxy s -> r) -> r
reify a k = unsafeCoerce (Magic k :: Magic a r) (const a) Proxy
This makes it possible to reify a value at the type level, then reflect it back:
ghci> reify (42 :: Integer) (\p -> reflect p) :: Integer
42
I was interested in using this technique, but I thought it would be convenient for my purposes to use a type family with Reifies rather than a functional dependency, so I attempted to rewrite the implementation using the usual transformation:
class Reifies s where
type Reflects s
reflect :: Proxy s -> Reflects s
newtype Magic a r = Magic (forall (s :: *). (Reifies s, Reflects s ~ a) => Proxy s -> r)
reify :: forall a r. a -> (forall (s :: *). (Reifies s, Reflects s ~ a) => Proxy s -> r) -> r
reify a k = unsafeCoerce (Magic k :: Magic a r) (const a) Proxy
Sadly, however, this no longer works! This changes compilation significantly enough to break the unsafeCoerce trick:
ghci> reify (42 :: Integer) (\p -> reflect p) :: Integer
2199023255808
However, I’m not familiar enough with how GHC works to understand why. Is it possible to implement Data.Reflection using an associated type instead of a functional dependency? If so, what needs to change? If not, why not?
The unsafeCoerce trick takes advantage of the fact that
Reifies s a => Proxy s -> r
has exactly the same representation, at run-time, as
a -> Proxy s -> r
By enlarging the constraint to (Reifies s a, a ~ Reflects s), you violate this critical assumption. There are several ways to fix this. Here's one:
{-# language MultiParamTypeClasses, TypeFamilies, PolyKinds, KindSignatures,
RankNTypes, ScopedTypeVariables, TypeOperators #-}
module TFReifies where
import Data.Proxy
import Unsafe.Coerce
import Data.Type.Equality
class Reifies s a where
type Reflects s :: *
reflect' :: proxy s -> a
reflect :: (Reifies s a, a ~ Reflects s) => proxy s -> a
reflect = reflect'
newtype Magic a r = Magic (forall (s :: *). (Reifies s a) => Proxy s -> r)
reify' :: forall a r. a -> (forall (s :: *). (Reifies s a) => Proxy s -> r) -> r
reify' a k = unsafeCoerce (Magic k :: Magic a r) (const a) Proxy
reify :: forall a r. a -> (forall (s :: *). (Reifies s a, a ~ Reflects s) => Proxy s -> r) -> r
reify a f = reify' a (\(p :: Proxy s) -> case unsafeCoerce Refl :: a :~: Reflects s of Refl -> f p)
Here's a version closer to yours:
class Reifies s where
type Reflects s :: *
reflect :: proxy s -> Reflects s
newtype Magic a r = Magic (forall (s :: *). (Reifies s) => Proxy s -> r)
reify :: forall a r. a -> (forall (s :: *). (Reifies s, a ~ Reflects s) => Proxy s -> r) -> r
reify a f = reify' a (\(p :: Proxy s) -> case unsafeCoerce Refl :: a :~: Reflects s of Refl -> f p)
where
-- This function is totally bogus in other contexts, so we hide it.
reify' :: forall a r. a -> (forall (s :: *). (Reifies s) => Proxy s -> r) -> r
reify' a k = unsafeCoerce (Magic k :: Magic a r) (const a) Proxy
I'm learning about mtl and I wish learn the proper way to create new monads as modules (not as typical application usage).
As a simple example I have written a ZipperT monad (complete code here):
{-# LANGUAGE FlexibleInstances, FunctionalDependencies, MultiParamTypeClasses, GeneralizedNewtypeDeriving #-}
module ZipperT (
MonadZipper (..)
, ZipperT
, runZipperT
) where
import Control.Applicative
import Control.Monad.State
class Monad m => MonadZipper a m | m -> a where
pushL :: a -> m ()
pushR :: a -> m ()
...
data ZipperState s = ZipperState { left :: [s], right :: [s] }
newtype ZipperT s m a = ZipperT_ { runZipperT_ :: StateT (ZipperState s) m a }
deriving ( Functor, Applicative
, Monad, MonadIO, MonadTrans
, MonadState (ZipperState s))
instance (Monad m) => MonadZipper s (ZipperT s m) where
pushL x = modify $ \(ZipperState left right) -> ZipperState (x:left) right
pushR x = modify $ \(ZipperState left right) -> ZipperState left (x:right)
...
runZipperT :: (Monad m) => ZipperT s m a -> ([s], [s]) -> m (a, ([s], [s]))
runZipperT computation (left, right) = do
(x, ZipperState left' right') <- runStateT (runZipperT_ computation) (ZipperState left right)
return (x, (left', right'))
it's works and I can compose with other monads
import Control.Monad.Identity
import Control.Monad.State
import ZipperT
length' :: [a] -> Int
length' xs = runIdentity (execStateT (runZipperT contar ([], xs)) 0)
where contar = headR >>= \x -> case x of
Nothing -> return ()
Just _ -> do
right2left
(lift . modify) (+1)
-- ^^^^^^^
contar
But I wish to avoid the explicit lift.
What is the correct way to create modules like this?
Can I avoid the explicit lift? (I wish to hide the internal StateT structure of my ZipperT)
Thank you!
I think that if you can write an instance of MonadState for your transformer you can use modify without the lift:
instance Monad m => MonadState (ZipperT s m a) where
...
I must confess I am not sure about what part of the state modify should affect, though.
I've looked at the complete code. It seems that you already define
MonadState (ZipperState s) (ZipperT s m)
This already provides a modify which however modifies the wrong underlying state. What you actually wanted was to expose the state wrapped in m, provided that is a MonadState itself. This could theoretically be done with
instance MonadState s m => MonadState s (ZipperT s m) where
...
But now we have two MonadState instances for the same monad, causing a conflict.
I think I somehow solved this.
Here's what I did:
First, I removed the original deriving MonadState instance. I instead wrote
getZ :: Monad m => ZipperT s m (ZipperState s)
getZ = ZipperT_ get
putZ :: Monad m => ZipperState s -> ZipperT s m ()
putZ = ZipperT_ . put
modifyZ :: Monad m => (ZipperState s -> ZipperState s) -> ZipperT s m ()
modifyZ = ZipperT_ . modify
and replaced previous occurrences of get,put,modify in the ZipperT library with the above custom functions.
Then I added the new instance:
-- This requires UndecidableInstances
instance MonadState s m => MonadState s (ZipperT a m) where
get = lift get
put = lift . put
And now, the client code works without lifts:
length' :: [a] -> Int
length' xs = runIdentity (execStateT (runZipperT contar ([], xs)) 0)
where contar :: ZipperT a (StateT Int Identity) ()
contar = headR >>= \x -> case x of
Nothing -> return ()
Just _ -> do
right2left
modify (+ (1::Int))
-- ^^^^^^^
contar
I've defined my own monad transformer:
data Config = Config { ... }
data State = State { ... }
newtype FooT m a = FooT {
runFoo :: ReaderT Config (StateT State m) a
} deriving (Functor, Monad, MonadReader Config, MonadState State)
And I've defined a MonadTrans instance for it.
instance MonadTrans FooT where
lift = FooT . lift . lift
Now, I have various monads that I can't just have be derived for me by the compiler. I'll take MonadIO as the example. So I've defined my MonadIO instance as
instance MonadIO m => MonadIO (FooT m) where
liftIO = lift . liftIO
However, I find that I'm doing a lot of lifting, for each Monad. Why could the author of each Monad typeclass (i.e. MonadIO, MonadCatchIO, MonadFoo) not define a general instance in terms of MonadTrans, instead of making me implement an instance for each new MonadTrans I come up with? a la
instance (MonadIO m, MonadTrans t, Monad (t m)) => MonadIO (t m) where
liftIO = lift . liftIO
That requires UndecidableInstances to compile, and I'm not certain that it's correct (in fact, pretty sure it's incorrect), but serves to express my intent for now.
So, is this possible? If not, why not? Will it ever be?
Let's say that I've come up with an alternative to MonadIO, called
MyMonadIO. It's like MonadIO in every way, except for the name:
class Monad m => MyMonadIO m where
myLiftIO :: IO a -> m a
Assuming your FooT type:
newtype FooT m a = FooT
{ runFoo :: ReaderT Config (StateT AppState m) a
} deriving (Functor, Applicative, Monad, MonadReader Config, MonadState AppState)
It's possible to create an instance of MyMonadIO for ReaderT,
StateT, and finally FooT. I've added extra type annotations to make it
easier for the reader to figure out what's going on:
instance MyMonadIO m => MyMonadIO (ReaderT r m) where
myLiftIO :: IO a -> ReaderT r m a
myLiftIO = (lift :: m a -> ReaderT r m a) . (myLiftIO :: IO a -> m a)
instance MyMonadIO m => MyMonadIO (StateT s m) where
myLiftIO :: IO a -> StateT s m a
myLiftIO = (lift :: m a -> StateT s m a) . (myLiftIO :: IO a -> m a)
instance MyMonadIO m => MyMonadIO (FooT m) where
myLiftIO :: IO a -> FooT m a
myLiftIO = (lift :: m a -> FooT m a) . (myLiftIO :: IO a -> m a)
It's also possbile to use GeneralizedNewtypeDeriving to easily derive
MyMonadIO for FooT (assuming there are already instances for ReaderT and
StateT):
newtype FooT m a = FooT
{ runFoo :: ReaderT Config (StateT AppState m) a
} deriving (Functor, Applicative, Monad, MyMonadIO, MonadReader Config, MonadState AppState)
If you look at the body of the myLiftIO function for the ReaderT, StateT,
and FooT instances, they are exactly the same: lift . myLiftIO.
Here's a repeat of the question:
Why could the author of each Monad typeclass (i.e. MonadIO, MonadCatchIO,
MonadFoo) not define a general instance in terms of MonadTrans, instead of
making me implement an instance for each new MonadTrans I come up with?
For MyMonadIO, this general instance would be as follows:
instance (Monad (t n), MyMonadIO n, MonadTrans t) => MyMonadIO (t n) where
myLiftIO :: IO a -> t n a
myLiftIO = (lift :: n a -> t n a) . (myLiftIO :: IO a -> n a)
With this instance defined, you don't need a specific instance for ReaderT,
StateT, or even FooT.
This requires UndecidableInstances. However, the problem with this is not undecidability, but that this instance overlaps some potentially valid instances of MyMonadIO.
For instance, imagine the following datatype:
newtype FreeIO f a = FreeIO (IO (Either a (f (FreeIO f a))))
instance Functor f => Functor (FreeIO f) where
fmap :: (a -> b) -> FreeIO f a -> FreeIO f b
fmap f (FreeIO io) = FreeIO $ do
eitherA <- io
pure $
case eitherA of
Left a -> Left $ f a
Right fFreeIO -> Right $ fmap f <$> fFreeIO
instance Functor f => Applicative (FreeIO f) where
pure :: a -> FreeIO f a
pure a = FreeIO . pure $ Left a
(<*>) :: FreeIO f (a -> b) -> FreeIO f a -> FreeIO f b
(<*>) (FreeIO ioA2b) (FreeIO ioA) = FreeIO $ do
eitherFa2b <- ioA2b
eitherFa <- ioA
pure $
case (eitherFa2b, eitherFa) of
(Left a2b, Left a) -> Left $ a2b a
(Left a2b, Right fFreeIOa) -> Right $ fmap a2b <$> fFreeIOa
(Right fFreeIOa2b, o) -> Right $ (<*> FreeIO (pure o)) <$> fFreeIOa2b
instance Functor f => Monad (FreeIO f) where
(>>=) :: FreeIO f a -> (a -> FreeIO f b) -> FreeIO f b
(>>=) (FreeIO ioA) mA2b = FreeIO $ do
eitherFa <- ioA
case eitherFa of
Left a ->
let (FreeIO ioB) = mA2b a
in ioB
Right fFreeIOa -> pure . Right $ fmap (>>= mA2b) fFreeIOa
You don't necessarily need to understand this FreeIO datatype (especially the Functor, Applicative, and Monad instances). It's enough just to know that this is a valid data type.
(If you're interested, this is just a free monad wrapped around IO.)
It's possible to write a MyMonadIO instance for FreeIO:
instance Functor f => MyMonadIO (FreeIO f) where
myLiftIO :: IO a -> FreeIO f a
myLiftIO ioA = FreeIO (Left <$> ioA)
We can even imagine writing a function using FreeIO:
tryMyLiftIOWithFreeIO :: Functor f => FreeIO f ()
tryMyLiftIOWithFreeIO = myLiftIO $ print "hello"
If you try to compile tryMyLiftIOWithFreeIO with both this instance (MyMonadIO (FreeIO f)) and the bad instance from above, you get the following error:
test-monad-trans.hs:103:25: error:
• Overlapping instances for MyMonadIO (FreeIO f)
arising from a use of ‘myLiftIO’
Matching instances:
instance (Monad (t n), MyMonadIO n, MonadTrans t) => MyMonadIO (t n)
-- Defined at test-monad-trans.hs:52:10
instance Functor f => MyMonadIO (FreeIO f)
-- Defined at test-monad-trans.hs:98:10
• In the expression: myLiftIO $ print "hello"
In an equation for ‘tryMyLiftIOWithFreeIO’:
tryMyLiftIOWithFreeIO = myLiftIO $ print "hello"
Why does this happen?
Well, in instance (Monad (t n), MyMonadIO n, MonadTrans t) => MyMonadIO (t n), what is the kind of t and n?
Since n is supposed to be a Monad, it's kind is * -> *. And since t is a monad transformer, it's kind is (* -> *) -> * -> *. t n is also supposed to be a Monad, so it's kind is also * -> *:
n :: * -> *
t :: (* -> *) -> * -> *
t n :: * -> *
Now, in instance Functor f => MyMonadIO (FreeIO f), what are the kinds of FreeIO and f?
f is supposed to be a Functor, so it's kind is * -> *. FreeIO's kind is (* -> *) -> * -> *. FreeIO f is a Monad, so it's kind is * -> *:
f :: * -> *
FreeIO :: (* -> *) -> * -> *
FreeIO f :: * -> *
Since the kinds are the same, you an see that instance Functor f => MyMonadIO (FreeIO f) overlaps with instance (Monad (t n), MyMonadIO n, MonadTrans t) => MyMonadIO (t n). GHC isn't sure which one to pick!
You can get around this by marking your instance FreeIO instance as OVERLAPPING:
instance {-# OVERLAPPING #-} Functor f => MyMonadIO (FreeIO f) where
myLiftIO :: IO a -> FreeIO f a
myLiftIO m = FreeIO (Left <$> m)
However, this is a treacherous route to go down. You can find out more about why overlapping can be bad from the GHC user guide.
This FreeIO example was created by Edward Kmett. You can find another clever example of an overlapping instance in this reddit post.
If you are planning on writing a monad typeclass (like MyMonadIO) and
releasing it to Hackage, one option is to use the
DefaultSignatures
functionality. This makes it easier for users of your library to define
instances.
Using DefaultSignatures, defining the MyMonadIO class would look like this:
class Monad m => MyMonadIO m where
myLiftIO :: IO a -> m a
default myLiftIO
:: forall t n a.
( MyMonadIO n
, MonadTrans t
, m ~ t n
)
=> IO a -> t n a
myLiftIO = (lift :: n a -> t n a) . (myLiftIO :: IO a -> n a)
This says that there is a default implementation of myLiftIO for any t n,
where n is an instance of MyMonadIO, and t is an instance of
MonadTrans.
With this default siguature for myLiftIO, defining instances of MyMonadIO for ReaderT and StateT would look like this:
instance MyMonadIO m => MyMonadIO (ReaderT r m)
instance MyMonadIO m => MyMonadIO (StateT s m)
Very simple. You don't need to provide the function body of myLiftIO since
it will use the default.
The only drawback of this is that it is not widely done. The
DefaultSignatures machinery seems to be mainly used for generic
programming, not monad typeclasses.
After reading (and skimming some sections of) Wadler's paper on monads, I decided to work through the paper more closely, defining functor and applicative instances for each of the monads he describes. Using the type synonym
type M a = State -> (a, State)
type State = Int
Wadler uses to define the state monad, I have the following (using related names so I can define them with a newtype declaration later on).
fmap' :: (a -> b) -> M a -> M b
fmap' f m = \st -> let (a, s) = m st in (f a, s)
pure' :: a -> M a
pure' a = \st -> (a, st)
(<#>) :: M (a -> b) -> M a -> M b
sf <#> sv = \st -> let (f, st1) = sf st
(a, st2) = sv st1
in (f a, st2)
return' :: a -> M a
return' a = pure' a
bind :: M a -> (a -> M b) -> M b
m `bind` f = \st -> let (a, st1) = m st
(b, st2) = f a st1
in (b, st2)
When I switch to using a type constructor in a newtype declaration, e.g.,
newtype S a = S (State -> (a, State))
everything falls apart. Everything is just a slight modification, for instance,
instance Functor S where
fmap f (S m) = S (\st -> let (a, s) = m st in (f a, s))
instance Applicative S where
pure a = S (\st -> (a, st))
however nothing runs in GHC due to the fact that the lambda expression is hidden inside that type constructor. Now the only solution I see is to define a function:
isntThisAnnoying s (S m) = m s
in order to bind s to 'st' and actually return a value, e.g.,
fmap f m = S (\st -> let (a, s) = isntThisAnnoying st m in (f a, s))
Is there another way to do this that doesn't use these auxiliary functions?
If you look here, you will see that they define it this way:
newtype State s a = State { runState :: (s -> (a,s)) }
so as to give the inner lambda a name.
The usual way is to define newtype newtype S a = S {runState : State -> (a, State)}. Then instead of your isntThisAnnoying s (S m) you can write runState t s where t is the same as S m.
You have to use a newtype because type synonyms cannot be typeclass instances.