2012-03-01 33 views
6

Tôi luôn viết của tôi danh sách sản xuất chức năng đệ quy ở định dạng này:Haskell Danh sách Concatenation vs (đầu: đuôi) định dạng

recursiveFunc :: [a] -> [b] 
recursiveFunc (x:xs) = [change x] ++ resursiveFunc xs where 
    change :: a -> b 
    change x = ... 

Tôi nhận ra bất kỳ chức năng như trên có thể được viết cho các trường hợp a -> b và sau đó đơn giản chỉ cần map được chỉnh sửa trên một tập hợp [a], nhưng vui lòng thực hiện ví dụ này xuống dưới nước.

HLint đề nghị thay thế [change x] ++ recursiveFunc xs bằng change x : recursiveFunc xs.

Đây có phải là gợi ý hoàn toàn thẩm mỹ, hoặc có một số ảnh hưởng đến cách Haskell thực thi chức năng này không?

+4

Vâng, với một đối số đầu tiên của phần tử đơn, '++' * sẽ * chỉ là 'cons' một lần và sau đó thoát, nhưng đó là cách rất vòng để thêm một giá trị duy nhất. – delnan

+2

Phiên bản của bạn có lợi thế là nếu vào một thời điểm nào đó bạn quyết định sửa đổi chức năng của mình sao cho có nhiều hơn một phần tử được thêm vào danh sách, thì sẽ ít thay đổi hơn. –

+0

đề xuất hlint không thay đổi kết quả của biểu thức. –

Trả lời

9

Khi sử dụng [change x] ++ recursiveFunc xs bạn tạo danh sách một phần tử không cần thiết, sau đó được tách riêng bởi hàm ++. Sử dụng : điều đó không xảy ra.

Plus ++ là một chức năng mà sau đó sẽ sử dụng hàm tạo :. Khi bạn sử dụng trực tiếp :, không cần phải gọi hàm.

Vì vậy, việc sử dụng : hiệu quả hơn về mặt lý thuyết (trình biên dịch có thể tối ưu hóa những khác biệt đó).

4

Lợi thế chính là change x : blah rõ ràng hơn - (:) chính xác là những gì bạn đang cố gắng làm (thêm một phần tử vào danh sách). Tại sao gọi hai chức năng khi một người sẽ làm gì?

Cách được đề xuất cũng hiệu quả hơn một chút - theo cách của bạn, tạo danh sách 1 phần tử rồi ném đi và thay thế bằng liên kết danh sách khác. Cách khác chỉ cần tạo một liên kết danh sách. Điều đó nói rằng, sự khác biệt là đủ nhỏ để không quan trọng 99% thời gian.

4

Dòng

recursiveFunc (x:xs) = [change x] ++ resursiveFunc xs 

là một chút bối rối vì nó không có trong normalform. Điều đó có nghĩa rằng ++ thể được thay thế trực tiếp với một bên tay phải của định nghĩa của nó:

(++) (a:as) bs = a:((++) as bs) 
(++) [] bs = bs 

-- => 

recursiveFunc (x:xs) = (change x):((++) [] resursiveFunc xs) 

-- => 

recursiveFunc (x:xs) = (change x):(resursiveFunc xs) 

Một Haskell biên dịch tự động áp dụng chuyển đổi như vậy.

Nhưng vì nó quá tầm thường nên mã của bạn khó đọc hơn. Một người nhìn vào nó và hỏi 'chờ đã ... cái gì?'

Các vấn đề liên quan