Over on Code Review, я ответил на вопрос о наивном решении Haskell fizzbuzz, предложив реализацию, которая выполняет итерацию вперед, избегая квадратичной стоимости растущего числа простых чисел и полностью отбрасывая модульное деление (почти). Здесь код:
fizz :: Int -> String
fizz = const "fizz"
buzz :: Int -> String
buzz = const "buzz"
fizzbuzz :: Int -> String
fizzbuzz = const "fizzbuzz"
fizzbuzzFuncs = cycle [show, show, fizz, show, buzz, fizz, show, show, fizz, buzz, show, fizz, show, show, fizzbuzz]
toFizzBuzz :: Int -> Int -> [String]
toFizzBuzz start count =
let offsetFuncs = drop (mod (start - 1) 15) fizzbuzzFuncs
in take count $ zipWith ($) offsetFuncs [start..]
В качестве дополнительной подсказки я предложил переписать ее с помощью Data.List.unfoldr
. Версия unfoldr
является очевидной простой модификацией этого кода, поэтому я не буду вводить ее здесь, если люди, желающие ответить на мой вопрос, не настаивают на том, что это важно (никаких спойлеров для OP над обзором кода). Но у меня есть вопрос об относительной эффективности решения unfoldr
по сравнению с zipWith
. Хотя я больше не неофит Хаскелла, я не эксперт по внутренним вопросам Haskell.
Решение An unfoldr
не требует бесконечного списка [start..]
, так как он может просто разворачиваться из start
. Мои мысли
- Решение
zipWith
не запоминает каждый следующий элемент[start..]
по мере его запроса. Каждый элемент используется и отбрасывается, поскольку не сохраняется ссылка на главу [start..]. Таким образом, больше нет памяти, чем сunfoldr
. - Обеспокоенность по поводу производительности
unfoldr
и последних патчей, чтобы сделать ее всегда встроенной, выполняется на уровне, который я еще не достиг.
Итак, я думаю, что эти два эквивалента в потреблении памяти, но не имеют представления об относительной производительности. Надеясь, что более информированные Haskellers могут направить меня к пониманию этого.
unfoldr
кажется естественным, чтобы использовать для генерации последовательностей, даже если другие решения более выразительны. Я просто знаю, что мне нужно больше узнать об этой фактической производительности. (По какой-то причине я нахожу foldr
гораздо легче понять на этом уровне)
Примечание: unfoldr
использование Maybe
стало первой потенциальной проблемой производительности, которая возникла у меня, прежде чем я даже начал исследовать проблему (и единственный бит обсуждений оптимизации/вложения, которые Я полностью понял). Поэтому я сразу же смог перестать беспокоиться о Maybe
(учитывая недавнюю версию Haskell).