Explain monomorphism restriction to me please? - haskell

I started doing 99 haskell problems and I was on problem 7 and my unittests were blowing up.
Apparently, it's due to this: http://www.haskell.org/haskellwiki/Monomorphism_restriction
I just wanted to make sure I understood this correctly because I'm kinda confused.
situation 1: func a is defined with no type def or with a non-strict type def and then used once, the compiler has no issues infering the type at compile time.
situation 2: the same func a is used many times in the program, the compiler can't be 100% sure what the type is unless it recomputes the function for the given arguments.
To avoid the computation loss, ghc complains to the programmer that it needs a strict type def on a
to work correctly.
I think in my situation, assertEqual has the type def of
assertEqual :: (Eq a, Show a) => String -> a -> a -> Assertion
I was getting an error when test3 was defined that I interpreted as saying that it had 2 possible types for the return of testcase3 (Show and Eq) and didn't know how to continue.
Does that sound correct or am I completely off?
problem7.hs:
-- # Problem 7
-- Flatten a nested list structure.
import Test.HUnit
-- Solution
data NestedList a = Elem a | List [NestedList a]
flatten :: NestedList a -> [a]
flatten (Elem x) = [x]
flatten (List x) = concatMap flatten x
-- Tests
testcase1 = flatten (Elem 5)
assertion1 = [5]
testcase2 = flatten (List [Elem 1, List [Elem 2, List [Elem 3, Elem 4], Elem 5]])
assertion2 = [1,2,3,4,5]
-- This explodes
-- testcase3 = flatten (List [])
-- so does this:
-- testcase3' = flatten (List []) :: Eq a => [a]
-- this does not
testcase3'' = flatten (List []) :: Num a => [a]
-- type def based off `:t assertEqual`
assertEmptyList :: (Eq a, Show a) => String -> [a] -> Assertion
assertEmptyList str xs = assertEqual str xs []
test1 = TestCase $ assertEqual "" testcase1 assertion1
test2 = TestCase $ assertEqual "" testcase2 assertion2
test3 = TestCase $ assertEmptyList "" testcase3''
tests = TestList [test1, test2, test3]
-- Main
main = runTestTT tests
1st situation: testcase3 = flatten (List [])
GHCi, version 7.4.2: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Main ( problem7.hs, interpreted )
problem7.hs:29:20:
Ambiguous type variable `a0' in the constraints:
(Eq a0)
arising from a use of `assertEmptyList' at problem7.hs:29:20-34
(Show a0)
arising from a use of `assertEmptyList' at problem7.hs:29:20-34
Probable fix: add a type signature that fixes these type variable(s)
In the second argument of `($)', namely
`assertEmptyList "" testcase3'
In the expression: TestCase $ assertEmptyList "" testcase3
In an equation for `test3':
test3 = TestCase $ assertEmptyList "" testcase3
Failed, modules loaded: none.
Prelude>
2nd situation: testcase3 = flatten (List []) :: Eq a => [a]
GHCi, version 7.4.2: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Main ( problem7.hs, interpreted )
problem7.hs:22:13:
Ambiguous type variable `a0' in the constraints:
(Eq a0)
arising from an expression type signature at problem7.hs:22:13-44
(Show a0)
arising from a use of `assertEmptyList' at problem7.hs:29:20-34
Possible cause: the monomorphism restriction applied to the following:
testcase3 :: [a0] (bound at problem7.hs:22:1)
Probable fix: give these definition(s) an explicit type signature
or use -XNoMonomorphismRestriction
In the expression: flatten (List []) :: Eq a => [a]
In an equation for `testcase3':
testcase3 = flatten (List []) :: Eq a => [a]
Failed, modules loaded: none.

It's not so much the monomorphism restriction, it's the resolution of ambiguous type variables by defaulting that causes the compilation failure.
-- This explodes
-- testcase3 = flatten (List [])
-- so does this:
-- testcase3' = flatten (List []) :: Eq a => [a]
-- this does not
testcase3'' = flatten (List []) :: Num a => [a]
flatten :: NestedList a -> [a]
flatten (Elem x) = [x]
flatten (List x) = concatMap flatten x
flatten imposes no constraints on the type variable a, so there's no problem with the definition of testcase3 as such, it would be polymorphic.
But when you use it in test3,
test3 = TestCase $ assertEmptyList "" testcase3 -- ''
you inherit the constraints of
assertEmptyList :: (Eq a, Show a) => String -> [a] -> Assertion
Now the compiler has to find out at which type testcase3 should be used there. There is not enough context to determine the type, so the compiler tries to resolve the type variable by defaulting. According to the defaulting rules, a context (Eq a, Show a) cannot be resolved by defaulting, since only contexts involving at least one numeric class are eligible for defaulting. So compilation fails due to an ambiguous type variable.
testcase3' and testcase3'' however fall under the monomorphism restriction due to the expression type signature which imposes constraints on the right hand side of the definition that are inherited by the left.
testcase3' fails to compile due to that, regardless of whether it is used in an assertion.
testcase3'' gets defaulted to [Integer] since the expression type signature imposes a numeric constraint. Thus when the type is monomorphised for testcase'', the constrained type variable is defaulted to Integer. Then there is no question of the type at which it is used in test3.
If you had given type signatures to the bindings instead of to the right hand side,
testcase3' :: Eq a => [a]
testcase3' = flatten (List [])
testcase3'' :: Num a => [a]
testcase3'' = flatten (List [])
both values would have compiled on their own to polymorphic values, but still only testcase3'' would be usable in test3, since only that introduces the required numeric constraint to allow defaulting.

Related

why does quickCheck create lists of units

I tried the following from the paper QuickCheck Testing for fun and profit.
prop_revApp xs ys = reverse (xs ++ ys) == reverse xs ++ reverse ys
and it passed even though it should not have.
I ran verboseCheck and I see that it is only checking lists of units, i.e.:
Passed:
[(),(),(),(),(),(),(),(),(),(),(),(),(),()]
I was wondering why this was.
I am aware I can fix it by defining the type of the property but was wondering if this was necessary or I was missing something.
The prop_revApp function is quite generic:
*Main> :t prop_revApp
prop_revApp :: Eq a => [a] -> [a] -> Bool
If you're just loading the code in GHCi, and run it, yes, indeed, the property passes:
*Main> quickCheck prop_revApp
+++ OK, passed 100 tests.
This is because GHCi comes with a set of preferred defaults. For convenience, it'll try to use the simplest type it can.
It doesn't get much simpler than (), and since () has an Eq instance, it picks that.
If, on the other hand, you actually try to write and compile some properties, the code doesn't compile:
import Test.Framework (defaultMain, testGroup)
import Test.Framework.Providers.QuickCheck2 (testProperty)
import Test.QuickCheck
main :: IO ()
main = defaultMain tests
prop_revApp xs ys = reverse (xs ++ ys) == reverse xs ++ reverse ys
tests = [
testGroup "Example" [
testProperty "prop_revApp" prop_revApp
]
]
If you try to run these tests with stack test, you'll get a compiler error:
test\Spec.hs:11:17: error:
* Ambiguous type variable `a0' arising from a use of `testProperty'
prevents the constraint `(Arbitrary a0)' from being solved.
Probable fix: use a type annotation to specify what `a0' should be.
These potential instances exist:
instance (Arbitrary a, Arbitrary b) => Arbitrary (Either a b)
-- Defined in `Test.QuickCheck.Arbitrary'
instance Arbitrary Ordering
-- Defined in `Test.QuickCheck.Arbitrary'
instance Arbitrary Integer
-- Defined in `Test.QuickCheck.Arbitrary'
...plus 19 others
...plus 61 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
* In the expression: testProperty "prop_revApp" prop_revApp
In the second argument of `testGroup', namely
`[testProperty "prop_revApp" prop_revApp]'
In the expression:
testGroup "Example" [testProperty "prop_revApp" prop_revApp]
|
11 | testProperty "prop_revApp" prop_revApp
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You'll have to give the property a more specific type; e.g.
tests = [
testGroup "Example" [
testProperty "prop_revApp" (prop_revApp :: [Int] -> [Int] -> Bool)
]
]
Now the test compiles, but fails:
$ stack test
Q56101904-0.1.0.0: test (suite: Q56101904-test)
Example:
prop_revApp: [Failed]
*** Failed! Falsifiable (after 3 tests and 3 shrinks):
[1]
[0]
(used seed -7398729956129639050)
Properties Total
Passed 0 0
Failed 1 1
Total 1 1
Q56101904-0.1.0.0: Test suite Q56101904-test failed
Test suite failure for package Q56101904-0.1.0.0
Q56101904-test: exited with: ExitFailure 1
Logs printed to console

Ambiguous type variable in a test for empty list

Consider the following snippet which defines a function foo which takes in a list and performs some operation on the list (like sorting).
I tried to load the snippet in ghci:
-- a function which consumes lists and produces lists
foo :: Ord a => [a] -> [a]
foo [] = []
foo (x:xs) = xs
test1 = foo [1, 2, 3] == [2, 3]
test2 = null $ foo []
yet the following error occurs:
No instance for (Ord a0) arising from a use of ‘foo’
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
instance (Ord a, Ord b) => Ord (Either a b)
-- Defined in ‘Data.Either’
instance forall (k :: BOX) (s :: k). Ord (Data.Proxy.Proxy s)
-- Defined in ‘Data.Proxy’
instance (GHC.Arr.Ix i, Ord e) => Ord (GHC.Arr.Array i e)
-- Defined in ‘GHC.Arr’
...plus 26 others
In the second argument of ‘($)’, namely ‘foo []’
In the expression: null $ foo []
In an equation for ‘test2’: test2 = null $ foo []
The problem is in the expression test2 = null $ foo []. Furthermore, removing Ord a constraint from the type definition of foo will solve the problem. Strangely, typing null $ foo [] in the interactive mode (after loading the definition for foo) works correctly and produces the expected true.
I need a clear explanation for this behaviour.
I like thinking of typeclasses in "dictionary-passing style". The signature
foo :: Ord a => [a] -> [a]
says that foo takes a dictionary of methods for Ord a, essentially as a parameter, and a list of as, and gives back a list of as. The dictionary has things in it like (<) :: a -> a -> Bool and its cousins. When we call foo, we need to supply such a dictionary. This is done implicitly by the compiler. So
foo [1,2,3]
will use the Ord Integer dictionary, because we know that a is Integer.
However, in foo [], the list could be a list of anything -- there is no information to determine the type. But we still need to find the Ord dictionary to pass to foo (although your foo doesn't use it at all, the signature says that it could, and that's all that matters). That's why there is an ambiguous type error. You can specify the type manually, which will give enough information to fill in the dictionary, like this
null (foo ([] :: [Integer]))
or with the new TypeApplications extension
null (foo #Integer [])
If you remove the Ord constraint, it works, as you have observed, and this is just because we no longer need to supply a dictionary. We don't need to know what specific type a is to call foo anymore (this feels a little magical to me :-).
Note that foo ([] :: Ord a => [a]) does not eliminate the ambiguity, because it is not known which specific Ord dictionary you want to pass; is it Ord Int or Ord (Maybe String), etc.? There is no generic Ord dictionary, so we have to choose, and there is no rule for what type to choose in this case. Whereas when you say (Ord a, Num a) => [a], then defaulting specifies a way to choose, and we pick Integer, since it is a special case of the Num class.
The fact that foo [] works in ghci is due to ghci’s extended defaulting rules. It might be worth reading about type defaulting in general, which is surely not the prettiest part of Haskell, but it is going to come up a lot in the kinds of corner cases you are asking about.

Write Quick Sort in Haskell and need help to resolve the issue

I try to write a quick sort in Haskell and I knew there are many versions out there.
This one is pretty simple for Int type
quickSort1::[Int]->[Int]
quickSort1 [] = []
quickSort1 (x:xs) = [l | l <- xs, l < x] ++ [x] ++ [ r | r <- xs, r > x]
I can print on Main as following
print $ quickSort1 [] -- output []
print $ quickSort1 [2, 1] -- output [1, 2]
I modified the above quickSort1 to "more general" type with (Ord a) instead of Int
quickSort2::(Ord a)=>[a]->Maybe [a]
quickSort2 [] = Nothing
quickSort2 (x:xs) = Just $ [ l | l <- xs, l < x] ++ [x] ++ [ r | r <- xs, r > x]
On my Main, I can run
it works
print $ quickSort2 [2, 1] -- output [1, 2]
I got compiler error when I run following
print $ quickSort2 [] -- got error
Can anyone explain to me what is going on with my new version of quickSort2
I assume you use a file foo.hs and in it
main = print $ quicksort []
quicksort = ... - as defined above in quickSort2
then you get two error messages when you runghc foo.hs
foo.hs:3:8: error:
• Ambiguous type variable ‘a0’ arising from a use of ‘print’
prevents the constraint ‘(Show a0)’ from being solved.
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show Integer -- Defined in ‘GHC.Show’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
...plus 22 others
...plus 11 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the expression: print $ quicksort []
In an equation for ‘main’: main = print $ quicksort []
one telling you that ghc cannot tell what Show instance to use and ghc 8 already tells you how to solve this:
add a type annotation (as #duplode already suggested)
main = print $ quicksort ([] :: [Int])
Quite similar but slightly different is the second error message
foo.hs:3:16: error:
• Ambiguous type variable ‘a0’ arising from a use of ‘quicksort’
prevents the constraint ‘(Ord a0)’ from being solved.
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Ord Ordering -- Defined in ‘GHC.Classes’
instance Ord Integer
-- Defined in ‘integer-gmp-1.0.0.1:GHC.Integer.Type’
instance Ord a => Ord (Maybe a) -- Defined in ‘GHC.Base’
...plus 22 others
...plus five instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the second argument of ‘($)’, namely ‘quicksort []’
In the expression: print $ quicksort []
In an equation for ‘main’: main = print $ quicksort []
Where in the first message the print function demanded a Show instance - here you promised the quicksort to supply a list of orderables - but did not say which to use, so GHC complains about what Ord to use.
Both messages are due to the fact that [] is too polymorphic it could be a list of anything - [Int] is good, but it could also be something like [Int -> Bool] which is neither Showable nor Orderable.
You could as well supply quicksort with something weird like a
newtype HiddenInt = HI Int deriving (Ord) --but not Show
which would work for the quicksort function but not for print.
Side Note
Your quicksort functions need to be recursive in order to really be correct - as I pointed out in my comments - there is a logical problem in your algorithm - be sure to test your functions properly e.g.
import Data.List (sort)
main :: IO ()
main = do print $ "quicksort [10,9..1] == Just (sort [10,9..1]) is: "
++ show $ quicksort ([10,9..1]::Int]) == Just (sort ([10,9..1]::Int]))
print $ "quicksort [5,5,5] == Just (sort [5,5,5]) is: "
++ show $ quicksort ([5,5,5] :: [Int]) == Just (sort ([5,5,5] :: [Int]))
quicksort :: (Ord a) => [a] -> Maybe [a]
quicksort = ...
or if you are interested take a look at QuickCheck - which is a bit more advanced, but a step in the right direction for verifying your algorithms/functions work the way you expect them.

No instance for (Show a0) arising from a use of `print' The type variable `a0' is ambiguous

