Question about List Type Constraint and Null

Hi all, The following function gives me an "Ambiguous type variable `a' in the constraint: `Read a' arising from a use of `res'" error: test :: Read a => String -> Maybe [(a,String)] test s = if null res then Nothing else Just $ fst $ head res where res = reads s The reason as 'jmcarthur' so patiently explained on IRC is that 'res' is used twice and the type constraint 'a' is different for each use, hence the ambiguity. I get that. But I have a further question why should 'null ...' care about the type of its list argument? Isn't it polymorphic? So it shouldn't make a difference that the 'a' inside res is ambiguous because we know for sure that it always returns a list of some kind. Thanks, -deech

On 22/01/11 06:03, aditya siram wrote:
Hi all, The following function gives me an "Ambiguous type variable `a' in the constraint: `Read a' arising from a use of `res'" error: test :: Read a => String -> Maybe [(a,String)] test s = if null res then Nothing else Just $ fst $ head res where res = reads s
This code doesn't give me that error, in fact it gives me no error at all. /M -- Magnus Therning OpenPGP: 0xAB4DFBA4 email: magnus@therning.org jabber: magnus@therning.org twitter: magthe http://therning.org/magnus

Ok I've figured out why I can't compile it. But now I'm more confused
than ever. The problem was that I have a -XNoMonomorphismRestriction
flag on Ghci. Removing this allowed me to compile.
But why?
-deech
On Sat, Jan 22, 2011 at 2:07 AM, Magnus Therning
On 22/01/11 06:03, aditya siram wrote:
Hi all, The following function gives me an "Ambiguous type variable `a' in the constraint: `Read a' arising from a use of `res'" error: test :: Read a => String -> Maybe [(a,String)] test s = if null res then Nothing else Just $ fst $ head res where res = reads s
This code doesn't give me that error, in fact it gives me no error at all.
/M
-- Magnus Therning OpenPGP: 0xAB4DFBA4 email: magnus@therning.org jabber: magnus@therning.org twitter: magthe http://therning.org/magnus
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

El sáb, 22-01-2011 a las 11:06 -0600, aditya siram escribió:
Ok I've figured out why I can't compile it. But now I'm more confused than ever. The problem was that I have a -XNoMonomorphismRestriction flag on Ghci. Removing this allowed me to compile.
This is indeed a bit tricky, it seems. res has a type-class polymorphic type Read a => ... (the ... is complicated by the fact that you have given a strange signature to test, see below) With the monomorphism restriction on, ghc takes the type-signature for test, inferes a type for res in the line Just $ fst $ head res, and uses this type for the null res test. Interestingly, it doesn't infer a monomorphic type for res, but insists that the instantiation for the type-class parameter is the same in both occurences. With no monomorphism restriction, ghc doesn't do this inference, because the type for res in null res may be different to the type of res in Just $ fst $ head res. (i.e., the instantion for the type-class parameter may be different) Finally, are you sure that the given type signature is what you want? Don't you want test :: Read a => String -> Maybe a Jürgen

Finally, are you sure that the given type signature is what you want? Don't you want
test :: Read a => String -> Maybe a
Yes that was a mistake, but the weirder thing is that fixing the type sig does nothing to change the behavior described before: it still fails to compile with -XNoMonomorphismRestriction and compiles fine if it's removed. It's going to take me a while understand absorb your explanation. Thanks! -deech
Jürgen
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

