#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
реализации assequence . replicate n
.2. @camccann — ты прав!
sequence ms = foldr ...
— спасибо за подсказку