Những gì bạn muốn làm có vẻ như gấp hoặc không gấp một chuỗi các đối tượng cùng loại. Nó là hấp dẫn để sử dụng apply
cho mục đích này, bởi vì trong nhiều trường hợp nó thực sự sẽ làm việc. Nhưng nó không chính xác là công cụ phù hợp cho việc này, và đây là lý do:
apply
là một cơ chế lập trình meta, không chỉ vậy, nó còn quá chung chung cho tác vụ vì nó có thể xử lý các chuỗi các đối tượng thuộc các loại khác nhau, không nhất thiết phải gọi các hàm của hai đối số. Kết quả là, một số lần bạn sẽ nhận được một hành vi không chính xác, ví dụ:
(apply 'concat "baz" '("foo" "bar"))
> "bazfoobar"
Nhưng theo trực giác, bạn mong đợi một loại không phù hợp ở đây.
Không có cách nào để đảm bảo apply
sẽ có thể xử lý nhiều đối số như bạn có thể đưa ra, đó thường là giới hạn được áp đặt bởi việc triển khai ngôn ngữ.
Hàm được gọi bởi apply
sẽ có thể có được một tham chiếu của danh sách đối số được truyền cho nó theo cách này. Điều này cũng không rõ ràng và có thể dẫn đến lỗi sau:
(let ((test (list 1 2 3)))
(cons
(apply (lambda (&rest x)
(prog1 (cl-reduce '+ x) (setcar x 0)))
test)
test))
;; This behaviour is undefined. Could end up both ways
> (6 1 2 3)
> (6 0 2 3)
Nếu danh sách đối số được sao chép, thì bạn phải trả giá cho việc sử dụng nhiều bộ nhớ hơn mức cần thiết, nhưng nếu nó không được sao chép (thông qua như hiện tại), thì bạn có nguy cơ làm hỏng danh sách, nếu hàm được gọi là sửa đổi nó.
Vì vậy, cách tốt hơn để làm là sử dụng cl-reduce
. Lợi ích là nó được thiết kế đặc biệt để thực hiện loại nhiệm vụ này.
(cl-reduce 'concat '("foo" "bar" "baz"))
> "foobarbaz"