[英]Testing Number Theoretic Functions in Haskell using a recursor over natural numbers
我正在使用遞歸實現一些數論函數作為 Haskell 中的冪運算。 我正在使用 QuickCheck 庫來測試我的實現。 為了簡化我的測試,我使用基礎庫中的 Natural 數據類型、在 quickcheck-instances 庫中定義的 Natural 的任意實例以及以下函數分別從 Nat 轉換為 Natural 和從 Natural 轉換為 Nat,考慮到數據Nat由我自己定義:
data Nat = Zero | Succ Nat
natToNatural :: Nat -> Natural
natToNatural Zero = 0
natToNatural (Succ n) = 1 + natToNatural n
naturalToNat :: Natural -> Nat
naturalToNat 0 = Zero
naturalToNat n = Succ (naturalToNat (n - 1))
實現在自然數上使用以下遞歸:
recNat :: a -> (Nat -> a -> a) -> Nat -> a
recNat a _ Zero = a
recNat a h (Succ n) = h n (recNat a h n)
我的取冪的 function 是
expR :: Nat -> Nat -> Nat
expR m n = recNat (Succ Zero) (\ _ y -> multR m y) n
我使用 Natural 的冪來定義 prop_Exp 屬性
prop_Exp :: Natural -> Natural -> Bool
prop_Exp m n = natToNatural (expR m' n') == m ^ n
where
m' :: Nat
m' = naturalToNat m
n' :: Nat
n' = naturalToNat n
通過 QuickCheck 測試我對 expR function 的實現
main :: IO ()
main = quickCheck prop_expR
但是,運行此代碼后,我得到一個異常:
*** Exception: stack overflow
我想知道這段代碼有什么問題
正如chi所說, Nat
類型將數字表示為遞歸數據結構。 我認為它與[()]
同構,但我可能會誤會......
AFAICT,轉換函數以及recNat
都不是尾遞歸的,因此當使用10^10
之類的東西時,它們會為數十億個元素構建 thunk。 較大的數字會導致堆棧溢出,這並不奇怪。
您可以告訴 QuickCheck 限制生成的值的范圍。 choose
function 是該問題的通用解決方案,但 AFAICT Natural
沒有Random
實例。 相反,您也許可以使用chooseEnum
,因為Natural
確實有一個Enum
實例。
幾年前,我也以類似的方式涉足自然數(和相關的想法) 。 這是我寫的乘法屬性:
testProperty "Multiplication" $ do
x <- choose @Integer (0, 25)
y <- choose (0, 25)
return $ x * y === toNum (multiplyF (fromNum x) (fromNum y))
因為我使用了choose
,所以我沒有將我的 QuickCheck 屬性基於Natural
。 這使我能夠告訴 QuickCheck 只選擇大於0
的數字。 對於乘法,我必須將整數限制為小於25
,但對於其他屬性,我選擇了更大的范圍:
testProperty "Increment" $ do
i <- choose @Integer (0, 1e4)
return $ i + 1 === toNum (incF (fromNum i))
已經好幾年了,所以我不記得為什么我選擇了這些特定的數字。 當時我使用的是一台較舊的筆記本電腦,但我不記得更高的數字是否導致我的進程溢出,或者僅僅是測試運行得太慢。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.