Подсчет времени рекурсии в Хаскеле - PullRequest
0 голосов
/ 16 января 2019

Я пишу небольшое школьное задание в Хаскеле, чтобы определить расстояние между двумя указанными датами. Я написал грубую функцию для циклического перемещения по датам, но не могу понять, как писать циклы в функциональном программировании. Раньше я занимался только процедурным и ООП-программированием. Мне как-то нужно хранить информацию о том, сколько раз я вызывал функцию nextDate, но Haskell не позволяет мне вводить переменную внутри функции. Вот код, который я дошел до сих пор. Это не очень Хаскели вообще ...

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 голосов
/ 16 января 2019

Если вы хотите отслеживать, сколько раз вызывается функция, вы должны указать это как вход. Нет другого способа сделать это, потому что 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...