为什么我从GHCi收到这个警告?

8

当启用OverloadedStrings时,我在模式匹配时收到一个奇怪的警告...

$ 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.

我不理解为什么在使用OverloadedStrings时会针对f发出警告,特别是因为在没有使用OverloadedStrings时我没有收到关于f的警告,并且对于gh也没有警告,它们与f的唯一区别在于第一个模式(在所有情况下只匹配单个特定值)。

假设这不是GHC中的错误,那我可能遗漏了什么?


是否可能对 "" 进行重载,使得 [""] 等同于 [_] - Gabe
不,它匹配的方式就像是[""]而不是[_] - dave4420
你在 GHC 7.0 上测试过这个吗? - Thomas M. DuBuisson
我不知道有 GHC 7.0!GHC 主页列出的最新版本是 6.12.3。我应该从哪里下载它? - dave4420
7.0版本目前处于RC阶段。如果你不太熟悉Haskell/GHC,也许应该等待官方发布。我只是好奇是否尝试过,因为类型检查器已经进行了全面改进。 - Thomas M. DuBuisson
2个回答

5

这里是一个稍微简单一点的例子,展示了在 GHC 6.12.3 中出现的同样问题:

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

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

只有g在使用-XOverloadedStrings时才会收到重叠警告。我认为这必须是一个错误。


是的,这很明显是一个 bug。另外奇怪的是,如果移除 g 的类型签名(导致其类型被推断为 (IsString t, Eq t) => t -> Bool),警告就会消失。 - Reid Barton

2

编辑:基本上您需要这样做(在匹配后将(IsString b)=> b转换回 [Char] ,但匹配是以一致的类型进行的):

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"

否则,GHC会警告将"" :: String"" :: (Data.String.IsString t) => t(字面值)进行匹配。有趣的是要找出为什么(可能是一个 bug?),因为字面值""应该正确地默认为String。
Prelude> show ("" :: (Data.String.IsString t) => t)

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

要使用-XOverloadedStrings进行模式匹配,您的字符串必须派生自Eq。虽然使用-XOverloadedStrings时字符串仍然只是[Char],但字符串字面值不是。

另一种在不触发警告的情况下执行此操作的方法:

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"}

运行它:

$ 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"

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

本文介绍了haskell中的过载字符串类型类扩展。它允许程序员使用字符串字面量而不必显式地将它们转换为特定的字符串类型,这对于编写字符串处理相关的代码非常有用。在使用此扩展时,编译器会自动选择适当的字符串类型,并将该字符串解释为所需类型的值。然后,该值可以像任何其他值一样使用。

我正在普通的String上进行模式匹配(在我的真实程序中,我需要在代码的另一部分中使用重载字符串),因此它已经派生了Eq。所以,我不明白这有什么帮助? - dave4420
1
@Dave Hinton:这就像是在比较苹果和橙子,但 GHC 不确定在比较之前是否能够安全地将橙子转换为苹果(具体来说,它在处理“”时遇到了问题)。虽然函数输入的类型是字符串,但你要比较的内容(字符串字面量)必须先转换为字符串。 - vls

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接