I don't know Miranda too well, but based on Haskell (I believe the differences between the two here would be minor, with only the #
being a unary operator for list length being the only semi-significant one and with ||
being the comment syntax): The .
is function composition:
(p . q) x = p (q x)
|| also can be written as:
p . q = \x -> p (q x)
Function composition is an associative operation, so p . (q . r)
= (p . q) . r
= p . q . r
.
Using this information, we can expand this with the definition of .
:
g = (foldr (+) 0) . (foldr ((:) . ((#) . (:[]))) []) || Original definition
g list = foldr (+) 0 (foldr ((:) . ((#) . (:[]))) [] list)
g list = foldr (+) 0 (foldr (\x -> (:) (((#) . (:[])) x)) [] list)
g list = foldr (+) 0 (foldr (\x -> (:) ((\y -> (#) ((:[]) y)) x)) [] list)
This can be cleaned up some more:
g list = foldr (+) 0 (foldr (\x -> (:) ((\y -> (#)(y:[])) x)) [] list) || More conventional operator syntax for the innermost `:`
g list = foldr (+) 0 (foldr (\x -> (:) ((#)(x:[]))) [] list) || Innermost lambda was applied to x. Substitute y for x.
g list = foldr (+) 0 (foldr (\x -> (:) ((#)([x]))) [] list) || Apply innermost `:`
g list = foldr (+) 0 (foldr (\x -> (:) #[x])) [] list) || Remove unnecessary parentheses
g list = foldr (+) 0 (foldr (\x acc -> (:) (#[x]) acc) [] list) || Explicitly write implicit argument. This particular step is called eta-expansion
g list = foldr (+) 0 (foldr (\x acc -> (:) 1 acc) [] list) || #[x] is always 1, no matter what x is
g list = foldr (+) 0 (foldr (\x acc -> 1 : acc) [] list) || More conventional syntax for `:`
Also note that the foldr
doesn't apply +0
to every element, as you've stated in the question. foldr op z (a:b:c:[])
becomes op a (op b (op c z)))
(a:b:c:[]
is another way to write [a,b,c]
). I always thought this diagram is helpful to understand that:

Additionally, most likely the reason that you got an error when calling it directly is that p . q x
is not the same as (p . q) x
.