当前位置: 首页 > 知识库问答 >
问题:

用自然数上的递归子检验Haskell中的数论函数

陈嘉荣
2023-03-14

我用递归函数在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)

我的幂函数是

expR :: Nat -> Nat -> Nat
expR m n = recNat (Succ Zero) (\ _ y -> multR m y) n
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
main :: IO ()
main = quickCheck prop_expR
*** Exception: stack overflow

共有1个答案

籍英叡
2023-03-14

正如chi所说,NAT类型将数字表示为递归数据结构。我认为它与[()]同构,但我可能错了······

当然,转换函数和recnat都不是尾部递归的,所以当使用10^10这样的东西时,它们将为数十亿个元素建立thunk。从较大的数字中得到堆栈溢出并不奇怪。

您可以告诉QuickCheck限制生成的值的范围。choose函数是该问题的通用解决方案,但是AFAICTnatural没有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))
testProperty "Increment" $ do
  i <- choose @Integer (0, 1e4)
  return $ i + 1 === toNum (incF (fromNum i))
 类似资料:
  • 我们从右到左都知道并爱/恨作文: 什么是自然/从左到右组合的“最标准”操作符(如在某种公共库中):

  • 作为一个Haskell新手,我不明白为什么表达式抛出异常和函数组合必须与运算符一起应用-它右边的表达式不需要进一步计算,因为它只是一个。编译它的另一种方法是将在括号中,但是与,那么为什么把它放在括号中可以编译表达式呢?

  • 考虑Python中的这个基本递归: 根据斐波那契数列的(n-1)(n-2)函数,这是有道理的。 Python如何执行包含另一个递归的递归,这个递归不在同一代码行内,而是在同一代码行内?“finobacci(number-1)”是否完成所有递归,直到它到达“1”,然后它对“fibonacci(number-2)”做同样的事情,并将它们相加? 作为比较,下面的递归函数将一个数“x”提升为“y”的幂,我

  • 我正在从事一个基于C中自定义数据结构list\t的项目。这是可以帮助我操作这个list\t的预定义函数,我被要求编写的函数叫做insert\u list(list\u t,list\u t,int),它是尾部递归的。 我要编写的insert_list()函数接受两个输入,类型为list_t和一个保证不大于第一个list_t大小的额外整数n,并返回另一个list_t,其中包含第一个list_t中的前

  • 这个递归编码是错误的还是仅仅是那个控制台。即使执行递归,log()也不总是被执行? 在控制台中执行testrecursion不会返回任何错误。 信息控制台日志显示 再次执行测试递归会在信息控制台日志中显示这一点。 第三次执行testrecursion会在信息控制台日志中显示这一点。 在对此进行了数十次测试后,递归步骤似乎偶尔被调用。输出似乎是随机的。预期输出为 这是否看起来像递归正确发生,只是控制

  • 我有一个家庭作业问题,它给出了一个递归函数,我必须使用尾部递归来实现它。函数为f(0)=1 f(n)=1 2*f(n-1) 我并不擅长尾部递归,我试着查找示例,但我发现的都是没有斐波那契序列的示例,这没有多大帮助。 我真正拥有的是 我知道尾递归基本上每次调用都计算函数,我只是不知道如何实现它。 编辑:我打了一个错字f(n)应该是1 2*f(n-1)