data NestedList a = Elem a | List [NestedList a]
flatten :: NestedList a -> [a]
flatten (Elem element) = [element]
flatten (List []) = []
flatten (List (first:rest)) = flatten first ++ flatten (List (rest))
main = print $ flatten $ List []
I wrote the above seen code in haskell. When I execute this with any other parameter, for example
main = print $ flatten $ List [Elem 1, Elem 2]
main = print $ flatten $ Elem 1
It gives
[1, 2]
[1]
respectively.
It fails when I execute it with an empty List.
main = print $ flatten $ List []
Error message
No instance for (Show a0) arising from a use of `print'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Show Double -- Defined in `GHC.Float'
instance Show Float -- Defined in `GHC.Float'
instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
...plus 23 others
In the expression: print
In the expression: print $ flatten $ List []
In an equation for `main': main = print $ flatten $ List []
Questions
Why does it fail and how can I fix this?
Should I change my NestedList definition to accept an empty List? If so, how do I do that. Its quite confusing.
The list type is polymorphic. Since you don't supply an element, just the empty list constructor [], there's no way to infer what list type this is.
Is it: [] :: [Int]
or [] :: [Maybe (Either String Double)]. Who's to say?
You are. Supply a type annotation to resolve the polymorphism, then GHC can dispatch to the correct show instance.
E.g.
main = print $ flatten $ List ([] :: [Int])
To add to the answers here already, you may object "but what does it matter what type of things my list contains? it doesn't have any of them in it!"
Well, first of all, it is easy to construct situations in which it's unclear whether or not the list is empty, and anyway type checking hates to look at values, it only wants to look at types. This keeps things simpler, because it means that when it comes to deal with values, you can be sure you already know all the types.
Second of all, it actually does matter what kind of list it is, even if it's empty:
ghci> print ([] :: [Int])
[]
ghci> print ([] :: [Char])
""
The problem is the compiler can't know the type of flatten $ List []. Try to figure out the type yourself, you'll see it's [a] for some a, whilst print requires its argument to be an instance of Show, and [a] is an instance of Show if a is an instance of Show. Even though your list is empty, so there's no need for any constraint on a to represent [], there's no way for the compiler to know.
As such, putting an explicit type annotation (for any type for which an instance of Show exists) should work:
main = print $ flatten $ List ([] :: [NestedList Int])
or
main = print $ flatten $ List ([] :: [NestedList ()])
or
main = print fl
where
fl :: [()]
fl = flatten $ List []
[] can be a list of floats, strings, booleans or actually any type at all. Thus, print does not know which instance of show to use.
Do as the error message says and give an explicit type, as in ([] :: [Int]).

