Понимание списка в Haskell

#haskell #list-comprehension

#haskell #понимание списка

Вопрос:

Я использовал следующий код, чтобы получить все комбинации из заранее определенного количества чисел:

 getList x = [ [a,b,c] | a <- [1..x], b <- [1..x], c <- [1..x]]
  

Для начала это было прекрасно, но я хочу расширить программу для обработки очень больших списков, и я продолжаю думать, что должен быть лучший способ сделать это. Как бы я создал функцию, которая принимает тот же параметр x, что и здесь, а также другой параметр для определения количества элементов в подсписках. Для четырех элементов я бы пошел и изменил код:

 getList x = [ [a,b,c,d] | a <- [1..x], b <- [1..x], c <- [1..x], d <- [1..x]]
  

Это не обязательно должно быть понимание списка. Спасибо за любую помощь.

Ответ №1:

Я полагаю, что вам нужна была бы replicateM функция в Control.Monad .

Монада списка основана на «попытке всех возможных комбинаций», а plain replicate создает список, повторяя элемент некоторое количество раз. Таким образом, результатом replicateM является, учитывая некоторый список возможных значений, список всех возможных способов выбора элемента из этого списка некоторое количество раз.

Например:

 > replicateM 2 [0, 1]
[[0,0],[0,1],[1,0],[1,1]]
> replicateM 3 [0, 1]
[[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]]
  

Итак, чтобы расширить вашу функцию до произвольных повторений, вы бы использовали что-то вроде:

 getListN n x = replicateM n [1..x]
  

…где ваш оригинал getList был бы эквивалентен getListN 3 .

Комментарии:

1. Спасибо, эта функция охватывает все, что я хотел там сделать.

2. 1 в избранном. Мне определенно придется разложить / десугаризировать это для себя и увидеть внутреннюю работу этой монадической магии.

3. @Dan: Если это поможет, я могу сказать, что конечный результат в значительной степени совпадает с тем, что дает понимание списка в вопросе, и что большая часть волшебства происходит в sequence функции.

Ответ №2:

На случай, если кому-то нравится немонадическое решение для понимания внутренней работы (хотя решение через replicateM отличное!):

 getListN n = foldl (ass bs -> [ b:as | b <- bs, as <- ass]) [[]] . replicate n
  

По сути, эта реализация через foldl работает точно так же, как и replacatM -solution.

Комментарии:

1. Я думаю, sequence на самом деле используется правый сгиб, а не левый. В противном случае, да, это эквивалентно replicateM реализации as sequence . replicate n .

2. @camccann — ты прав! sequence ms = foldr ... — спасибо за подсказку