我有以下代码:
module FunctorsApplicativeFunctorsAndMonoids(List(..), combineLists) where
data List a = Empty | Value a (List a) deriving (Eq, Show)
combineLists:: List a -> List a -> List a
combineLists (Value a rest) b = Value a (combineLists rest b)
combineLists Empty b = b
Run Code Online (Sandbox Code Playgroud)
我编写了此测试以确保行为按我的预期工作:
module FunctorsApplicativeFunctorsAndMonoidsSpec where
import Test.Hspec
import FunctorsApplicativeFunctorsAndMonoids
spec :: Spec
spec = do
describe "List" $ do
it "should implement combineLists" $ do
combineLists (Value 1 Empty) (Value 2 Empty) `shouldBe` (Value 1 (Value 2 Empty))
combineLists Empty (Value 1 Empty) `shouldBe` (Value 1 Empty)
combineLists (Value 1 Empty) Empty `shouldBe` (Value 1 Empty)
combineLists Empty Empty `shouldBe` Empty
Run Code Online (Sandbox Code Playgroud)
最后一次测试失败并出现以下错误:
stack test
exercises> build (lib + test)
Preprocessing library for exercises-0.1.0.0..
Building library for exercises-0.1.0.0..
Preprocessing test suite 'exercises-test' for exercises-0.1.0.0..
Building test suite 'exercises-test' for exercises-0.1.0.0..
[10 of 11] Compiling FunctorsApplicativeFunctorsAndMonoidsSpec
/Users/jerred/git/learn-you-a-haskell-exercises/test/FunctorsApplicativeFunctorsAndMonoidsSpec.hs:17:32: error:
• Ambiguous type variable ‘a0’ arising from a use of ‘shouldBe’
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 [safe] Show a => Show (List a)
-- Defined in ‘FunctorsApplicativeFunctorsAndMonoids’
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
...plus 24 others
...plus 50 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In a stmt of a 'do' block:
combineLists Empty Empty `shouldBe` Empty
In the second argument of ‘($)’, namely
‘do combineLists (Value 1 Empty) (Value 2 Empty)
`shouldBe` (Value 1 (Value 2 Empty))
combineLists Empty (Value 1 Empty) `shouldBe` (Value 1 Empty)
combineLists (Value 1 Empty) Empty `shouldBe` (Value 1 Empty)
combineLists Empty Empty `shouldBe` Empty’
In a stmt of a 'do' block:
it "should implement combineLists"
$ do combineLists (Value 1 Empty) (Value 2 Empty)
`shouldBe` (Value 1 (Value 2 Empty))
combineLists Empty (Value 1 Empty) `shouldBe` (Value 1 Empty)
combineLists (Value 1 Empty) Empty `shouldBe` (Value 1 Empty)
combineLists Empty Empty `shouldBe` Empty
|
17 | combineLists Empty Empty `shouldBe` Empty
| ^^^^^^^^^^
Progress 1/2
-- While building package exercises-0.1.0.0 (scroll up to its section to see the error) using:
/Users/jerred/.asdf/installs/haskell/9.0.1/stack/setup-exe-cache/x86_64-osx/Cabal-simple_mPHDZzAJ_3.4.0.0_ghc-9.0.1 --builddir=.stack-work/dist/x86_64-osx/Cabal-3.4.0.0 build lib:exercises test:exercises-test --ghc-options " -fdiagnostics-color=always"
Process exited with code: ExitFailure 1
Run Code Online (Sandbox Code Playgroud)
我对为什么会发生此错误感到有些困惑。是不是因为List类型构造函数接受了一个a参数,但因为Empty没有而发生错误?为什么其他测试按预期工作?
是的,这是因为List有一个论点并且Empty没有足够的信息来确定该论点是什么。
我们有以下类型:
combineLists :: List a -> List a -> List a
shouldBe :: a -> a -> SomethingLMAO -- and therefore:
shouldBe :: List a -> List a -> SomethingLMAO
Run Code Online (Sandbox Code Playgroud)
总之,这些类型意味着在形式上
combineLists x y `shouldBe` z
Run Code Online (Sandbox Code Playgroud)
我们知道x, y, 和 的所有三个都是z具有相同元素类型的列表。这意味着如果三者中的任何一个有足够的信息来确定元素类型,那么其他元素也知道元素类型。但在你有问题的例子中......
combineLists Empty Empty `shouldBe` Empty
Run Code Online (Sandbox Code Playgroud)
三者都没有任何元素,因此元素类型是不确定的!
在继续学习的过程中,您可能会注意到更多的问题:“默认”有时被允许以静默方式消除一些歧义类型,而不受类型类约束的类型从一开始就不会被认为是歧义的。无论您是想立即查看报告/GHC 手册以了解所有详细信息,还是等到它出现时,我都会由您决定。