Хэмминг со списками в Хаскеле

Я хочу написать функцию Хемминга в Haskell, которая получает список в качестве ввода. У меня уже есть это:

    merge :: [Integer] -> [Integer] -> [Integer]
    merge (x:xs)(y:ys)
      | x == y    = x : merge xs ys
      | x <  y    = x : merge xs (y:ys)
      | otherwise = y : merge (x:xs) ys


hamming :: [Integer] 
hamming 
  = 1 : merge (map (2*) hamming) (merge (map (3*) hamming) (map (5*) hamming))

Это было просто. Но теперь я хочу что-то вроде "Хэмминга [4,6,7,9]" в качестве входных данных. Фактическое значение равно 1, но теперь оно должно быть списком, а каждое число в списке находится в списке Хэмминга. И конечно 2х 3х и 5х в списке.

Я написал что-то вроде

"hamming (x:xs) = x : merge (map (2*) hamming) (merge (map (3*) hamming) (map (5*) hamming))" просто чтобы проверить список, но это не работает.

1 ответ

Хотя это дубликат, я покажу вам, как вы могли бы прийти к решению. Который действительно появляется в дубликате; здесь мое внимание будет сосредоточено на путешествии, а не на пункте назначения. Ты пытался

hamming (x:xs)
    = 1 : merge (map (2*) hamming) (merge (map (3*) hamming) (map (5*) hamming))

Что здесь происходит? Это функция? Список? Здесь все перемешано; это беспорядок. Вы хотите превратить определение списка в функцию, назвав ее hamming [2,3,5], сказать; но то, что должно идти в map выражения? Вызов функции, hamming [2,3,5], также?

Но это противоречило бы цели, так как мы явно используем один и тот же список здесь в нескольких отдельных местах, то есть в трех (или, возможно, в большем...) map s, каждый из которых поддерживает свой собственный указатель на разделяемую последовательность. И выполнение отдельных вызовов функций, даже если они эквивалентны, (скорее всего и почти наверняка) приведет к созданию трех отдельных, даже если они равны. И это не то, что нам нужно здесь (это на самом деле забавное упражнение; попробуйте его и посмотрите, насколько медленнее и потребляет память функция).

Итак, разделите ваши проблемы! Перепишите это сначала как (все еще недействительно)

hamming (x:xs) = h where
  h = 1 : merge (map (2*) h) (merge (map (3*) h) (map (5*) h))

Сейчас h это общий список, и у вас есть свобода делать свою функцию, hamming что бы вы ни хотели, т.е.

hamming :: [Integer] -> [Integer] 
hamming [2,3,5] = h where
   h = 1 : merge (map (2*) h) (merge (map (3*) h) (map (5*) h))
     = 1 : merge (map (2*) h) (merge (map (3*) h) (merge (map (5*) h) []))

то есть,

     = 1 : foldr merge [] [map (p*) h | p <- [2,3,5]]

так как

       g a (g b (g c (... (g n z) ...)))
     =
       foldr g z [a,b,c,...,n]

и вот оно, ваш ответ, вплоть до некоторого обыденного переименования параметров.

Не забудьте переименовать свой merge функционировать как union Так как "слияние" не должно пропускать дубликаты, вызывая слияние как таковое. И сохраняйте все ваши определения, начиная с одного и того же уровня отступа в файле.

Другие вопросы по тегам