Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange Haskell type error only happening when currying assertEqual

Tags:

haskell

This code will compile correctly:

import Text.Printf
import Test.HUnit
doubleMe x = x + x
doubleUs x y = doubleMe x + doubleMe y
doubleSmallNumber x = if x > 100 then x else x*2
doubleSmallNumber' x = if x > 100 then x else x*2 + 1
conanO'Brien = "It's a-me, Conan O'Brien!"
main = do
  runTestTT $ TestList [TestCase $ ae 4 $ doubleMe 2,
                        TestCase $ ae 10 $ doubleUs 2 3,
                        TestCase $ ae 4 $ doubleSmallNumber 2,
                        TestCase $ ae 1000 $ doubleSmallNumber' 1000,
                        TestCase $ assertEqual "" "It's a-me, Conan O'Brien!" conanO'Brien]
  where ae = assertEqual "" 

The output is:

$ clear && ghc baby.hs && ./baby     
[1 of 1] Compiling Main             ( baby.hs, baby.o )
Linking baby ...
ld: warning: could not create compact unwind for .LFB3: non-standard register 5 being saved in prolog
Cases: 5  Tried: 5  Errors: 0  Failures: 0

When I change the code to:

import Text.Printf
import Test.HUnit
doubleMe x = x + x
doubleUs x y = doubleMe x + doubleMe y
doubleSmallNumber x = if x > 100 then x else x*2
doubleSmallNumber' x = if x > 100 then x else x*2 + 1
conanO'Brien = "It's a-me, Conan O'Brien!"
main = do
  runTestTT $ TestList [TestCase $ ae 4 $ doubleMe 2,
                        TestCase $ ae 10 $ doubleUs 2 3,
                        TestCase $ ae 4 $ doubleSmallNumber 2,
                        TestCase $ ae 1000 $ doubleSmallNumber' 1000,
                        TestCase $ ae "It's a-me, Conan O'Brien!" conanO'Brien]
  where ae = assertEqual "" 

I get:

[1 of 1] Compiling Main             ( baby.hs, baby.o )

baby.hs:12:65:
    No instance for (Num [Char])
      arising from the literal `1000'
    Possible fix: add an instance declaration for (Num [Char])
    In the first argument of `doubleSmallNumber'', namely `1000'
    In the second argument of `($)', namely `doubleSmallNumber' 1000'
    In the second argument of `($)', namely
      `ae 1000 $ doubleSmallNumber' 1000'

I don't understand why.

Also does anybody have any ideas for fixing the ld warning:

ld: warning: could not create compact unwind for .LFB3: non-standard register 5 being saved in prolog
like image 582
Vanson Samuel Avatar asked Dec 01 '22 02:12

Vanson Samuel


1 Answers

This is an example of the monomorphism restriction. ae "looks like a value" (doesn't have arguments) and doesn't have an explicit type, so compiler won't infer a polymorphic type for it.

In first example, it gets type Int -> Int -> Assertion (I think).

In the second, from ae "It's a-me, Conan O'Brien!" conanO'Brien it gets the type String -> String -> Assertion. Remember that the type of integer literals is actually Num a => a, and 1000 gets type String from ae, so the compiler needs an instance Num String.

EDITED: This can be fixed by giving an explicit type annotation: where ae :: (Show a, Eq a) => a -> a -> Assertion = assertEqual "". Or by adding arguments to definition (eta-expanding it): where ae x y = assertEqual "" x y.

like image 103
Alexey Romanov Avatar answered Dec 04 '22 01:12

Alexey Romanov