计算Haskell中的递归次数

时间:2019-01-16 16:29:15

标签: loops haskell recursion counting

我正在Haskell编写一个小型学校作业,以确定两个给定日期之间的距离。我写了一个粗略的函数来循环日期,但是我无法用函数式编程的方式来编写循环。我之前只做过程序和OOP编程。我不知何故需要存储有关我调用nextDate函数多少次的信息,但是Haskell不允许我在函数内部引入变量。这是到目前为止我提出的代码。完全不是Haskelly ...

nextDate year month day = 
    if day + 1 < 31
        then (year,month, day+1)
    else if month + 1 < 12
        then (year, month + 1, 1)
    else (year +1,1,1)

calculateDifference year month day year2 month2 day2 = 
    let x = 0
    if year == year2 && month == month2 && day == day2 then x
    else 
     nextDate(year, month, day)
     x = x + 1

    -- How I would do it in Python
    -- x = 0
    -- while((tuple1) != (year2, month2, day2)):
    --  x += 1
    --  tuple1 = nextDate(tuple1)
    -- print(x)

1 个答案:

答案 0 :(得分:2)

如果要跟踪调用该函数的次数,则需要提供该输入作为输入。没有其他方法可以执行此操作,因为Haskell仅允许您使用传递给函数的参数。

例如,假设我想计算一个阶乘,但我想跟踪它采取了多少步骤。我的函数签名看起来像这样:

factorial :: Int -> (Int, Int) -- Takes a number, returns the number and recursion count
factorialInternal :: (Int, Int) -> (Int, Int) -- This actually does the recursion

,然后定义如下所示:

factorial n = factorialInternal (n, 0)
factorialInternal (1, n) = (1, n + 1)
factorialInternal (x, n) = let (y, z) = factorialInternal (x-1, n) in (x * y, z + 1)

本质上,跟踪递归量的参数在每个级别上都会增加,然后成为factorial输出的一部分。

它肯定有助于创建接口函数,这样您在使用函数时就不必手动输入起始递归级别(无论如何始终为零)。函数签名的示例如下:

-- The function you call
calculateDifference :: (Int, Int, Int) -> (Int, Int, Int) -> Int
-- What the calculateDifference function calls (the third parameter is the recursion counter)
calculateDifferenceInternal :: (Int, Int, Int) -> (Int, Int, Int) -> Int -> Int

从这里,您应该能够弄清楚如何实现calculateDifferencecalculateDifferenceInternal


编辑:正如amalloy指出的那样,一个更好的解决方案是只输出计数器,而不要输入一个计数器:因此,factorialInternal :: (Int, Int) -> (Int, Int)可以代替factorialInternal Int -> (Int, Int)。定义如下:

factorialInternal 1 = (1, 0)
factorialInternal n = let (x, y) = factorialInternal (n - 1) in (n * x, y + 1)