views:

180

answers:

2

I'm getting a curious warning when pattern matching, but only when OverloadedStrings is enabled...

$ ghci -Wall
GHCi, version 6.12.1: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> let f x = case (x :: [String]) of {[""] -> "root"; ["product", _] -> "product"; _ -> "unknown"}
Prelude> :q
Leaving GHCi.
$ ghci -Wall -XOverloadedStrings
GHCi, version 6.12.1: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> let f x = case (x :: [String]) of {[""] -> "root"; ["product", _] -> "product"; _ -> "unknown"}

<interactive>:1:10:
    Warning: Pattern match(es) are overlapped
             In a case alternative: [""] -> ...
Prelude> let g x = case (x :: [String]) of {[] -> "root"; ["product", _] -> "product"; _ -> "unknown"}
Prelude> let h x = case (x :: [String]) of {["oops"] -> "root"; ["product", _] -> "product"; _ -> "unknown"}
Prelude> :q
Leaving GHCi.

I don't understand why I get the warning for f with OverloadedStrings, particularly since I don't get the warning for f without OverloadedStrings, and also don't get the warning for g or h, which differ from f only in the first pattern (which in all cases matches only a single particular value).

On the assumption that this is not a bug in GHC, what am I missing?

+2  A: 

EDIT: Basically you want this (after matching converting back from (IsString b) => b into [Char] but matching is done in consistent types):

f :: [String] -> String
f = matchf

matchf :: (Show b, IsString a, Eq a, IsString b) => [a] -> b
matchf x = case x of [""] -> "root"; ["product", _] -> "product"; _ -> "unknown"

Otherwise GHC warns about matching "" :: String to "" :: (Data.String.IsString t) => t (literal). It would be interesting to find out why (probably a bug?) given that literal "" properly defaults to String:

Prelude> show ("" :: (Data.String.IsString t) => t)

<interactive>:1:0:
    Warning: Defaulting the following constraint(s) to type `String'

Your string must be deriving Eq for pattern matching to work with -XOverloadedStrings. String is still just [Char] with -XOverloadedStrings but string literals are not.

Another way to do this without triggering a warning:

test.hs:

import GHC.Exts(IsString(..))

newtype OString = OString String deriving (Eq, Show)
instance IsString OString where fromString = OString

f :: [OString] -> OString
f x = case (x :: [OString]) of {[""] -> "root"; ["product", _] -> "product"; _ -> "unknown"}

Run it:

$ ghci -Wall -XOverloadedStrings
GHCi, version 6.12.1: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :l test.hs
[1 of 1] Compiling Main             ( test.hs, interpreted )
Ok, modules loaded: Main.
*Main> f []
OString "unknown"
*Main> f [""]
OString "root"
*Main> f ["product"]
OString "unknown"
*Main> f ["product", "x"]
OString "product"

Source: http://www.haskell.org/ghc/docs/6.12.2/html/users_guide/type-class-extensions.html#overloaded-strings

vls
I am pattern matching on ordinary `String` s though (in my real program, I need overloaded strings in a different part of my code), so it has already derived `Eq`. So, I don't see how this helps?
Dave Hinton
@Dave Hinton: it's trying to compare apples to oranges but GHC is unsure that it can convert oranges into apples safely prior to the comparison (specifically, it is having trouble with ""). While the function input is of type String, what you're comparing it to (string literals) have to be converted into Strings first.
vls
+4  A: 

Here's a slightly simpler example that shows the same issue in GHC 6.12.3:

f :: String -> Bool
f "" = True
f "a" = False

g :: String -> Bool
g "" = True
g "aa" = False

Only g gets the overlap warning with -XOverloadedStrings. I think this has to be a bug.

Travis Brown
Yes, this is quite clearly a bug. What's also odd is that removing the type signature of `g` (causing its type to be inferred as `(IsString t, Eq t) => t -> Bool`) makes the warning go away.
Reid Barton

related questions