Why does function apply complain about long lists?

柔情痞子 提交于 2019-12-05 13:24:53
Kaz

ANSI Common Lisp allows implementations to constrain the maximum number of arguments which can be passed to a function. This limit is given by call-arguments-limit can be as small as 50.

For functions which behave like algebraic group operators obeying the associative property (+, list, and others), we can get around the limit by using reduce to decimate the input list while treating the function as binary.

For instance to add a large list of numbers: (reduce #'+ list) rather than (apply #'+ list).

Notes on reduce

In Common Lisp, reduce will appear to work even if the list is empty. Few other languages give you this, and it doesn't actually come from reduce: it won't work for all functions. But with + we can write (reduce #'+ nil) and it calculates zero, just like (apply #'+ nil).

Why is that? Because the + function can be called with zero arguments, and when called with zero arguments, it yields the identity element for the additive group: 0. This dovetails with the reduce function.

In some other languages the fold or reduce function must be given an initial seed value (like 0), or else a nonempty list. If it is given neither, it is an error.

The Common Lisp reduce, if it is given an empty list and no :initial-value, will call the kernel function with no arguments, and use the return value as the initial value. Since that value is then the only value (the list is empty), that value is returned.

Watch out for functions with special rules for the leftmost argument. For instance:

(apply #'- '(1)) -> -1  ;; same as (- 1), unary minus semantics.

(reduce #'- '(1)) -> 1  ;; what?

What's going on is that when reduce is given a one-element list, it just returns the element without calling the function.

Basically it is founded on the mathematical assumption mentioned above that if no :initial-value is supplied then f is expected to support (f) -> i, where i is some identity element in relation to f, so that (f i x) -> x. This is used as the initial value when reducing the singleton list, (reduce #'f (list x)) -> (f (f) x) -> (f i x) -> x.

The - function doesn't obey these rules. (- a 0) means "subtract zero from a" and so yields a, whereas (- a) is the additive inverse of a, probably for purely pragmatic, notational reasons (namely, not making Lisp programmers write (- 0 a) just to flip a sign, just for the sake of having - behave more consistently under reduce and apply). The - function also may not be called with zero arguments.

If we want to take a list of numbers and subtract them all from some value x, the pattern for that is:

(reduce #'- list-of-numbers :initial-value x)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!