簡體   English   中英

使用自然數上的遞歸測試 Haskell 中的數論函數

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM