I'll try to demonstrate how behzad.nouri's code is working in an effort to understand it myself:
Keeping in mind Haskell's laziness, we observe that !! n means our final list will be evaluated up to it's (n+1)th element. Our main block for each coin is:
let b = (take x a) ++ zipWith (+) b (drop x a) in b
There's a little trick here that works because b is a list. Note that a similar kind of self-reference wouldn't work if b were an integer. Let's say our only coin was 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]
(Which means one way to make zero, one way to make two, and one way to make four.) What happens is b gets built recursively as it's self-referenced until there is a length match for the zip evaluation:
> 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]
Now let's use this knowledge to follow through 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]
That's one way to make zero and one way to make three. Next:
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]
That's one way to make 0, one way to make 2, one way to make 3, and one way to make 4. Next:
let b = (take 1 [1,0,1,1,1]) ++ zipWith (+) b (drop 1 [1,0,1,1,1]) in b
This is the one with the most iterations since b is built from just one element
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]
That's 1 way to make 0, 1 way to make 1, 2 ways to make 2, 3 ways to make 3, and 4 ways to make 4.