GHC type inference woes - haskell

Question. Is there any way to make this code work without an explicit type signature?
Code. First, I have a in-practice-much-nicer alternate MonadTrans class, inspired by Data.Newtype. It looks like this,
{-# LANGUAGE FlexibleContexts, TypeFamilies #-}
module Alt.Control.Monad.Trans where
import Control.Monad
class (Monad 𝔪, Monad (BaseMonad 𝔪)) => MonadTrans (𝔪 :: * -> *) where
type BaseMonad 𝔪 :: * -> *
lift :: (BaseMonad 𝔪) α -> 𝔪 α
Then, I have a class A with method foo, and if some base monad M is an A, then any transformed monad T M is also an A. In code,
class A 𝔪 where
foo :: String -> 𝔪 ()
instance (A (BaseMonad 𝔪), MonadTrans 𝔪) => A 𝔪 where
foo n = lift $ foo n
However, if I now want to create a shortcut for foo with its first argument substituted, then I need an explicit type signature, or the compiler's context stack overflows.
minimize_call :: A 𝔪 => 𝔪 ()
minimize_call = foo "minimize"
Possible info to help inference. Let's say we have an associated type B :: * -> *. I'm thinking that I want to tell the compiler B satisfies B t /= t, B (B t) /= B t, etc. i.e. B is somehow "monotonic" -- that chasing associated types is equivalent to removing newtype wrappers, and it should know that it cannot remove newtype wrappers forever, hence adding the context A to the signature is necessary.

Yes, there is a way. Provide a grounded instance for A, and add NoMonomorphismRestriction to the language pragma (in addition to the also required FlexibleInstances and UndecidableInstances).
However, the A class will be unusable. There is no way for the compiler to know that there never will be a MonadTrans instance with BaseMonad m = m. Thus it cannot select an instance, ever, because it cannot know whether to use the instance from here or another one.
{-# LANGUAGE FlexibleContexts, TypeFamilies, FlexibleInstances, UndecidableInstances, NoMonomorphismRestriction #-}
module Trans (MonadTrans(..), A(..), minimize_call) where
import Control.Monad
class (Monad m, Monad (BaseMonad m)) => MonadTrans (m :: * -> *) where
type BaseMonad m :: * -> *
lift :: (BaseMonad m) α -> m α
class A m where
foo :: String -> m ()
data Foo a = Bork
instance Monad Foo where
return _ = Bork
_ >>= _ = Bork
instance A Foo where
foo _ = Bork
instance (A (BaseMonad m), MonadTrans m) => A m where
foo n = lift $ foo n
-- minimize_call :: A m => m ()
minimize_call = foo "minimize"
compiles with ghc 6.12, 7.0, 7.2 and 7.4. Without the signature, minimize_call must get a monomorphic type, unless the MR is turned off. That can't work anyway because the constraint A m is not defaultable. So therefore the MR must be turned off. But then the type checker still chases its own tail trying to prove the constraint is satisfiable. With only the lifting instance, it can't. If you provide an anchor, it can.
But providing a type signature is much much better.

Related

Getting confused with complex Haskell typeclass declarations

I have a type alias for a monad transformer stack:
type KStat s a = ReaderT (KStatRoot s) (ExceptT KindError (ST s)) a
I need to abstract users away from this type, largely because the KStatRoot structure was causing cyclic dependencies. I therefore created a separate module and defined a typeclass for it:
class (Monad (m s), MonadError KindError (m s)) =>
MStat m s where
liftToST :: ST s a -> m s a
kstatNewRef :: a -> m s (STRef s a)
kstatReadRef :: STRef s a -> m s a
kstatWriteRef :: STRef s a -> a -> m s ()
This definition compiles OK (albeit needing {-# LANGUAGE MultiParamTypeClasses,FlexibleContexts #-} to work, but I can see why both of those are required), and I've been able to convert some use sites to the typeclass and have them type check, so everything seems OK there. But I'm struggling to work out how to define my instance for the class:
instance MStat (KStat s a) s where
liftToST = lift . lift
kstatNewRef = liftToST . newSTRef
kstatReadRef = liftToST . readSTRef
kstatWriteRef r v = liftToST $ writeSTRef r v
gives me the error:
src/KindLang/Data/KStat.hs:27:17:
The first argument of ‘MStat’ should have kind ‘* -> * -> *’,
but ‘KStat s a’ has kind ‘*’
In the instance declaration for ‘MStat (KStat s a) s’
which kind of makes sense, but then if I change KStat s a to KStat in the instance header I get this error:
src/KindLang/Data/KStat.hs:27:10:
Type synonym ‘KStat’ should have 2 arguments, but has been given none
In the instance declaration for ‘MStat KStat s’
which seems to basically saying the exact opposite.
I'm using these language extensions in the module I declare the instance:
{-# LANGUAGE RankNTypes, TypeSynonymInstances, FlexibleInstances, MultiParamTypeClasses #-}
How do I resolve these errors?
Complete file demonstrating the errors follows:
{-# LANGUAGE RankNTypes, TypeSynonymInstances, FlexibleContexts,
FlexibleInstances, MultiParamTypeClasses #-}
import Control.Monad.Except
import Control.Monad.ST
import Control.Monad.Reader
import Data.STRef
data KStatRoot s = KStatRoot
data KindError
class (Monad (m s), MonadError KindError (m s)) =>
MStat m s where
liftToST :: ST s a -> m s a
kstatNewRef :: a -> m s (STRef s a)
kstatReadRef :: STRef s a -> m s a
kstatWriteRef :: STRef s a -> a -> m s ()
type KStat s a = ReaderT (KStatRoot s) (ExceptT KindError (ST s)) a
instance MStat (KStat s m) s where
liftToST = lift . lift
kstatNewRef = liftToST . newSTRef
kstatReadRef = liftToST . readSTRef
kstatWriteRef r v = liftToST $ writeSTRef r v
The first error is "correct" (you need to use a type of two arguments in the instance declaration), and your attempted fix makes sense.
However, a type synonym doesn't really exist without its arguments. That is, after
type Foo a = ...
you can't use Foo by itself. Foo has to be applied to an argument in order to be processed by the type checker. This is the cause of your second error.
The only workaround I see is changing KStat to a newtype:
newtype KStat s a = KStat{ runKStat :: ReaderT (KStatRoot s) (ExceptT KindError (ST s)) a }
That will let you use KStat without arguments. You'll just have to add explicit runKStat/KStat conversions everywhere.

Two functions compile with type annotations. Remove one annotation - doesn't compile. Remove two - compiles again. Why?

Mind this Reflex program:
{-# LANGUAGE ScopedTypeVariables, RecursiveDo #-}
import Control.Applicative
import Control.Monad
import Control.Monad.IO.Class
import Prelude hiding (div)
import Reflex.Dom
import qualified Data.Map as M
clickMe :: MonadWidget t m => m (Event t ())
clickMe = do
rec (e,_) <- elAttr' "button" M.empty (display c)
c :: Dynamic t Int <- count (domEvent Click e)
return $ domEvent Click e
div :: forall t m a . MonadWidget t m => m a -> m a
div = elAttr "div" ("style" =: "border : 1px solid black")
app :: forall t m . MonadWidget t m => m ()
app = div $ do
aClicks <- clickMe
bClicks <- clickMe
a <- count aClicks
b <- count bClicks
l <- combineDyn (\a b -> replicate (a-b) ()) a b
simpleList l (const clickMe)
return ()
main = mainWidget app
If you remove the type annotation from either div or app, the program won't compile with a huge, scary type error. If you remove both, it will compile again. From a programmer's perspective, this gives a terrible user experience when someone is trying to incrementally annotate an unannotated program. It makes no sense that adding a correct type annotation to an unannotated term causes a compiler error, and it leads the programmer to think he got the type wrong.
This is the error you get by removing div's annotation.
Those are the inferred types.
Why this happens?
This is due to to the monomorphism restriction. When the compiler is typechecking a top-level binding without a type annotation, it will not assign a polymorphic type if that type has a constraint and the function has no syntactic argument, which is the case for both of your functions.
However, if you include neither type signature, it still doesn't compile. In your case, you gave it some extra information (the foo = [app, _] part) and for some reason it chose to pick a monomorphic type - I don't know what changed about your environment but that isn't standard behaviour.
Here is a simple file distilling the issue you are having:
{-# LANGUAGE RankNTypes, KindSignatures, MultiParamTypeClasses, FunctionalDependencies #-}
module Test where
import Prelude hiding (div)
class MonadWidget t (m :: * -> *) | m -> t
div :: forall t m a . MonadWidget t m => m a -> m a
div = (undefined :: forall t m a . MonadWidget t m => m a -> m a)
app :: forall t m . MonadWidget t m => m ()
app = (div (undefined :: forall t m . MonadWidget t m => m ())
:: forall t m . MonadWidget t m => m () )
If you comment out either type signature, or both, you will be met with an error.
However, comment out any top-level type signature, but run this with ghc -XNoMonomorphismRestriction Test.hs and it will compile successfully in every configuration. Here are a few tests.
As Reid Barton noted in comments, this is due to The Dreaded Monomorphism Restriction.
Here is simplified example:
foo :: Monad m => m a -> m a
foo = (>>= return)
bar :: Monad m => m ()
bar = foo (return ())
When monomorphism restriction enabled and foo's type signature commented:
GHC tries to assign monomorphic type to to foo and fails because there is no default Monad instance:
No instance for (Monad m0) arising from a use of ‘>>=’
The type variable ‘m0’ is ambiguous
using foo at bar leads to another error which I cannot explain
Couldn't match type ‘m0’ with ‘m’
because type variable ‘m’ would escape its scope
Adding {-# LANGUAGE NoMonomorphismRestriction #-} pragma fixes this and allows to add type signatures incrementally.

Why does this code require the Monad constraint?

While building a monad stack with monad transformers to write a library, I hit a question about the behavior of it.
The following code won't pass the type checker:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Foo (FooM, runFooM, foo) where
import Control.Applicative
import Control.Monad.Reader
newtype FooM m a = FooM { runFooM :: ReaderT Int m a }
deriving (Functor, Applicative, Monad, MonadReader Int)
foo :: FooM m Int
foo = do
x <- ask
return x
The error is:
$ ghc foo.hs
[1 of 1] Compiling Foo ( foo.hs, foo.o )
foo.hs:12:3:
No instance for (Monad m) arising from a do statement
Possible fix:
add (Monad m) to the context of
the type signature for foo :: FooM m Int
In a stmt of a 'do' block: x <- ask
In the expression:
do { x <- ask;
return x }
In an equation for ‘foo’:
foo
= do { x <- ask;
return x }
The fix is easy as GHC suggests, just adds Monad constraint to the foo function:
foo :: Monad m => FooM m Int
foo = do
x <- ask
return x
But here, the foo function only asks the FooM value to give its Int value and it is already an (automatically derived) MonadReader instance.
So I think Monad constraint is not required to m.
I guess this relates to the implementation of the monad transformers (I use mlt==2.2.1),
but I cannot figure out the exact reason.
I may miss something obvious though.
Could you explain why this doesn't pass the checker?
Thanks.
It's because the Monad instance for ReaderT is defined as
instance Monad m => Monad (ReaderT r m)
i.e. the type ReaderT r m is an instance of Monad only if the inne rm is an instance of Monad. That's why you cannot have an unconstrained m when using the Monad instance of ReaderT (which your FooM type is using via the deriving mechanism).
returns type is Monad m => a -> m a, hence the need for the constraint.
By the monad laws, foo ≡ ask, which will indeed work without the Monad constraint. But if you don't require Monad, then GHC can hardly make simplifications based on these laws, can it? Certainly not before type checking the code. And what you wrote is syntactic sugar for
foo = ask >>= \x -> return x
which requires both (>>=) :: Monad (FooM m) => FooM m Int -> (Int->FooM m Int) -> FooM m Int and return :: Monad (FooM m) => Int->FooM m Int.
Again, the >>= return does nothing whatsoever for a correct monad, but for a non-monad it isn't even defined and can thus not just be ignored.

Forall'd constraint is not bound in RULE by lhs

I'm messing around with the SPECIALIZE pragma while trying to find a solution to this problem.
I came up with this example:
{-# LANGUAGE FlexibleContexts, GeneralizedNewtypeDeriving #-}
import Data.Vector
import qualified Data.Vector.Generic as V
class Foo a
newtype Phantom m = T Int deriving (Show)
instance (Foo m) => Num (Phantom m)
f :: (Num r, V.Vector v r) => v r -> v r -> v r
{-# SPECIALIZE f :: (Foo m) => Vector (Phantom m) -> Vector (Phantom m) -> Vector (Phantom m) #-}
f x y = V.zipWith (+) x y
main = print "hello"
which fails to compile (GHC 7.6.2) because
Forall'd constraint `Foo m' is not bound in RULE lhs.
Googling only turned up a couple of GHC bug reports from years ago. I didn't see anything about "forall'd constraints" while reading about SPECIALIZE or RULE. My specialize signature does seem less polymorphic than the original, and it satisfies the "if-and-only-if" rule.
replace with
{-# SPECIALIZE f :: (Num (Phantom m)) => Vector (Phantom m) -> Vector (Phantom m) -> Vector (Phantom m) #-}
and it will work. The r in Num r is Phantom m not m, thus you can't add the constraint Num m. This is logical--Num (Phantom m) does not imply Num m and you could get other instances under the open world assumption.
EDIT:
You actually don't need any constraint at all in this case
{-# SPECIALIZE f :: Vector (Phantom m) -> Vector (Phantom m) -> Vector (Phantom m) #-}
anyway, the basic problem if I understand what you are trying to do is that you can't constrain when you perform an optimization based on phantom type parameters.

Haskell: Overlapping instances

Consider the following example program:
next :: Int -> Int
next i
| 0 == m2 = d2
| otherwise = 3 * i + 1
where
(d2, m2) = i `divMod` 2
loopIteration :: MaybeT (StateT Int IO) ()
loopIteration = do
i <- get
guard $ i > 1
liftIO $ print i
modify next
main :: IO ()
main = do
(`runStateT` 31) . runMaybeT . forever $ loopIteration
return ()
It can only use get instead of lift get because instance MonadState s m => MonadState s (MaybeT m) is defined in the MaybeT module.
Many such instances are defined in kind of a combinatoric explosion manner.
It would have been nice (although impossible? why?) if we had the following type-class:
{-# LANGUAGE MultiParamTypeClasses #-}
class SuperMonad m s where
lifts :: m a -> s a
Let's try to define it as such:
{-# LANGUAGE FlexibleInstances, ... #-}
instance SuperMonad a a where
lifts = id
instance (SuperMonad a b, MonadTrans t, Monad b) => SuperMonad a (t b) where
lifts = lift . lifts
Using lifts $ print i instead of liftIO $ print i works, which is nice.
But using lifts (get :: StateT Int IO Int) instead of (get :: MaybeT (StateT Int IO) Int) doesn't work.
GHC (6.10.3) gives the following error:
Overlapping instances for SuperMonad
(StateT Int IO) (StateT Int IO)
arising from a use of `lifts'
Matching instances:
instance SuperMonad a a
instance (SuperMonad a b, MonadTrans t, Monad b) =>
SuperMonad a (t b)
In a stmt of a 'do' expression:
i <- lifts (get :: StateT Int IO Int)
I can see why "instance SuperMonad a a" applies. But why does GHC think that the other one does, too?
To follow up ephemient's excellent answer: Haskell type classes use an open-world assumption: some idiot can come along later and add an instance declaration that's not a duplicate and yet overlaps with your instance. Think of it as an adversary game: if an adversary can make your program ambiguous, the compiler bleats.
If you're using GHC you can of course say to the compiler "to hell with your paranoia; allow me my ambiguous instance declaration":
{-# LANGUAGE OverlappingInstances #-}
If later evolution of your program leads to overload resolution you didn't expect, the compiler gets 1,000 I-told-you-so points :-)
Deprecation Note
This pragma has been deprecated since GHC 7.10, and per-instance pragmas should be used instead. More detail can be found in the GHC documentation.
Just because you haven't defined an instance in your current module doesn't mean that one couldn't be defined somewhere else.
{-# LANGUAGE ... #-}
module SomeOtherModule where
-- no practical implementation, but the instance could still be declared
instance SuperMonad (StateT s m) m
Suppose your module and SomeOtherModule are linked together in a single program.
Now, answer this: does your code use
instance SuperMonad a a
-- with a = StateT Int IO
or
instance (SuperMonad a b, MonadTrans t, Monad b) => SuperMonad a (t b)
-- with a = StateT Int IO
-- t = StateT Int
-- b = IO
?
When you have overlapping instances try to attach their behaviour to newtypes:
type SuperEgo :: (k -> Type) -> (k -> Type)
newtype SuperEgo m a = SuperEgo (m a)
type Elevator :: (k -> k1 -> Type) -> (k -> k1 -> Type)
newtype Elevator trans m a = Elevator (trans m a)
instance SuperMonad m (SuperEgo m) where
lifts :: m ~> SuperEgo m
lifts = SuperEgo
instance (SuperMonad m super, Monad super, MonadTrans trans) => SuperMonad m (Elevator trans super) where
lifts :: m ~> Elevator trans super
lifts = Elevator . lift . lifts
Monads can now derive via SuperEgo M to get an identity instances
{-# Language DerivingVia #-}
data Ok a = Ok a
deriving (SuperMonad Ok)
via SuperEgo Ok
It's more of a hassle to define a monad transformer so I'll show how to define a lifting instance for an existing Monad transformers like StateT s. This uses standalone deriving which is more verbose, you need to fill in the class context yourself:
deriving
via Elevator (StateT s) super
instance (Monad super, SuperMonad m super) => SuperMonad m (StateT s super)

Resources