有時我有一組測驗,我想在一堆不同的型別上運行。這是我通常如何執行此操作的一個簡單示例:
import Test.Framework (Test)
import Test.Framework.Providers.QuickCheck2 (testProperty)
import Test.QuickCheck
additionCommutes :: (Eq a, Num a) => a -> a -> Bool
additionCommutes x y = x y == y x
divisionByItselfIsOne :: (Eq a, Ord a, Fractional a) => a -> Property
divisionByItselfIsOne x = x > 0 ==> x / x == 1
-- pretend rounding errors won't occur, this is just an example
floatTests :: [Test]
floatTests = [
testProperty "float addition commutes"
(additionCommutes :: Float -> Float -> Bool),
testProperty "float divided by itself is 1"
(divisionByItselfIsOne :: Float -> Property)
]
doubleTests :: [Test]
doubleTests = [
testProperty "double addition commutes"
(additionCommutes :: Double -> Double -> Bool),
testProperty "double divided by itself is 1"
(divisionByItselfIsOne :: Double -> Property)
]
但我寧愿避免重復列出每種型別的測驗。(可能涉及很多測驗。)我想定義一次測驗串列,然后為每種型別實體化它。像這樣的東西...
numberTests :: (Eq a, Ord a, Num a, Fractional a) => [Test] for the type "a"
numberTests = [
testProperty "double addition commutes"
(additionCommutes :: a -> a -> Bool),
testProperty "double divided by itself is 1"
(divisionByItselfIsOne :: a -> Property)
]
floatTests = numberTests :: [Test] for the type "float"
doubleTests = numberTests :: [Test] for the type "double"
當然,這不是有效的 Haskell。我感覺可能有一些神奇的型別級編程技術可以用來完成此任務。我瀏覽了 Maguire 的 Thinking With Types,但我仍然不知道如何解決這個問題。有什么建議么?
如果有一種技術在原則上可行,但不能很好地與 QuickCheck 的反射功能配合使用,那很好——我更感興趣的是建立我的型別級編程技能,而不是解決這個特定問題。
uj5u.com熱心網友回復:
你很接近:
{-# Language AllowAmbiguousTypes #-}
{-# Language ScopedTypeVariables #-}
{-# Language TypeApplications #-}
-- vvvvvvvvv
numberTests :: forall a. (Eq a, Ord a, Num a, Fractional a) => [Test]
numberTests = -- just like in the question
-- vvvvvvv
floatTests = numberTests @Float
doubleTests = numberTests @Double
您甚至不需要專門命名floatTestsand doubleTests; 你可以寫一些像
allTests = numberTests @Float numberTests @Double
如果你愿意。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/487894.html
標籤:哈斯克尔
上一篇:如何在servant-websocket的管道端點中使用你自己的Monad?
下一篇:構建lib時cabal安裝出錯