Reflection on inputs to a function in Haskell?

I have a reflective situation where I want to display the types of inputs/outputs of a function. I could just add it to a separate data structure, but then I have duplication and would have to make sure they stay in sync manually.
For example, a function:
myFunc :: (String, MyType, Double) -> (Int, SomeType TypeP, MyOtherType a)
and so now I want to have something like (can be somewhat flexible, esp. when params involved):
input = ["String", "MyType", "Double"]
output = ["Int", "SomeType TypeP", "MyOtherType a"]
defined automatically. It doesn't have to be Strings directly. Is there a simple way to do this?
You don't really need a custom parser. You can just reflect on the TypeRep value you receive. For instance the following would work:
module ModuleReflect where
import Data.Typeable
import Control.Arrow
foo :: (Int, Bool, String) -> String -> String
foo = undefined
-- | We first want to in the case that no result is returned from splitTyConApp
-- to just return the input type, this. If we find an arrow constructor (->)
-- we want to get the start of the list and then recurse on the tail if any.
-- if we get anything else, like [] Char then we want to return the original type
-- [Char]
values :: Typeable a => a -> [TypeRep]
values x = split (typeOf x)
where split t = case first tyConString (splitTyConApp t) of
(_ , []) -> [t]
("->", [x]) -> [x]
("->", x) -> let current = init x
next = last x
in current ++ split next
(_ , _) -> [t]
inputs :: Typeable a => a -> [TypeRep]
inputs x = case values x of
(x:xs) | not (null xs) -> x : init xs
_ -> []
output :: Typeable a => a -> TypeRep
output x = last $ values x
and a sample session
Ok, modules loaded: ModuleReflect.
*ModuleReflect Data.Function> values foo
[(Int,Bool,[Char]),[Char],[Char]]
*ModuleReflect Data.Function> output foo
[Char]
*ModuleReflect Data.Function> inputs foo
[(Int,Bool,[Char]),[Char]]
This is just some quick barely tested code, I'm sure it can be cleaned up. And the reason I don't use typeRepArgs is that in the case of other constructors they would be broken up to, e.g [] Char returns Char instead of [Char].
This version does not treat elements of tuples as seperate results, but it can be easily changed to add that.
However as mentioned before this has a limitation, It'll only work on monomorphic types. If you want to be able to find this for any type, then you should probably use the GHC api. You can load the module, ask it to Typecheck and then inspect the Typecheck AST for the function and thus find it's type. Or you can use Hint to ask for the type of a function. and parse that.
Have a look at Data.Typeable: It defined a functiontypeOf :: Typeable a => a -> TypeRep, TypeRep is instance of Show. For example:
$ ghci
GHCi, version 6.12.1: http://www.haskell.org/ghc/ :? for help
:m Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :m +Data.Typeable
Prelude Data.Typeable> :i TypeRep
data TypeRep
= Data.Typeable.TypeRep !Data.Typeable.Key TyCon [TypeRep]
-- Defined in Data.Typeable
instance [overlap ok] Eq TypeRep -- Defined in Data.Typeable
instance [overlap ok] Show TypeRep -- Defined in Data.Typeable
instance [overlap ok] Typeable TypeRep -- Defined in Data.Typeable
Prelude Data.Typeable> typeOf (+)
Integer -> Integer -> Integer
Prelude Data.Typeable> typeOf (\(a,(_:x),1) -> (a :: (),x :: [()]))
((),[()],Integer) -> ((),[()])
Now, you only need a custom parser that translated this output into something suitable for you. This is left as an exercise to the reader.
PS: There seems to be one limitation: All types must be known before, for instance typeOf id will fail.

Resources