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

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.

Related

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.

Testing empty list [] with Eq type

Currently, I am writing a function in Haskell to check a list is symmetric or not.
isReflexive :: Eq a => [(a, a)] -> Bool
isReflexive [] = True
isReflexive xs = and [elem (x, x) xs | x <- [fst u | u <- xs] ++ [snd u | u <- xs]]
test = do
print(isReflexive [])
main = test
The function works fine on the list that is not empty. However, when I test the empty list with the function, it raised an error
Ambiguous type variable ‘a2’ arising from a use of ‘isReflexive’ prevents the constraint ‘(Eq a2)’ from being solved.
Probable fix: use a type annotation to specify what ‘a2’ should be.
These potential instances exist:
instance Eq Ordering -- Defined in ‘GHC.Classes’
instance Eq Integer -- Defined in ‘integer-gmp-1.0.2.0:GHC.Integer.Type’
instance Eq a => Eq (Maybe a) -- Defined in ‘GHC.Maybe’
...plus 22 others
...plus 7 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the first argument of ‘print’, namely ‘(isReflexive [])’
How to fix this error?
The problem is simply that, in order to apply isReflexive, GHC needs to know which type you are using it on.
The type signature of isReflexive - Eq a => [(a, a)] -> Bool doesn't tell GHC a concrete type that the function works on. That's perfectly fine, and usual, but most often the code that calls the function makes it clear what exactly a is in that particular application. That's not so here, because [] has itself a polymorphic (and therefore ambiguous) type, [a] (for any a).
To fix it you simply have to provide a concrete type for your [] here, which is consistent with the signature of isReflexive. It really doesn't matter what, but an example from many that will work is:
test = do
print(isReflexive ([] :: [(Int, Int)]))
(Note that this is exactly what GHC is telling you when it says Probable fix: use a type annotation to specify what 'a2' should be. 'a2' in that message corresponds to 'a' here, GHC tends to use 'a1', 'a2' etc to refer to all type variables.)

How to write getters for existential types in Haskell

Thanks to the answer to this question I've defined a type like so:
data Chain = forall a. Integral a => Chain [[a]] [a] a a
I need to write a getter function for each field, or argument if you like. Here's my first attempt:
getSimplices (Chain simplices _ _ _) = simplices
But when I try to compile ghc gives the following error:
Chain.hs:10:40: error:
• Couldn't match expected type ‘t’ with actual type ‘[[a]]’
because type variable ‘a’ would escape its scope
This (rigid, skolem) type variable is bound by
a pattern with constructor:
Chain :: forall a. Integral a => [[a]] -> [a] -> a -> a -> Chain,
in an equation for ‘getSimplices’
at Chain.hs:10:15-35
• In the expression: simplices
In an equation for ‘getSimplices’:
getSimplices (Chain simplices _ _ _) = simplices
• Relevant bindings include
simplices :: [[a]] (bound at Chain.hs:10:21)
getSimplices :: Chain -> t (bound at Chain.hs:10:1)
I fixed it like this:
getSimplices (Chain simplices _ _ _) = map (map fromIntegral) simplices
Even if some kind of ghc magic prevents this from being obscenely slow for a getter, I think fixing something this way is just atrocious. Is there a better way to define getters for types like this?
The constructor of an existential type necessarily "forgets" about a:
Chain :: Integral a => [[a]] -> [[a]] -> a -> a -> Chain
Note how the resulting type no longer depends on a.
A consequence of this is that, when we pattern match on Chain, we can not make any assumption about what a is. After all we could have chosen anything when constructing. The only knowledge we have on a is that it must be an integral type. Hence, we can only access using the methods of the Integral type class.
The general rule is that, when we pattern match on Chain, we must return a value of a type which does not depend on a. A getter like
getter (Chain _ _ x _) = x
violate that rule. After all, what type would that have?
getter :: Chain -> ???
Surely not
getter :: Chain -> a
which would instead mean that we can extract any type we wish from Chain. This can not realistically work: we can't be free to choose what type to put in, and then be also free to choose what type to take out.
What we can do, however, is to exploit Integral:
getter :: Chain -> Integer
getter (Chain _ _ x _) = fromIntegral x
Integer does not depend on a, so it is OK.
What type do you suppose getSimplices should have? The "obvious" choice is
getSimplices :: Integral a => Chain -> [[a]]
But this doesn't work with your implementation, because the caller of getSimplices gets to choose the a, and there's no guarantee that the values stored in the Chain are of the same type that the caller wants, since you threw that information away. Consider:
let c = Chain [[1 :: Int]] [2] 3 4
in (getSimplices c) :: [[Integer]]
This is clearly allowed by your two type signatures which promise to work for any Integral type, but also clearly cannot work without some conversion: the Ints have to be turned into Integers somehow.
As the comments say, this is rather unusual. It would be much simpler to add a type parameter to Chain, so that it tracks the type you used to create it, and constrains its output to that type as well:
data Chain a = Chain [[a]] [a] a a
getSimplices :: Chain a -> [[a]]
getSimplices (Chain xs _ _ _) = xs

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.

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

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

Resources