On Saturday 22 January 2011 20:01:19, aditya siram wrote:
Yes that was a mistake, but the weirder thing is that fixing the type sig does nothing to change the behavior described before: it still fails to compile with -XNoMonomorphismRestriction and compiles fine if it's removed.
It's going to take me a while understand absorb your explanation.
Perhaps the following will help understanding it: module ReadStuff where test :: String -> Maybe Int test s = if null res then Nothing else Just $ fst $ head res where res = reads s Prelude> :l ReadStuff [1 of 1] Compiling ReadStuff ( ReadStuff.hs, interpreted ) ReadStuff.hs:4:18: Ambiguous type variable `a' in the constraint: (Read a) arising from a use of `res' Probable fix: add a type signature that fixes these type variable(s) In the first argument of `null', namely `res' In the expression: null res In the expression: if null res then Nothing else Just $ fst $ head res Failed, modules loaded: none. The inferred type for res is res :: Read a => [(a,String)] with an implicit (forall a.). The value of `null res' for a given String obviously depends on the type at which res is used. To make test work, the type of res to use there has to be determined somehow. The natural way is to force res in line 4 to have the same type as res in line 7, where the type is determined by the signature of test (you could also write `null (res :: [(Bool,String)])' in line 4, but that would lead to *** Exception: Prelude.head: empty list for some inputs). Turning the monomorphism restriction off says explicitly 'let res be a polymorphic value', so you get the ambiguous type variable in line 4. The monomorphism restriction says 'don't generalise the type of res [there's no type signature on res, so it's in a restricted binding group]'. So you get `res :: Read b => [(b,String)]' for some so far unknown, but monomorphic b. The use of res in line 7 determines b (here Int, in general the same type that instantiates the `a' in test's signature).

The value of `null res' for a given String obviously depends on the type at which res is used. Why does it matter what the type of res is as long as it is some kind of list? Doesn't 'reads' always gives [(a1,String)]? So why does it matter what type 'a1' is?
Thanks for the clear explanation of the monomorphism restriction. -deech

On Saturday 22 January 2011 23:11:07, aditya siram wrote:
The value of `null res' for a given String obviously depends on the type at which res is used.
Why does it matter what the type of res is as long as it is some kind of list? Doesn't 'reads' always gives [(a1,String)]? So why does it matter what type 'a1' is?
Because reads "True, that" :: [(Bool,String)] ~> [(True,", that")] and reads "True, that" :: [(Int,String)] ~> [] So to evaluate `null res', the type of res must be known/fixed. If it isn't, the compiler has two choices. It can refuse to compile or it can compile and let the runtime throw an error "Can't evaluate because I don't know the type" (I think the second option isn't available for GHC). In my opinion, the first option is preferable.
Thanks for the clear explanation of the monomorphism restriction. -deech

Wow, 'reads' is a weird function. Thanks a bunch for the explanation.
-deech
On Sat, Jan 22, 2011 at 4:26 PM, Daniel Fischer
On Saturday 22 January 2011 23:11:07, aditya siram wrote:
The value of `null res' for a given String obviously depends on the type at which res is used.
Why does it matter what the type of res is as long as it is some kind of list? Doesn't 'reads' always gives [(a1,String)]? So why does it matter what type 'a1' is?
Because
reads "True, that" :: [(Bool,String)] ~> [(True,", that")]
and
reads "True, that" :: [(Int,String)] ~> []
So to evaluate `null res', the type of res must be known/fixed. If it isn't, the compiler has two choices. It can refuse to compile or it can compile and let the runtime throw an error "Can't evaluate because I don't know the type" (I think the second option isn't available for GHC). In my opinion, the first option is preferable.
Thanks for the clear explanation of the monomorphism restriction. -deech

On Saturday 22 January 2011 19:45:40, Jürgen Doser wrote:
El sáb, 22-01-2011 a las 11:06 -0600, aditya siram escribió:
Ok I've figured out why I can't compile it. But now I'm more confused than ever. The problem was that I have a -XNoMonomorphismRestriction flag on Ghci. Removing this allowed me to compile.
This is indeed a bit tricky, it seems. res has a type-class polymorphic type Read a => ... (the ... is complicated by the fact that you have given a strange signature to test, see below)
With the monomorphism restriction on, ghc takes the type-signature for test, inferes a type for res in the line Just $ fst $ head res, and uses this type for the null res test. Interestingly, it doesn't infer a monomorphic type for res, but insists that the instantiation for the type-class parameter is the same in both occurences.
With no monomorphism restriction, ghc doesn't do this inference, because the type for res in null res may be different to the type of res in Just $ fst $ head res. (i.e., the instantion for the type-class parameter may be different)
You can however make ghc consider res a monomorphic value even with the MR turned off by a) turning on MonoLocalBinds b) turning on ScopedTypeVariables, bringing a into scope (via forall a) and giving res a type signature involving that a or you can avoid all these problems by using the nicer code test s = case reads s of [] -> Nothing ((x,_):_) -> Just x
Finally, are you sure that the given type signature is what you want? Don't you want
test :: Read a => String -> Maybe a
Jürgen

Good afternoon, I have HUGS installed on my MAC OSX... Can you please give me some guidance to installing GHCI on the same MAC OSX? I need to keep both HUGS and GHCI on the MAC. Thank you

Have you tried the instructions for the Haskell Platform? From what I
understands it includes GHC (which usually includes GHCi) and various
Haskell libraries:
http://hackage.haskell.org/platform/mac.html
Antoine
On Sat, Jan 22, 2011 at 4:45 PM, patricklynch
Good afternoon, I have HUGS installed on my MAC OSX... Can you please give me some guidance to installing GHCI on the same MAC OSX? I need to keep both HUGS and GHCI on the MAC. Thank you
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

deech,
Shouldn't the type of test be "test :: Read a => String -> Maybe a" ?
Also, specifying the expected return type will make the error go away in ghci:
*Main> test "42"
<interactive>:1:0:
Ambiguous type variable `a' in the constraint:
`Read a' arising from a use of `test' at <interactive>:1:0-8
Probable fix: add a type signature that fixes these type variable(s)
*Main> test "42" :: Maybe Int
Just 42
Or else ghci has no context to determine what you are trying to
"read". Is this how you were trying out your code?
Patrick
On Sat, Jan 22, 2011 at 1:03 AM, aditya siram
Hi all, The following function gives me an "Ambiguous type variable `a' in the constraint: `Read a' arising from a use of `res'" error: test :: Read a => String -> Maybe [(a,String)] test s = if null res then Nothing else Just $ fst $ head res where res = reads s
The reason as 'jmcarthur' so patiently explained on IRC is that 'res' is used twice and the type constraint 'a' is different for each use, hence the ambiguity. I get that.
But I have a further question why should 'null ...' care about the type of its list argument? Isn't it polymorphic? So it shouldn't make a difference that the 'a' inside res is ambiguous because we know for sure that it always returns a list of some kind.
Thanks, -deech
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
-- ===================== Patrick LeBoutillier Rosemère, Québec, Canada

El sáb, 22-01-2011 a las 00:03 -0600, aditya siram escribió:
But I have a further question why should 'null ...' care about the type of its list argument? Isn't it polymorphic? So it shouldn't make a difference that the 'a' inside res is ambiguous because we know for sure that it always returns a list of some kind.
The point is that for different types for res, the list has a different number of elements. So without saying what the type of res is, you cannot know if the list is empty or not. Jürgen
participants (7)
-
aditya siram
-
Antoine Latter
-
Daniel Fischer
-
Jürgen Doser
-
Magnus Therning
-
Patrick LeBoutillier
-
patricklynch