我有如下代碼:
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
我寫了這個測驗,以確保該行為如我所期望的那樣作業:
我寫了這個測驗。
module FunctorsApplicativeFunctorsAndMonoidsSpec where
import Test.Hspec
import FunctorsApplicativeFunctorsAndMonoids
spec :: Spec ::.
spec = do
描述 "List" $ do
它 "應實作 combineLists" $ do
combineLists (Value 1 Empty) type">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
最后一個測驗失敗了,出現了以下錯誤:
。stack test
exercises> build (lib test)
Preprocessing library for exercises-0.1.0.0.
Building library for exercises-0.1.0.0.
Preprocessing測驗套件'exercices-test' for exercises-0.1.0.0。
Building test suite 'exercices-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:錯誤。
- Ambiguous type variable 'a0' arising from a use of 'shouldBe'
阻止約束'(Show a0)'被解決。
Probable修復:使用type注釋來指定'a0'應該是什么。
這些潛在的實體存在。
instance [safe] Show a => Show (List a)
--定義于'FunctorsApplicativeFunctorsAndMonoids'。
instance Show Ordering --定義于'GHC.Show'。
instance Show a => Show (Maybe a) --在'GHC.Show'中定義的。 顯示'
...加上其他24個
...加上50個涉及范圍外型別的實體
(使用 -fprint-potential-instances) title">物質 to see them all)
- 在一個'do'塊的stmt。
combineLists Empty Empty `shouldBe` Empty
在'($)'的第二個引數,即
'做 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'
在一個'do'塊的stmt。
它 "應該實作 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
-- 在構建package exercises-0.1.0.0(滾動到它的部分可以看到錯誤)時,使用:
/Users/jerred/.asdf/installs/haskell/9.0.1/stack/setup-ex-cache/x86_64-osx/Cabal-imple_mPHDZzAJ_3.4.0_ghc-9. 0.1 --builddir=.stack-work/dist/x86_64-osx/Cabal-3.4.0.0 build lib:exercices test:exercices-test --ghc-options " -fdiagnostics-color=always"
Process退出了,代碼為。ExitFailure 1
我有點不明白為什么會發生這個錯誤。是不是因為List型別建構式需要一個a引數,但是因為Empty沒有,所以出現了錯誤?為什么其他的測驗都能如期進行呢?
uj5u.com熱心網友回復:
是的,這是因為List有一個引數,而Empty沒有足夠的資訊來計算出這個引數是什么。
我們有以下型別:
combineLists :: List a -> List a -> List a
shouldBe :: a -> a -> SomethingLMAO --因此:
shouldBe :: List a -> List a -> SomethingLMAO。
這些型別加在一起,意味著在一個形式為
的術語中combineLists x y `shouldBe` z
我們知道x、y和z中的三個都將是具有相同元素型別的串列。這意味著,如果這三個中的任何一個有足夠的資訊來確定一個元素型別,那么其他的元素型別也是已知的。但是在你這個有問題的例子中......
combineLists Empty Empty `shouldBe` Empty<
三者都沒有任何元素,因此,元素型別就不確定了!
在你繼續研究的程序中,你可能還會注意到一些褶皺。"默認 "有時被允許默默地消除一些含糊不清的型別,而那些不受型別類別約束的型別首先就不會被視為含糊不清。你是想現在就查看Report/GHC手冊來了解所有的細節,還是等到它出現的時候再去了解,我就不說了。
uj5u.com熱心網友回復:
shouldBe的型別簽名是這樣的:
shouldBe :: (HasCallStack, Show a, Eq a) => a -> a -> Expectation
因此,shouldBe的任何引數必須是Showable。
GHC的(可以說是很長的)錯誤資訊告訴我們問題所在:
GHC的錯誤資訊告訴我們問題所在。
Ambiguous type variable 'a0' arising from a use of 'shouldBe'
阻止約束'(Show a0)'被解決。
...
|
17 | combineLists Empty Empty `shouldBe` Empty !
| ^^^^^^^^^^
盡管我們必須使用垂直滑塊才能看到你問題文本中的基本行號。
現在,Empty是否可以顯示?空的型別是List a,對于某些型別的a,但哪一個?不,編譯器不會從上面的源行中獲取線索。
因此,如果你手動將Empty的型別強制為合理的型別,代碼就能正常作業。
combineLists Empty Empty `shouldBe` (Empty : : List Integer)
正如Daniel的精彩回答中提到的,最右邊的運算元的型別會傳播到shouldBe的另一邊。這就是為什么其他3個測驗不會引起任何問題的原因。
自給自足的測驗。
源代碼的自足編譯版本:
importTest.Hspec
import Test.Hspec.Expectations
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
spec :: Spec Spec
spec = do
描述 "List" $ do
它 "應實作 combineLists" $ do
combineLists (Value 1 Empty) type">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 : : List Integer)
main:: IO ()
main = do
putStrLn $ "Hello impure world!"
補遺:面向表的方法
如上所述,編譯器不能在各種檢查之間傳播型別資訊。但是如果我們把測驗安排成((operand1, operand2), result)圖元的list,型別資訊就可以傳播,因為在Haskell串列中,所有元素都需要有相同的型別。此外,這將預期結果的串列與檢查它們的機制分開。像這樣:
spec2 :: Spec Spec
spec2 =
let truthTable =
[
( (Value 1 Empty, Value 2 Empty) , Value 1 (Value 2 Empty) )
, ( (Empty, Empty) , Empty )
, ( (Empty, Value 1 Empty) , Value 1 Empty )
, ( (Value 1 Empty, Empty) , Value 1 Empty )
]
checkFn = ((op1, op2), result) -> shouldBe ( combineLists op1 op2) result
checks = sequence_ (map checkFn truthTable)
在中
do
描述 "List" $ do
它 "應該實作 combineLists" $ 檢查
在這里,整數字面1和2受益于Haskell implicit default clause。因此,編譯器可以理解每個人都必須是List Integer型別,包括Empty項。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/316939.html
標籤:
上一篇:TypeError:'numpy.float64'型別的物件在列印資料幀中第一列的回歸系數時沒有len()
下一篇:如何獲取連接組件的最大值和坐標?
