1
votes

Haskell. Matching pattern Problem. Cannot put in IO value of function with empty list

print $ note1 []

failing to compile, but works fine in ghci ?! Also the print $ note1 [1] works fine and compiles fine too. The problem only with empty list:

print $ note1 []

(N.B. I am new in Haskell) I have a matching pattern function

note1          :: (Show a) => [a] -> String
note1 []       = "Empty"
note1 (x:[])   = "One"

But print $ note1 [] fails to compile, but perfectly works in ghci interpreter?!

I am using stack 2.3.1 and ghc 8.8.3 on MacOS.

This is the compilation error produced by compiler.

    /Users/admin1/Haskell/PROJECTS/orig1/src/Lib.hs:18:13: error:
    • Ambiguous type variable ‘a0’ arising from a use of ‘note1’
      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 15 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the second argument of ‘($)’, namely ‘note1 []’
      In a stmt of a 'do' block: print $ note1 []
      In the expression:
        do putStrLn "someFunc"
           putStrLn $ show (1)
           putStrLn $ show $ length ("a" :: String)
           putStrLn $ show (length' "a")
           ....   |
18 |     print $ note1 []
1

1 Answers

7
votes

The problem is the (unnecessary, in this case) Show a constraint on note1. Here's what happens. When GHC is typechecking print $ note1 [], it needs to work out which Show instance to use with note1. That's typically inferred from the type of elements in the list that it's passed. But the list it's passed ... doesn't have any elements. So the typechecker has no particular way to choose an instance, and just gives up. The reason this works in GHCi is that GHCi, by default, enables the ExtendedDefaultRules language extension, which expands the type defaulting rules. So instead of throwing up its hands, the type checker picks the type () for elements of the list, and everything works. Something sort of similar is going on when you use [1]. In that case, the standard defaulting rule comes into play: numeric types default to Integer, so the typechecker picks that type.

How should you fix this? You could manually write

print $ note1 ([] :: [()])

to make your code compile, but if that's your real code, you'd be much better off removing the unnecessary constraint:

note1          :: [a] -> String
note1 []       = "Empty"
note1 (x:[])   = "One"

As a side note, since you don't use the x variable, it's best to make that fact explicit by either using the special _ pattern:

note1          :: [a] -> String
note1 []       = "Empty"
note1 (_:[])   = "One"

or prefixing the variable name with an underscore:

note1          :: [a] -> String
note1 []       = "Empty"
note1 (_x:[])   = "One"

This indicates, both to other programmers (such as yourself a few hours later) and the compiler, that you are intentionally not using that value.

Additionally, you can (and probably should) use list syntax to clarify the second pattern:

note1 [_] = "One"

Finally, the note1 function has a bit of a problem: if you pass it a list with more than one element, it'll produce a pattern match failure. Whoops! It's usually better to write total functions when you can. When you can't, it's generally best to use an explicit error call to indicate what went wrong. I recommend compiling your code with the -Wall flag to help catch mistakes.