Operational monad with interpreter in arbitrary monad - haskell

I'm using the operational monad by Heinrich Apfelmus.
I'd like to parameterize the interpreter with the monad for the result type.
The following version of my code compiles:
{-# LANGUAGE GADTs #-}
import Control.Monad.Operational
data EloI a where
Display :: Int -> EloI ()
type Elo a = Program EloI a
interpret :: Monad m => (Int -> m ())
-> Elo a
-> Int
-> m a
interpret display = interp
where
interp :: Monad m => Elo a -> Int -> m a
interp = eval . view
eval :: Monad m => ProgramView EloI a -> Int -> m a
eval (Display i :>>= is) s = interp (is ()) s
Now I change the last line to
eval (Display i :>>= is) s = display i >> interp (is ()) s
and type inference doesn't succeed anymore, I get the output
Could not deduce (m ~ m1) from the context (Monad m)
bound by the type signature for interpret :: Monad m => (Int -> m ()) -> Elo a -> Int -> m a
(...)
When I remove the type signature for interp, I get an additional error (could not deduce (a1 ~ a)).
When I change all m to IO (like in the tic tac toe example for the operational monad), then it compiles again.
Am I trying something that does not make sense or can I provide some hint to GHC? I have to admit I'm not sure that I need this flexibility.

That's because the m in the local type signatures are fresh type variables, so they promise to work with any Monad. If you use display, eval can only work for the specific monad display uses. It should work if you a) remove the local type signatures, or b) bring the type variable m into scope
{-# LANGUAGE ScopedTypeVariables #-}
...
interpret :: forall m. (Int -> m ()) -> Elo a -> Int -> m a

Related

Using >> without explicitly declaring it in a monad

I am trying to get good at Monads and have written the following Monads and functions in which I use the >> (in the apply-function) although it is not declared in the Monad itself. How come this is possible to compile, as I understand http://learnyouahaskell.com/a-fistful-of-monads#walk-the-line it is required to declare it in the instantiation of the Monad as is the case with the Maybe Monad.
data Value =
NoneVal
| TrueVal | FalseVal
| IntVal Int
| StringVal String
| ListVal [Value]
deriving (Eq, Show, Read)
data RunErr = EBadV VName | EBadF FName | EBadA String
deriving (Eq, Show)
newtype CMonad a = CMonad {runCMonad :: Env -> (Either RunErr a, [String]) }
instance Monad CMonad where
return a = CMonad (\_ -> (Right a, []))
m >>= f = CMonad (\env -> case runCMonad m env of
(Left a, strLst) -> (Left a, strLst)
(Right a, strLst) -> let (a', strLst') = runCMonad (f a) env in (a', strLst ++ strLst'))
output :: String -> CMonad ()
output s = CMonad(\env -> (Right (), [] ++ [s]))
apply :: FName -> [Value] -> CMonad Value
apply "print" [] = output "" >> return NoneVal
Furthermore, how would I make it possible to show the output (print it) from the console when running apply. Currently I get the following error message, although my types have derive Show:
<interactive>:77:1: error:
* No instance for (Show (CMonad Value)) arising from a use of `print'
* In a stmt of an interactive GHCi command: print it
The >> operator is optional, not required. The documentation states that the minimal complete definition is >>=. While you can implement both >> and return, you don't have to. If you don't supply them, Haskell can use default implementations that are derived from either >> and/or Applicative's pure.
The type class definition is (current GHC source code, reduced to essentials):
class Applicative m => Monad m where
(>>=) :: forall a b. m a -> (a -> m b) -> m b
(>>) :: forall a b. m a -> m b -> m b
m >> k = m >>= \_ -> k
return :: a -> m a
return = pure
Notice that >>= lacks an implementation, which means that you must supply it. The two other functions have a default implementation, but you can 'override' them if you want to.
If you want to see output from GHCi, the type must be a Show instance. If the type wraps a function, there's no clear way to do that.
The declaration of Monad in the standard Prelude is as follows: (simplified from the Prelude source)
class Applicative m => Monad m where
(>>=) :: forall a b. m a -> (a -> m b) -> m b
(>>) :: forall a b. m a -> m b -> m b
m >> k = m >>= \_ -> k
{-# INLINE (>>) #-}
return :: a -> m a
return = pure
It's a typeclass with three methods, (>>=), (>>) and return.
Of those three, two have a default implementation - the function is implemented in the typeclass, and one does not.
Monad is a subclass of Applicative, and return is the same as pure - it is included in the Monad typeclass (or at all) for historical reasons.
Of the remaining two, (>>=) is all that is needed to define a Monad in Haskell. (>>) could be defined outside of the typeclass, like this:
(>>) :: (Monad m) => forall a b. m a -> m b -> m b
m >> k = m >>= \_ -> k
The reason this is included is in case a monad author wants to override the default implementation with an implementation which is more efficient.
A typeclass method which is not required is know as optional.
Haddock documentation automatically generates a 'Mnimal complete definition' based on the methods without default implementations. You can see here that the minimal definition of Monad is indeed (>>=).
Sometimes, all methods can have default implementations, but they are not optional. This can happen when one of two methods must be provided, and the other is defined in terms of it. This is the case for the Traversable typeclass, where traverse and sequenceA are both implemented in terms of each other. Not implementing either method will cause them to go into an infinite loop.
To let you mark this, GHC provides the MINIMAL pragma, which generates the neccesary compiler warnings, and ensures the Haddocks are correct.
As an aside, failing to implement a required typeclass method is by default a compiler warning, not an error, and will cause a runtime exception if called. There is no good reason for this behaviour.
You can change this default using the -Werror=missing-methods GHC flag.
Happy Haskelling!

Why does this type annotation make my functional dependency conflict go away? (and why does it only happen on some versions of GHC?)

So I've been playing around with MonadState class and I have encountered something I consider very strange.
I can try to write a monad like the following:
test ::
( MonadState Int m
, MonadState Bool m
)
=> m ()
test = do
((+1) <$> get) >>= put
(not <$> get) >>= put
If we compile this in ghc 8.6.4 we get the following:
MonadTrans.hs:10:13: error:
• Couldn't match type ‘Int’ with ‘Bool’
arising from a functional dependency between constraints:
‘MonadState Bool m’
arising from a use of ‘get’ at MonadTrans.hs:10:13-15
‘MonadState Int m’
arising from the type signature for:
test :: forall (m :: * -> *).
(MonadState Int m, MonadState Bool m) =>
m ()
at MonadTrans.hs:(4,1)-(8,11)
• In the second argument of ‘(<$>)’, namely ‘get’
In the first argument of ‘(>>=)’, namely ‘((+ 1) <$> get)’
In a stmt of a 'do' block: ((+ 1) <$> get) >>= put
|
10 | ((+1) <$> get) >>= put
|
(older versions of GHC for example 8.2.2 are actually fine with this and compile. I have no idea why.)
Ok this makes sense since the declaration of MonadState has a dependency in it:
class Monad m => MonadState s m | m -> s where
we cannot have a single Monad be both MonadState Int and MonadState Bool. But here is where things get a little strange.
If I add a type annotation the code will compile
test ::
( MonadState Int m
, MonadState Bool m
)
=> m ()
test = do
(((+1) :: Int -> Int) <$> get) >>= put
(not <$> get) >>= put
To me this seems very strange. A moment ago it was complaining about a very real functional dependency conflict between the two. I don't see how disambiguating the type of (+1) makes that conflict go away.
What is happening here? How does the second one compile while the first fails? And why does the first compile on 8.2.2?
Try this:
plus1 :: Int -> Int
plus1 = (+ 1)
test :: (MonadState Int m, MonadState Bool m) => m ()
test = do
(plus1 <$> get) >>= put
(not <$> get) >>= put
Compiles fine, even without the inline type annotation.
What the functor?!
The thing is, when the compiler complains in your first example, it doesn't complain about the type signature just because it decided to verify it for the heck of it. Look a bit further in the error message: ...In the second argument of ‘(<$>)’, namely ‘get’...
Aha! The source of trouble is actually get! But why?
The trouble is the bloody overloaded arithmetic. You see, operator (+) has a polymorphic type, like this:
(+) :: Num a => a -> a -> a
And naked literals also have similar type:
1 :: Num a => a
So when you write (+1), it doesn't let the compiler know that you meant Int. It admits any type a as long as there is Num a.
So the compiler turns to further surroundings to get the type. But wait! Further surroundings are also generic:
get :: MonadState a m => m a
put :: MonadState a m => a -> m ()
Ok, so maybe we can get the type from the signature of test? Let's check that! Oh, no, the signature actually contains a conflict! Bail, bail, bail! That's when you get the error.
All of this doesn't happen on the second line, because not has a non-polymorphic type not :: Bool -> Bool, so the required type of get is known. And this is why either giving an inline type annotation Int -> Int or having it come from an external function plus1 helps on the first line as well.
If you do provide enough type information for the values in the body, the compiler never has to analyze the test signature. The signature specifies that there should be a MonadState Int m dictionary, and that's good enough. Whoever calls the function will have provide the dictionary, and we'll just use that.
Now, of course, when you get around to calling this function, you'll need to provide both dictionaries MonadState Int m and MonadState Bool m, and you can't get those, so you can't actually call such function. But you sure can define it.
That being said, you CAN actually have a monad with two different MonadState instances if you're willing to be sneaky enough about it.
Of course, if you try it straight up, you get a very straight up error:
data M a = M
instance MonadState Int M
instance MonadState Bool M
> Functional dependencies conflict between instance declarations:
> instance MonadState Int M -- Defined at ...
> instance MonadState Bool M -- Defined at ...
Ok, let's start small:
data M a = M
instance MonadState Int M
> Illegal instance declaration for `MonadState a M'
> The liberal coverage condition fails in class `MonadState'
> for functional dependency: `m -> s'
> Reason: lhs type `M' does not determine rhs type `a'
> Un-determined variable: a
Alright, so something in the type of M must indicate the type Int. That makes sense. Let's add it:
data M x a = M a
instance MonadState Int (M Int)
Ok, this works. So far so good.
But of course, in order to define MonadState Bool, I need to add Bool to the type as well:
data M x y a = M a
instance MonadState Int (M Int y)
instance MonadState Bool (M x Bool)
> Functional dependencies conflict between instance declarations:
Ah, still fundep failure! Ok, well, that makes sense too.
So is there a way I can fool the compiler into not checking the instances for the fundep? Yes, there is! I can be sneaky and make the instances overlapped, like this:
instance {-# OVERLAPPABLE #-} (Num a, Show a) => MonadState a (M a y) where
get = M 42
put x = M ()
instance {-# OVERLAPPING #-} MonadState Bool (M x Bool) where
get = M True
put x = M ()
Now all that's left is the Monad instance, and we can have it all actually run:
data M x y a = M a deriving (Functor, Show)
instance Applicative (M x y) where
pure = M
(M f) <*> (M x) = M $ f x
instance Monad (M x y) where
(M x) >>= f = f x
instance {-# OVERLAPPABLE #-} (Num a, Show a) => MonadState a (M a y) where
get = M 42
put x = trace ("Setting Num: " ++ show x) $ M ()
instance {-# OVERLAPPING #-} MonadState Bool (M x Bool) where
get = M True
put x = trace ("Setting Bool: " ++ show x) $ M ()
g :: M Int Bool ()
g = test
main = print g
I've included debug trace to verify how they're actually going to work, so the above program prints:
Setting Num: 43
Setting Bool: False
M ()

Can the type of this function be declared in standard Haskell

The following program compiles under GHC 8.0.2 with no language extensions, and produces the expected two lines of output.
However, it does not compile if the (non-top-level) type declaration for the value write' is removed.
Also, I cannot find any (top-level) type declaration for the function write.
I find this rather odd. If this is acceptable standard Haskell, surely it should be possible to create a type declaration for the function write.
So my question is: is there such a type declaration?
import Control.Monad.Trans.Maybe (MaybeT, runMaybeT)
import Control.Monad.Writer (MonadTrans, Writer, lift, runWriter, tell, when)
import ListT (ListT, toList) -- Volkov's list-t package
logging = True
write x = when logging write' where
write' :: MonadTrans m => m (Writer [String]) ()
write' = lift $ tell [x]
f :: ListT (Writer [String]) String
f = do
write "Hello from f"
return "ABC"
g :: MaybeT (Writer [String]) Int
g = do
write "Hello from g"
return 123
main :: IO ()
main = do
print $ runWriter $ toList f
print $ runWriter $ runMaybeT g
Using GHCi (remember to put this into a separate file and load it on GHCi's command line lest you get confused by GHCi's altered typing rules):
> :t write
write :: (Applicative (m (Writer [String])), MonadTrans m) =>
String -> m (Writer [String]) ()
Why? Well,
write' :: MonadTrans m => m (Writer [String]) ()
when :: Applicative f => Bool -> f () -> f ()
when logging :: Applicative f => f () -> f ()
so, when logging write' must unify write''s m (Writer [String]) with when loggings's f, causing the combined constraint (Applicative (m (Writer [String])), MonadTrans m). But wait, let's remove the type signatures and see what the most general type is:
-- equivalent but slightly easier to talk about
write = when logging . lift . tell . (:[])
(:[]) :: a -> [a]
tell :: MonadWriter w m -> w -> m ()
lift :: (Monad m, MonadTrans t) => m a -> t m a
tell . (:[]) :: MonadWriter [a] m => a -> m ()
lift . tell . (:[]) :: (MonadWriter [a] m, MonadTrans t) => a -> t m ()
when logging . lift . tell . (:[]) = write
:: (Applicative (t m), MonadWriter [a] m, MonadTrans t) => a -> t m ()
-- GHCi agrees
Per se, there's nothing wrong with this type. However, standard Haskell does not allow this. In standard Haskell, a constraint must be of the form C v or C (v t1 t2 ...) where v is a type variable. In the compiling case, this holds: the Applicative constraint has the type variable m on the outside, and the MonadTrans is just m. This is true in the non-compiling version, too, but we also have the constraint MonadWriter ([] a) m. [] is no type variable, so the type here is rejected. This constraint arises in the compiling version, too, but the type signatures nail the variables down to produce MonadWriter [String] (Writer [String]), which is immediately satisfied and does not need to appear in the context of write.
The restriction is lifted by enabling FlexibleContexts (preferably via a {-# LANGUAGE FlexibleContexts #-} pragma, but also maybe by -XFlexibleContexts). It originally existed to prevent things such as the following:
class C a where c :: a -> a
-- no instance C Int
foo :: C Int => Int
foo = c (5 :: Int)
-- with NoFlexibleContexts: foo's definition is in error
-- with FlexibleContexts: foo is fine; all usages of foo are in error for
-- not providing C Int. This might obscure the source of the problem.
-- slightly more insiduous
data Odd a = Odd a
-- no Eq (Odd a)
oddly (Odd 0) (Odd 0) = False
oddly l r = l == r
-- oddly :: (Num a, Eq (Odd a), Eq a) => Odd a -> Odd a -> Bool
-- Now the weird type is inferred! With FlexibleContexts,
-- the weird constraint can propagate quite far, causing errors in distant
-- places. This is confusing. NoFlexibleContexts places oddly in the spotlight.
But it happens to get in the way a lot when you have MultiParamTypeClasses on.

Can a typeclass constraint be used in a newtype definition?

Suppose we have the following newtype definition:
newtype A = A { _run :: Monad m => A -> [Int] -> m Int }
This does not compile with GHC 8.0.2:
error: Not in scope: type variable ‘m’
Replacing m with a concrete typeclass like IO or [] does compile, as I would expect. Given that this is ok, why does GHC not allow the signature above? What is wrong with adding a typeclass constraint inside of this newtype?
It depends on what you're trying to store in A.
If you're trying to store any function like that, as long as m is a Monad, use it as a type parameter, and specify this contraint in your functions:
newtype A m = A { _run :: A m -> [Int] -> m Int }
myFunction :: Monad m => A m -> A m
You could then have things like A [] -> [Int] -> [Int] or A Maybe -> [Int] -> Maybe Int inside the constructor.
f :: A Maybe -> [Int] -> Maybe Int
f _ (x:_) = Just x
f _ [] = Nothing
g :: Monad m => A m -> [Int] -> m Int
g _ xs = return $ head xs
myA :: A Maybe
myA = A f -- this works
myOtherA :: Monad m => A m
myOtherA = A g -- this works too
On the other hand, if you want to force the data you store to be polymorphic, you can use the GHC extension RankNTypes.
{-# LANGUAGE RankNTypes #-}
newtype A = A { _run :: forall m. Monad m => A -> [Int] -> m Int }
myFunction :: A -> A
You couldn't have things like A -> [Int] -> [Int] or A -> [Int] -> Maybe Int within the constructor, because the forall forces them to be general over any Monad m, so it would have to be of type Monad m => A -> [Int] -> Maybe Int.
f :: A -> [Int] -> Maybe Int
f _ (x:_) = Just x
f _ [] = Nothing
g :: Monad m => A -> [Int] -> m Int
g _ xs = return $ head xs
myA :: A
myA = A f -- this does not work ; it wants forall m. Monad m => m, not []
myOtherA :: A
myOtherA = A g -- this does work
This will only really be useful if you intend to use different specific Monad instances for an A-value. For example, Lenses work this way by using different functors to do different things to the lens.
This is possible:
{-# LANGUAGE RankNTypes #-}
newtype A = A { _run :: forall m. Monad m => A -> [Int] -> m Int }
It's hard to tell what you want to do, but this isn't very usable. Any value of type A needs to work for all monads (you don't get to choose).
This is also possible, with the same restrictions:
{-# LANGUAGE GADTs #-}
data A where A :: Monad m => (A -> [Int] -> m Int) -> A
But perhaps you mean something more like
newtype A m = A { _run :: A m -> [Int] -> m Int }
This allows for values of different types of A using different monads.
How would GHC know what instance of Monad to use when you create a piece of data of type A?
Or, put another way, the type variable m isn't in scope on the left hand side of the type definition. That means it doesn't know what m should be, and can't work it out. It's implicit.
I'm sure there's some way you could do what you want to with an extension, probably using an explicit forall. (The RankNTypes extension), however we'd need to know what you were after a bit more.

Lift a function and its argument to a different monadic context

I am not sure how to formulate this question scientifically exact, so I am just going to show you an example.
I am using state in a StateT transformer. Underlying is IO. Inside the StateT IO operation I need to use alloca. However, I can't lift alloca to StateT IO because it expects an argument of type (Ptr a -> IO a) while I require it to work with an argument of (Ptr a -> StateT IO MyState a).
(However, this is a generic question about monad transformers rather than specific to IO, StateT or alloca.)
I came up with the following, working solution:
-- for reference
-- alloca :: (Storable a) => (Ptr a -> IO b) -> IO b
allocaS :: (Storable a) => (Ptr a -> StateT s IO b) -> StateT s IO b
allocaS f = do
state <- get
(res, st) <- liftIO $ alloca $ \ptr -> (runStateT (f ptr) state)
put st
return res
However, it seems wrong to me that I should have to de- and reconstruct the StateT action in order to use it with alloca. Also, I have seen this pattern in some variations more than once and it's not always as simple and safe as here with StateT.
Is there a better way to do this?
This can be accomplished using MonadBaseControl in monad-control, which has been devised exactly for this purpose:
{-# LANGUAGE FlexibleContexts #-}
import Control.Monad
import Control.Monad.Trans.Control
import qualified Foreign.Ptr as F
import qualified Foreign.Marshal.Alloc as F
import qualified Foreign.Storable as F
alloca :: (MonadBaseControl IO m, F.Storable a) => (F.Ptr a -> m b) -> m b
alloca f = control $ \runInIO -> F.alloca (runInIO . f)
This enhanced version of alloca can be used with any monad stack based on IO that implements MonadBaseControl, including StateT s IO.
Instances of MonadBaseControl allow their monadic values to be encoded in the base monad (here IO), passed to a function in the base monad (like F.alloca) and then reconstruct them back.
See also What is MonadBaseControl for?
Package lifted-base contains many of the standard IO functions lifted to MonadBaseControl IO, but alloca isn't (yet) among them.
Good afternoon,
AFAIK, there is no general way to turn a function of type (a -> m b) -> m b into (a -> t m b) -> t m b because that would imply the existence of a function of type MonadTrans t => (a -> t m b) -> (a -> m b).
Such a function cannot possibly exist, since most transformers cannot be stripped so easily from a type signature (how do you turn a MaybeT m a into an m a for all a ?). Hence, the most general way to turn (a -> m b) -> m b to (a -> t m b) -> t m b is undefined.
In the case of StateT s m, there is a loophole that allows you to define it anyway. Since StateT s m a === s -> m (s,a), we can rewrite the type equation to :
(a -> StateT s m b) -> StateT s m b
=== (a -> s -> m (s,b)) -> s -> m (s,b)
=== s -> (s -> (a -> m (s,b)) -> m (s,b) -- we reorder curried arguments
=== s -> (s -> (A -> m B)) -> m B -- where A = a, B = (s,b)
Solving this new type signature is now trivial :
liftedState f s run = f (run s)
allocaS :: Storable a => (Ptr a -> StateT IO b) -> StateT IO b
allocaS = isomorphic (liftedState alloca)
That is about the best we can do in terms of code reuse, short of defining a new subclass of MonadTrans for all monads that exhibit the same behaviour.
I hope I made myself clear enough (I didn't want to go into too much detail for fear of being confusing)
Have an excellent day :-)

Resources