Я не слишком хорошо знаю Миранду, но на основе Хаскелла (я полагаю, что различия между ними здесь будут незначительными, поскольку только #
является унарным оператором для длины списка, являющимся единственным полусущественным и с ||
- это синтаксис комментария): .
- это состав функции:
(p . q) x = p (q x)
|| also can be written as:
p . q = \x -> p (q x)
Композиция функций является ассоциативной операцией, поэтому p . (q . r)
= (p . q) . r
= p . q . r
.
Используя эту информацию, мы можем расширить ее с помощью определения .
:
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)
Это можно исправить еще немного:
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 `:`
Также обратите внимание, что foldr
не применяется +0
к каждому элементу, как вы указали в вопросе. foldr op z (a:b:c:[])
становится op a (op b (op c z)))
(a:b:c:[]
- это еще один способ написать [a,b,c]
). Я всегда думал, что эта диаграмма полезна, чтобы понять, что:
Кроме того, наиболее вероятной причиной возникновения ошибки при непосредственном вызове является то, что p . q x
означает , а не так же, как (p . q) x
.