Я пытаюсь понять кое-что о Haskell функциях.
Во-первых, вот функция Фибоначчи, определенная типичным «медленным» способом (то есть рекурсивным без запоминания и без трюков с бесконечным списком). )
slowfib :: Int -> Integer
slowfib 0 = 0
slowfib 1 = 1
slowfib n = slowfib (n-2) + slowfib (n-1)
Далее каноническая запоминающаяся версия того же самого. (Только немного отличается от типичных примеров в tutorals / books / et c, потому что я предпочитаю префиксную версию оператора !!
.)
memfib = (!!) (map fib [0..])
where
fib 0 = 0
fib 1 = 1
fib k = memfib(k-2) + memfib(k-1)
Приведенное выше решение использует частичное применение * 1010 Оператор *, который имеет смысл: мы хотим, чтобы memfib
заканчивал как функция, которая принимает параметр, и мы определяем его без включения параметра в определение.
Пока все хорошо. Теперь я подумал, что мог бы написать эквивалентную функцию запоминания, которая включает , включает параметр в определение, поэтому я сделал это:
memfib_wparam n = ((!!) (map fib [0..])) n
where
fib 0 = 0
fib 1 = 1
fib k = memfib_wparam(k-2) + memfib_wparam(k-1)
(В терминах лямбда-исчисления memfib
и memfib_wparams
- это просто eta-преобразования друг друга. Я думаю ???)
Это работает, но запоминание пропало. На самом деле memfib_wparam
ведет себя даже хуже, чем showfib
: он не только медленнее, но и использует больше, чем вдвое.)
*Main> slowfib 30
832040
(1.81 secs, 921,581,768 bytes)
*Main> memfib 30
832040
(0.00 secs, 76,624 bytes)
*Main> memfib_wparam 30
832040
(2.01 secs, 2,498,274,008 bytes)
Что здесь происходит? Что еще более важно, каково мое более широкое понимание ошибочных определений функций Haskell? Я предполагал, что синтаксис, который я использовал в memfib_wparam
, был просто syntacti c sugar для того, что я делал в memfib
, но, очевидно, это не так.