Если вы хотите отслеживать, сколько раз вызывается функция, вы должны указать это как вход. Нет другого способа сделать это, потому что 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
Отсюда вы сможете понять, как реализовать calculateDifference
и calculateDifferenceInternal
.
РЕДАКТИРОВАТЬ: Как отметил Амаллой, лучшее решение состоит в том, чтобы просто вывести счетчик, а не принимать один: так что вместо 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)