哈斯克尔。匹配模式问题。无法输入空列表函数的 IO 值
print $ note1 []
Run Code Online (Sandbox Code Playgroud)
无法编译,但在 ghci 中工作正常?!另外,print $ note1 [1]工作正常,编译罚款了。只有空列表的问题:
print $ note1 []
Run Code Online (Sandbox Code Playgroud)
(注意我是 Haskell 的新手)我有一个匹配的模式函数
note1 :: (Show a) => [a] -> String
note1 [] = "Empty"
note1 (x:[]) = "One"
Run Code Online (Sandbox Code Playgroud)
但print $ note1 []无法编译,但在 ghci 解释器中完美运行?!
我在 MacOS 上使用 stack 2.3.1 和 ghc 8.8.3。
这是编译器产生的编译错误。
/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 []
Run Code Online (Sandbox Code Playgroud)
问题是(在这种情况下是不必要的)对 的Show a约束note1。这就是发生的事情。当 GHC 进行类型检查时print $ note1 [],它需要确定与哪个 Show实例一起使用note1。这通常是从它传递的列表中元素的类型推断出来的。但是它传递的列表......没有任何元素。所以 typechecker 没有特定的方法来选择一个实例,只是放弃了。这在 GHCi 中起作用的原因是 GHCi 默认启用ExtendedDefaultRules语言扩展,它扩展了类型默认规则。因此,类型检查器不会举手,而是选择()列表元素的类型,一切正常。当您使用时,会发生类似的事情[1]. 在这种情况下,标准的默认规则开始发挥作用:数字类型默认为Integer,因此类型检查器会选择该类型。
你应该如何解决这个问题?你可以手动写
print $ note1 ([] :: [()])
Run Code Online (Sandbox Code Playgroud)
使您的代码编译,但如果那是您的真实代码,则最好删除不必要的约束:
note1 :: [a] -> String
note1 [] = "Empty"
note1 (x:[]) = "One"
Run Code Online (Sandbox Code Playgroud)
附带说明一下,由于您不使用x变量,因此最好通过使用特殊_模式来明确说明这一事实:
note1 :: [a] -> String
note1 [] = "Empty"
note1 (_:[]) = "One"
Run Code Online (Sandbox Code Playgroud)
或用下划线作为变量名的前缀:
note1 :: [a] -> String
note1 [] = "Empty"
note1 (_x:[]) = "One"
Run Code Online (Sandbox Code Playgroud)
这表明,对于其他程序员(例如几个小时后的您自己)和编译器,您故意不使用该值。
此外,您可以(并且可能应该)使用列表语法来阐明第二种模式:
note1 [_] = "One"
Run Code Online (Sandbox Code Playgroud)
最后,该note1函数有一点问题:如果您向它传递一个包含多个元素的列表,它将产生模式匹配失败。哎呀!如果可以,通常最好编写完整的函数。如果不能,通常最好使用显式error调用来指示出了什么问题。我建议使用-Wall标志编译您的代码以帮助捕获错误。