Я попытаюсь продемонстрировать, как работает код behzad.nouri, чтобы понять его сам:
Учитывая лень Хаскелла, мы наблюдаем, что !! n
означает, что наш окончательный список будет оцененк этому (n+1)
й элемент.Наш основной блок для каждой монеты:
let b = (take x a) ++ zipWith (+) b (drop x a) in b
Здесь есть небольшая хитрость, которая работает, потому что b
- это список.Обратите внимание, что подобный тип ссылки на себя не сработал бы, если бы b
было целым числом.Допустим, наша единственная монета была 2:
> let b = (take 2 [1,0,0,0,0]) ++ zipWith (+) b (drop 2 [1,0,0,0,0]) in b
=> [1,0,1,0,1]
(что означает один способ сделать ноль, один способ сделать два и один способ сделать четыре.) Что происходит, то b
создается рекурсивно какна него ссылаются до тех пор, пока не будет совпадения длины для оценки почтового индекса:
> zipWith (+) [] (drop 2 [1,0,0,0,0])
=> []
-- But we prepended [1,0] so the next `b` is [1,0]
> zipWith (+) [1,0] (drop 2 [1,0,0,0,0])
=> [1,0]
-- But we prepended [1,0] so the next `b` is [1,0,1,0]
> zipWith (+) [1,0,1,0] (drop 2 [1,0,0,0,0])
=> [1,0,1]
-- But we prepended [1,0] so the result matching the length is [1,0,1,0,1]
Теперь давайте воспользуемся этими знаниями, чтобы выполнить solve 4 [1,2,3]
:
let b = (take 3 [1,0,0,0,0]) ++ zipWith (+) b (drop 3 [1,0,0,0,0]) in b
take 3 [1,0,0,0,0] -- n+1 elements are evaluated from the infinite list
=> [1,0,0]
++ [0,0] -- drop 3 from [1,0,0,0,0]
(+) []
=> []
-- prepend [1,0,0]
=> [1,0,0]
++ [0,0]
(+) [1,0,0]
=> [1,0]
-- prepend [1,0,0]
=> [1,0,0,1,0]
Это один из способов сделатьноль и один способ сделать три.Далее:
let b = (take 2 [1,0,0,1,0]) ++ zipWith (+) b (drop 2 [1,0,0,1,0]) in b
take 2 [1,0,0,1,0]
=> [1,0]
++ [0,1,0]
(+) []
=> []
-- prepend [1,0]
=> [1,0]
++ [0,1,0]
(+) [1,0]
=> [1,1,0]
-- prepend [1,0]
=> [1,0,1,1,0]
++ [0,1,0]
(+) [1,0,1,1,0]
=> [1,1,1]
-- prepend [1,0]
=> [1,0,1,1,1]
Это один способ сделать 0, один способ сделать 2, один способ сделать 3 и один способ сделать 4. Далее:
let b = (take 1 [1,0,1,1,1]) ++ zipWith (+) b (drop 1 [1,0,1,1,1]) in b
Этотот, на котором больше всего итераций, начиная с b
, построен только из одного элемента
take 1 [1,0,1,1,1]
=> [1]
++ [0,1,1,1]
(+) []
=> []
-- prepend [1]
=> [1]
++ [0,1,1,1]
(+) [1]
=> [1]
-- prepend [1]
=> [1,1]
++ [0,1,1,1]
(+) [1,1]
=> [1,2]
-- prepend [1]
=> [1,1,2]
++ [0,1,1,1]
(+) [1,1,2]
=> [1,2,3]
-- prepend [1]
=> [1,1,2,3]
++ [0,1,1,1]
(+) [1,1,2,3]
=> [1,2,3,4]
-- prepend [1]
=> [1,1,2,3,4]
Это 1 способ сделать 0, 1 способ сделать 1, 2 способа сделать 2, 3 способа сделать 3,и 4 способа сделать 4.