Why doesn't the compiler resolve implicit constrained type variables inside a function? - haskell

Here's the code:
class Problem p where
readProblem :: String -> p
solveProblem :: p -> String
readAndSolve = solveProblem . readProblem
And this is the error message GHC yields:
Ambiguous type variable `b0' in the constraint:
(Problem b0) arising from a use of `readProblem'
Probable fix: add a type signature that fixes these type variable(s)
In the second argument of `(.)', namely `readProblem'
In the expression: solveProblem . readProblem
In an equation for `readAndSolve':
readAndSolve = solveProblem . readProblem
As I understand, I have to somehow tell the compiler that the Problem instance used by solveProblem and readProblem is the same type, but I see no way to declare that. And why can't it figure that by itself?

You need not tell the compiler that it has to be the same type, the compiler figures that out by itself. However, it can't figure out which type to use. The canonical famous example of the problem is
foo = show . read
If foo had a legal type, that would be
foo :: (Read a, Show a) => String -> String
Now, how could the compiler determine a?
Your readAndSolve would have the type
readAndSolve :: Problem p => String -> String

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]).

Haskell - Num vs Double, Int types [duplicate]

This question already has answers here:
`String' is applied to too many type arguments
(2 answers)
Closed 1 year ago.
Haskell noob here.
Im trying to make the following function and this error is extremely cryptic to me:
:{
myfunc::(Double a)=> a -> a -> a
myfunc a b = a + b
:}
and I get:
error:
• Expected kind ‘* -> Constraint’, but ‘Double’ has kind ‘*’
• In the type signature: myfunc :: (Double a) => a -> a -> a
The same goes for Int.
However, it I use Num type, I get no error:
:{
myfunc::(Num a)=> a -> a -> a
myfunc a b = a+b
:}
The same goes if I use just plain Int or Double without Double a
:{
myfunc::Double -> Double -> Double
myfunc a b = a+b
:}
My question:
How come is it, that I can use Num a, or just plan Double, Int, but I cannot use Double a, or Int a?
Regards.
First a terminology note: when GHC writes * here in the error messages, read it as Type, the kind of types†. It is for historical reasons that older versions of GHC write it with the asterisk symbol.
So, your error message is
• Expected kind ‘Type -> Constraint’, but ‘Double’ has kind ‘Type’
• In the type signature: myfunc :: (Double a) => a -> a -> a
Ok, ‘Double’ has kind ‘Type’ – that should make enough sense, right? Double is a type.
But why does it say it's “expecting” Type -> Constraint? Well, it means you tried to use Double as if it were of this kind. Namely, you wrote Double a. Here, a has to be a type, but you can't apply a type to another type, that would be like applying a character to a character on the value level:
Prelude> 'x' 'y'
<interactive>:1:1: error:
• Couldn't match expected type ‘Char -> t’ with actual type ‘Char’
• The function ‘'x'’ is applied to one argument,
but its type ‘Char’ has none
By contrast, Num is a type class, and as such it has in fact the correct kind:
Prelude> :k Num
Num :: Type -> Constraint
Constraint is the correct kind that's expected on the left of the =>, so that's why you can write
myfunc :: Num a => a -> a -> a
Again, Double is a type, not a type class, so it can't be used in this way. However, what you can use is an equality constraint:
{-# LANGUAGE TypeFamilies #-}
myfunc :: a~Double => a -> a -> a
myfunc = (+)
This is effectively the same as
myfunc :: Double -> Double -> Double
(there are some subtle differences with respect to typechecking).
Vice versa, it is not possible to write
myfunc :: Num -> Num -> Num
myfunc = (+)
error:
• Expecting one more argument to ‘Num’
Expected a type, but ‘Num’ has kind ‘Type -> Constraint’
• In the type signature: myfunc :: Num -> Num -> Num
†To be completely precise, Type is the kind of lifted types. Don't worry about what that means: unless you're doing very low-level stuff, you may never need to work with unlifted types.

Ad hoc polymorphic functions

I have some data that I'd like to print (some is Maybe and some is not), and I'm trying to create a generic showField function as follows:
showField :: (Show a) => a -> Text
showField x
| isJust x = Text.pack $ show $ fromJust x
| isNothing x = "None"
| otherwise = Text.pack $ show x
This is throwing a rigid type error:
• Couldn't match expected type ‘Maybe a0’ with actual type ‘a’
‘a’ is a rigid type variable bound by
the type signature for:
showField :: forall a. Show a => a -> Text
at /data/users/jkozyra/fbsource/fbcode/experimental/jkozyra/hs/holdout_cleanup/HoldoutReaper.hs:244:18
• In the first argument of ‘isNothing’, namely ‘x’
In the expression: isNothing x
In a stmt of a pattern guard for
an equation for ‘showField’:
isNothing x
I generally understand this error, but I don't understand if there's a way to achieve what I'd like to. I've also tried pattern matching rather than guards, but can't quite work that out either. Is there something that I could construct in this format that would work?
It looks like you're trying to construct an adhoc polymorphic function - a function whose definition varies according to its type.
A parametric polymorphic function does the same thing to all data types:
both :: a -> (a,a)
both a = (a,a)
In Haskell, adhoc polymorphism is implemented using type classes:
class ShowField a where
showField :: a -> Text
instance Show a => ShowField (Maybe a) where
showField Nothing = "None"
showField (Just a) = Text.pack $ show a
However there's no way to define an instance for "all other types other than Maybe a" with type classes, so you just have to define instances for the types you actually care about:
class ShowField Int where
showField = Text.pack . show
class ShowField Float where
showField = Text.pack . show
You can cut down on boilerplate by using -XDefaultSignatures:
class ShowField' a where
showField :: a -> Text
default showField :: Show a => a -> Text
showField = Text.pack . show
instance ShowField' Int where
instance ShowField' Float where
The error tells us:
‘a’ is a rigid type variable bound by
the type signature for:
showField :: forall a. Show a => a -> Text
Basically, this tells us that according to the type signature you provided, the type of the first parameter is forall a. Show a (the 'forall a.' bit is implied by the signature), which means that the first parameter can be any type that is an instance of Show. It is a rigid type variable because it is defined by an explicit type signature.
It also tells us:
Couldn't match expected type ‘Maybe a0’ with actual type ‘a’
By applying the functions isJust and isNothing — both of type Maybe a -> Bool — to the first parameter you are also claiming the type of the first parameter is Maybe a which is obviously not the same type as forall a. Show a => a -> Text.
You can turn this into a correct program simply by removing the type signature for showField, but that won't have the behavior you desire — the inferred type signature will be (Show a) => Maybe a -> Text which obviously only accepts values of Maybe a (where a is also an instance of Show).
In Haskell, you can't have a function that accepts values of both a and Maybe a¹. Without more context, it's unclear what your actual goal is, but there is almost certainly a more idiomatic way to achieve it.
¹ Unless you have a type class that has instances for both a and Maybe a.

What is a quick way to determine how many typed holes to give to a function?

Typed holes offer a great way of finding out how to implement something: if you know what function to use, say foo, you can just write out something like foo _ _ _ and let the compiler tell you what types it expects for each argument. This makes it largely unnecessary to look up any documentation.
However, it only works properly if you actually write out the correct number of underscores. At the moment, I usually determine this by some trial-and-error, but it's not always obvious what hints to look out for, because in Haskell functions can always be just partially applied.
What is a good way to find out this number as quickly as possible?
As #chi suggests, the best thing I've found is "apply the hole to the function". I don't know if this answers the question, but hopefully it is at least somewhat helpful.
I'm guessing that by "functions can always be just partially applied" you mean you can have such a function:
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
foldr = undefined
for which you can't tell just from the type how many arguments it should take in order to typecheck at any particular type. The best that the typechecker can do here is to tell you the minimum number of arguments it will accept:
bar :: String -> String
bar = _1 foldr
* Found hole:
_1 :: ((a0 -> b0 -> b0) -> b0 -> t0 a0 -> b0) -> String -> String
Where: `t0' is an ambiguous type variable
`b0' is an ambiguous type variable
`a0' is an ambiguous type variable
* In the expression: _
In the expression: _ foldr
In an equation for `bar': bar = _ foldr
* Ambiguous type variable `t0' arising from a use of `foldr'
prevents the constraint `(Foldable t0)' from being solved.
Probable fix: use a type annotation to specify what `t0' should be.
These potential instances exist:
instance Foldable (Either a) -- Defined in `Data.Foldable'
instance Foldable Maybe -- Defined in `Data.Foldable'
instance Foldable ((,) a) -- Defined in `Data.Foldable'
...plus one other
...plus 22 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
Aside: the second error isn't particularly helpful here, as t0 could really be any of those types. But if you find yourself in such a situation often, then -fprint-potential-instances may actually be useful.
You can now do a little bit of typechecking in your head:
((a0 -> b0 -> b0) -> b0 -> t0 a0 -> b0 ) ->
<_1> <_2> String -> String
for the types to match, you must supply at least two holes. You may need more, but that will depend on the instantiation of b0. Substituting in these holes, you get a pretty easy problem
bar :: String -> String
bar = foldr _1 _2
* Found hole: _1 :: Char -> String -> String
* Found hole: _2 :: String
You may even encounter a (in my opinion, silly) function like
class C a where foo :: a
instance C String where
instance C a => C (Int -> a) where
in which case you can do the same thing, and the typechecker helpfully notifies you of all the possible instances:
bar :: String -> String
bar = _ foo
test0.hs:6:7: warning: [-Wtyped-holes]
* Found hole: _ :: t0 -> String -> String
Where: `t0' is an ambiguous type variable
* In the expression: _
In the expression: _ foo
In an equation for `bar': bar = _ foo
* Relevant bindings include
bar :: String -> String (bound at test0.hs:6:1)
test0.hs:6:9: warning: [-Wdeferred-type-errors]
* Ambiguous type variable `t0' arising from a use of `foo'
prevents the constraint `(C t0)' from being solved.
Probable fix: use a type annotation to specify what `t0' should be.
These potential instances exist:
instance C a => C (Int -> a) -- Defined at test0.hs:3:10
instance C String -- Defined at test0.hs:2:10
* In the first argument of `_', namely `foo'
In the expression: _ foo
In an equation for `bar': bar = _ foo
Here you really have to guess. In this (admittedly contrived) example, I would probably guess you want one argument, because bar takes one argument.
bar :: String -> String
bar = foo . _
test0.hs:6:7: warning: [-Wdeferred-type-errors]
* Ambiguous type variable `b0' arising from a use of `foo'
prevents the constraint `(C (b0 -> String))' from being solved.
(maybe you haven't applied a function to enough arguments?)
Probable fix: use a type annotation to specify what `b0' should be.
These potential instance exist:
instance C a => C (Int -> a) -- Defined at test0.hs:3:10
test0.hs:6:13: warning: [-Wtyped-holes]
* Found hole: _ :: String -> b0
Where: `b0' is an ambiguous type variable
Now it tells you there is one potential instance, and so you can guess that the type of that hole really should be String -> Int.

Explicit type conversion?

This is an example function:
import qualified Data.ByteString.Lazy as LAZ
import qualified Data.ByteString.Lazy.Char8 as CHA
import Network.Wreq
makeRequest :: IO (Network.Wreq.Response LAZ.ByteString)
makeRequest = do
res <- get "http://www.example.com"
let resBody = res ^. responseBody :: CHA.ByteString
--Do stuff....
return (res)
I'm struggling to understand the exact purpose of CHA.ByteString in this line:
let resBody = res ^. responseBody :: CHA.ByteString
Is this explicitly stating the type must be CHA.ByteString? Or does it serve another role?
Yes, this is just explicitly stating that the type must be CHA.ByteString. This does (by itself) not incur any sort of conversion, it's just a hint for the compiler (and/or the reader) that res must have this type.
These kinds of local annotations are needed when a value is both produced from a function with polymorphic result, and only consumed by functions with polymorphic argument. A simple example:
f :: Int -> Int
f = fromEnum . toEnum
Here, toEnum converts an integer to a arbitrary enumerable type – could for instance be Char. Whatever type you'd choose, fromEnum would be able to convert it back... trouble is, there is no way to decide which type should be used for the intermediate result!
No instance for (Enum a0) arising from a use of ‘fromEnum’
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
instance Integral a => Enum (GHC.Real.Ratio a)
-- Defined in ‘GHC.Real’
instance Enum Ordering -- Defined in ‘GHC.Enum’
instance Enum Integer -- Defined in ‘GHC.Enum’
...plus 7 others
In the first argument of ‘(.)’, namely ‘fromEnum’
In the expression: fromEnum . toEnum
In an equation for ‘f’: f = fromEnum . toEnum
For some simple number classes, Haskell has defaults, so e.g. fromIntegral . round will automatically use Integer. But there are no defaults for types like ByteString, so with a polymorphic-result function like responseBody, you either need to pass the result to a monomorphic function that can only accept CHA.ByteString, or you need to add an explicit annotation that this should be the type.
The notation x :: T reads expression x has type T
This may be necessary in the presence of type classes and higher ranked types to enable the compiler to type check the program. For example:
main = print . show . read $ "1234"
is ambiguous, since the compiler cannot know which of the overloaded read functions to use.
In addition, it is possible to narrow the type the compiler would infer. Example:
1 :: Int
Finally, a type signature like this is often used to make the program more readable.

Resources