How does GADTs affect type inference in this case? - haskell

Say I have a monad that emits soft failure through Writer. A simplified version goes like this (for the record, I'm using GHC 9.0.2):
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE FlexibleContexts #-}
-- {-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Lib where
import Control.Monad.Writer.CPS
import Data.Maybe
verify :: MonadWriter [String] m => some -> args -> m ()
verify _ _ = fix \(_ :: m ()) ->
do
let warn = tell . (: [])
a = Just 1 :: Maybe Int
b = Just [1, 23] :: Maybe [Int]
c = Just (id :: forall a. a -> a)
-- isJust' :: String -> Maybe a -> m ()
isJust' tag v = unless (isJust v) do
warn $ tag <> " is Nothing"
isJust' "a" a
isJust' "b" b
isJust' "c" c
All goes fine until I add GADTs extension, then GHC fails to find the most general type for isJust':
• Couldn't match type ‘[Int]’ with ‘Int’
Expected: Maybe Int
Actual: Maybe [Int]
• In the second argument of ‘isJust'’, namely ‘b’
In a stmt of a 'do' block: isJust' "b" b
In the expression:
do let warn = tell . (: [])
a = ...
....
isJust' "a" a
isJust' "b" b
isJust' "c" c
|
22 | isJust' "b" b
| ^
/var/tmp/demo/src/Lib.hs:23:17: error:
• Couldn't match type ‘a0 -> a0’ with ‘Int’
Expected: Maybe Int
Actual: Maybe (a0 -> a0)
• In the second argument of ‘isJust'’, namely ‘c’
In a stmt of a 'do' block: isJust' "c" c
In the expression:
do let warn = tell . (: [])
a = ...
....
isJust' "a" a
isJust' "b" b
isJust' "c" c
|
23 | isJust' "c" c
| ^
At which point I have to uncomment type annotation for isJust' to get this to type check - I'm wondering what is at play here, I don't think I'm using any GADTs features?
Side note 1: I usually just slam a NoMonomorphismRestriction to see if it helps, it didn't.
Side note 2: That use of fix is just for getting a hold on that m in the presence of ScopedTypeVariables - a side question is whether there are better ways to do this without relying on verify having an explicit type signature (say this function is defined inside an instance).

The problem is not GADTs but MonoLocalBinds, which is automatically enabled by GADTs. The issue is that isJust' :: String -> Maybe a -> m () has a polymorphic type signature, meaning you get to choose what a is every time you call it. At least, it would be polymorphic if MonoLocalBinds wasn't enabled. Per the documentation:
With MonoLocalBinds, a binding group will be generalised if and only if
It is a top-level binding group, or
Each of its free variables (excluding the variables bound by the group itself) is closed (see next bullet), or
Any of its binders has a partial type signature (see Partial Type Signatures).
If a variable does not satisfy one of the three bullets, its type is not generalized, i.e. it does not get to be polymorphic.
There is a rigorous definition of what a "closed variable" is, but the important part is:
if a variable is closed, then its type definitely has no free type variables.
The second argument of isJust' has type Maybe a for some unknown a, meaning it is not closed (edit: see Li-yao Xia's correction in the comments). So, bullet 1 is not satisfied because isJust' is defined within verify, bullet 2 is not satisfied because the second argument of isJust' is not closed, and bullet 3 is not satisfied because there are no holes in the type of isJust'. Thus, isJust' is not polymorphic after all.
All this means is that the a in String -> Maybe a -> m () is actually a fixed type that GHC has to infer. It sees you call isJust' "a" (a::Maybe Int) and assumes a ~ Int, but then it sees isJust' "b" (b::Maybe [Int]) and assumes a ~ [Int] as well. Obviously this is a problem, so GHC complains. The only thing adding the type signature does is tell GHC to make isJust' polymorphic.
Note that you can have GADTs and NoMonoLocalBinds at the same time, but because type inference with GADTs is tricky this will probably just cause more problems when you actually use GADTs.

Related

Haskell Wreq - Couldn't match expected type ‘GHC.Exts.Item a0’

I'm experiencing a type error when I run the following code:
runPost :: IO String
runPost = do
res <- post "http://httpbin.org/post" ["num" := (31337 :: Int)]
return $ show res
The error is the following:
• Couldn't match expected type ‘GHC.Exts.Item a0’
with actual type ‘FormParam’
The type variable ‘a0’ is ambiguous
• In the expression: "num" := (31337 :: Int)
In the second argument of ‘post’, namely
‘["num" := (31337 :: Int)]’
In a stmt of a 'do' block:
res <- post "http://httpbin.org/post" ["num" := (31337 :: Int)]
When I inspect the type of := in ghci, I see what appears to be the correct type:
*Main Network.Wreq> :t (:=)
(:=)
:: FormValue v =>
Data.ByteString.Internal.ByteString -> v -> FormParam
What I'm wondering is why GHC.Exts.Item is appearing as the expect type when I run the compiler. I've only imported the functions I'm using from Network.Wreq. Any ideas what might be going on here?
It's clear (to the compiler, if not to your fellow human) that ("num" := (31337 :: Int)) :: FormParam. What isn't clear to the compiler (and which you need to help it decide on) is the type of [x] once x is known to be a FormParam.
The Item "type" is actually a type family, coming from the IsList class; and the IsList connection is coming from having the OverloadedLists extension turned on.
Here's a minimal program that causes basically the same error, which should make it more clear what's going on:
{-# LANGUAGE OverloadedLists #-}
main :: IO ()
main = print [True]
• Couldn't match expected type ‘GHC.Exts.Item a0’
with actual type ‘Bool’
The type variable ‘a0’ is ambiguous
• In the expression: True
In the first argument of ‘print’, namely ‘[True]’
In the expression: print [True]
|
4 | main = print [True]
| ^^^^
The print function has type Show a => a -> IO (). If the OverloadedLists extension weren't enabled, then the expression [True] would have type [Bool], and everything would be fine. But with the OverloadedLists extension enabled, the expression [True] instead has type (GHC.Exts.IsList l, GHC.Exts.Item l ~ Bool) => l. After unifying, print [True] ends up basically having type (Show a, GHC.Exts.IsList a, GHC.Exts.Item a ~ Bool) => IO (). Notice that the type variable a doesn't appear anywhere to the right of the =>, which makes that an ambiguous type. To make the ambiguity even more concrete, note that in addition to [Bool], the type NonEmpty Bool would also work for a there. The compiler doesn't know which one you want and doesn't want to guess, so it gives you that error. To solve the problem, add a type annotation, like this: main = print ([True] :: [Bool])
For the actual problem in your question, the only differences are that you have the Postable typeclass instead of Show, and the FormParam type instead of Bool. You can fix your problem by replacing the erroring line with res <- post "http://httpbin.org/post" (["num" := (31337 :: Int)] :: [FormParam]).

Associated type family complains about `pred :: T a -> Bool` with "NB: ‘T’ is a type function, and may not be injective"

This code:
{-# LANGUAGE TypeFamilies #-}
module Study where
class C a where
type T a :: *
pred :: T a -> Bool
— Gives this error:
.../Study.hs:7:5: error:
• Couldn't match type ‘T a’ with ‘T a0’
Expected type: T a -> Bool
Actual type: T a0 -> Bool
NB: ‘T’ is a type function, and may not be injective
The type variable ‘a0’ is ambiguous
• In the ambiguity check for ‘Study.pred’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
When checking the class method:
Study.pred :: forall a. A a => T a -> Bool
In the class declaration for ‘A’
|
7 | pred :: T a -> Bool
| ^^^^^^^^^^^^^^^^^^^
Replacing type keyword with data fixes.
Why is one wrong and the other correct?
What do they mean by "may not be injective"? What kind of function that is if it is not even allowed to be one to one? And how is this related to the type of pred?
instance C Int where
type T Int = ()
pred () = False
instance C Char where
type T Char = ()
pred () = True
So now you have two definitions of pred. Because a type family assigns just, well, type synonyms, these two definitions have the signatures
pred :: () -> Bool
and
pred :: () -> Bool
Hm, looks rather similar, doesn't it? The type checker has no way to tell them apart. What, then, is
pred ()
supposed to be? True or False?
To resolve this, you need some explicit way of providing the information of which instance the particular pred in some use case is supposed to belong to. One way to do that, as you've discovered yourself, is to change to an associated data family: data T Int = TInt and data T Char = TChar would be two distinguishable new types, rather than synonyms to types, which have no way to ensure they're actually different. I.e. data families are always injective; type families sometimes aren't. The compiler assumes, in the absence of other hints, that no type family is injective.
You can declare a type family injective with another language extension:
{-# LANGUAGE TypeFamilyDependencies #-}
class C a where
type T a = (r :: *) | r -> a
pred :: T a -> a
The = simply binds the result of T to a name so it is in scope for the injectivity annotation, r -> a, which reads like a functional dependency: the result of T is enough to determine the argument. The above instances are now illegal; type T Int = () and type T Char = () together violate injectivity. Just one by itself is admissible.
Alternatively, you can follow the compiler's hint; -XAllowAmbiguousTypes makes the original code compile. However, you will then need -XTypeApplications to resolve the instance at the use site:
pred #Int () == False
pred #Char () == True

Haskell/GHC: overlapping instances reported while context only allows a single one

Dear Haskell/GHC experts,
I don't really understand why GHC reports overlapping instances while only one is actually valid according the provided contexts. For instance, let's consider the following piece of code:
{-# LANGUAGE FlexibleInstances #-}
class C a where
foo :: a -> String
foo x = "OK"
instance C Bool
instance (C a) => C [a]
instance (C a) => C [(Char, a)]
main = print $ foo [('a', True)]
Compiling it gives:
Test.hs:13:16: error:
* Overlapping instances for C [(Char, Bool)]
arising from a use of `foo'
Matching instances:
instance C a => C [a] -- Defined at Test.hs:9:10
instance C a => C [(Char, a)] -- Defined at Test.hs:11:10
* In the second argument of `($)', namely `foo [('a', True)]'
In the expression: print $ foo [('a', True)]
In an equation for `main': main = print $ foo [('a', True)]
The point is that ('a', True) has type (Char, Bool) which is not an instance of C. Therefore, instance C a => C [a] is not applicable to the value [('a', True)].
Therefore, why does GHC consider it?
The question is really about understanding the behaviour of GHC, not about how to avoid the issue (e.g. using OverlappingInstances). Is it because contexts are not used when "resolving" a function call? And if so, why?
Thanks in advance!
My understanding (could be very wrong):
First, from the documentation:
When matching, GHC takes no account of the context of the instance
declaration (context1 etc). GHC's default behaviour is that exactly
one instance must match the constraint it is trying to resolve. It is fine for there to be a potential of overlap (by including both declarations (A) and (B), say); an error is only reported if a particular constraint matches more than one.
The -XOverlappingInstances flag instructs GHC to allow more than one
instance to match, provided there is a most specific one.
In your case, the type passed to foo is [(Char,Bool)]. This satisfies the generic [a] and the more specialised [(Char,a)]. In the absence of OverlappingInstances flag, the most specific match scenario does not apply, and an error is reported.
Now if you were to tweak your code slightly like so:
instance C Bool
instance (C a) => C [a]
instance (C a) => C (Char, a)
Then there would be no overlap, because a tuple is not a list.

Type inference with GADTs - a0 is untouchable

Lets say I have this program
{-# LANGUAGE GADTs #-}
data My a where
A :: Int -> My Int
B :: Char -> My Char
main :: IO ()
main = do
let x = undefined :: My a
case x of
A v -> print v
-- print x
compiles fine.
But when I comment in the print x, I get:
gadt.hs: line 13, column 12:
Couldn't match type ‘a0’ with ‘()’
‘a0’ is untouchable
inside the constraints (a1 ~ GHC.Types.Int)
bound by a pattern with constructor
Main.A :: GHC.Types.Int -> Main.My GHC.Types.Int,
in a case alternative
at /home/niklas/src/hs/gadt-binary.hs:13:5-7
Expected type: GHC.Types.IO a0
Actual type: GHC.Types.IO ()
In the expression: System.IO.print v
In a case alternative: Main.A v -> System.IO.print v
Why do I get this error in line 13 (A v -> print v) instead of only in the print x line?
I thought the first occurrence should determine the type.
Please enlighten me :)
Well, first note that this has nothing to do with the particular print x: you get the same error when ending main with e.g. putStrLn "done".
So the problem is indeed in the case block, namely in that only the last statement of a do is required to have the type of the do block's signature. The other statements merely have to be in the same monad, i.e. IO a0 rather than IO ().
Now, usually this a0 is inferred from the statement itself, so for instance you can write
do getLine
putStrLn "discarded input"
though getLine :: IO String rather than IO (). However, in your example the information print :: ... -> IO () comes from inside the case block, from a GADT match. And such GADT matches behave differently from other Haskell statements: basically, they don't let any type information escape its scope, because if the information came from the GADT constructor then it's not correct outside of the case.
In that particular example, it seems obvious enough that a0 ~ () has nothing at all to do with the a1 ~ Int from the GADT match, but in general, such a fact could only be proven if GHC traced for all type information where it came from. I don't know if that's even possible, it would certainly be more complicated than Haskell's Hindley-Milner system, which heavily relies on unifying type information, which essentially assumes that it doesn't matter where the information came from.
Therefore, GADT matches simply act as a rigid “type information diode”: the stuff inside can never be used to determine types on the outside, like that the case block as a whole should be IO ().
However, you can manually assert that, with the rather ugly
(case x of
A v -> print v
) :: IO ()
or by writing
() <- case x of
A v -> print v

haskell -- odd ambiguous type variable error message for code in "where" statement with TypeFamilies extension

Does anyone know why this code fails?
{-# LANGUAGE NoMonomorphismRestriction,
TypeFamilies #-}
module Test where
asExprTyp :: Expr γ =>
γ α
-> α
-> γ α
asExprTyp x _ = x
int = undefined :: Integer
class Expr γ where
a :: γ α
-- this works fine
b = a `asExprTyp` int
-- this fails
mcode = do
return ()
where b = a `asExprTyp` int
The error is as follows,
Test.hs:23:15:
Ambiguous type variable `γ0' in the constraint:
(Expr γ0) arising from a use of `a'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `asExprTyp', namely `a'
In the expression: a `asExprTyp` int
In an equation for `b': b = a `asExprTyp` int
Failed, modules loaded: none.
I don't see what ghc complains about either. I thought it might be because it's trying to give the local binding a monomorphic type, but adding NoMonoLocalBinds to the language pragma didn't change anything.
However, the code compiles as is with a recent HEAD (7.3.20111026), together with the fact that it compiles without TypeFamilies enabled, that supports the bug hypothesis.
If it's a real problem you have to solve: adding type signatures makes ghc happy.
Okay, this is somewhat over my head since I've never used type families in Haskell. However, your example isn't actually using type families either, so I thought I'd see what happens when I remove the TypeFamilies language extension from the LANGUAGE pragma. Turns out: it compiles just fine then! :)
So it could very well be a GHC bug.
That being said, I poked at it a bit and noticed that the following compiles happily with TypeFamilies enabled:
mcode = do
b
return ()
where b = a `asExprTyp` int
This is probably nonsensical, since its inferred type is mcode :: (Expr m, Monad m) => m (), rather than just mcode :: Monad m => m (), but my point is that GHC seems happy only when a's type is tied in some way to mcode's type.
Not sure if this is helpful, but it definitely piqued my curiosity!

Resources