Позвольте мне переименовать вторую версию и исправить несколько опечаток, чтобы вы могли проверить функции.
toBits :: Integral a => a -> [Bool]
toBits 0 = []
toBits n = x : toBits m where
(m,y) = n `divMod` 2
x = y /= 0
toBits2 :: Integral a => a -> [Bool]
toBits2 = toBits' [] where
toBits' l 0 = l
toBits' l n = toBits' (x : l) m where
(m,y) = n `divMod` 2
x = y /= 0
Эти функции на самом деле не вычисляют одно и то же;первый создает список, начинающийся с младшего значащего бита, а второй начинается с самого старшего бита.Другими словами, toBits2 = reverse . toBits
, и фактически reverse
может быть реализован с тем же аккумулятором, который вы используете в toBits2
.
Если вы хотите, чтобы список начинался с младшего значащего бита, toBits
- это хороший стиль Haskell.Это не приведет к переполнению стека, потому что рекурсивный вызов содержится внутри конструктора (:), который является ленивым.(Кроме того, вы не можете вызвать наращивание thunk в аргументе toBits
, принудительно задав значение более позднего элемента списка результатов раньше, потому что в первом случае toBits 0 = []
необходимо оценить аргумент, чтобы определить, является лисписок пуст.)
Если вы хотите, чтобы список начинался с старшего значащего бита, можно либо написать toBits2
напрямую, либо определить toBits
и использовать reverse . toBits
.Вероятно, я бы предпочел последнее, так как, по моему мнению, это легче понять, и вам не нужно беспокоиться о том, что переопределение reverse
приведет к переполнению стека.