Có cách nào chung để 'mở rộng' danh sách được sử dụng làm đối số riêng lẻ cho chức năng khác không?


9

Ví dụ: giả sử tôi có một danh sách các chuỗi L, có lẽ từ một &restđối số. Tôi có thể làm gì để Lcó tác dụng tương tự như sau?

(concat (first L) (second L) ... (last L))

(Tôi biết mapconcatsẽ làm việc ở đây cho ví dụ này , nhưng tôi đang tìm một quy trình chung.)

Câu trả lời:



6

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 applycho 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:

  1. applylà 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.

  2. Không có cách nào để đảm bảo applysẽ 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ữ.

  3. Hàm được gọi bởi applysẽ 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"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.