2015-06-28 15 views
18

Nếu tôi có một loại giống như data T = T Int String và một chức năng như vậy:GHC có tạo một bản sao mới của một đối tượng khi phá hủy và xây dựng lại nó không?

identity :: T -> T 
identity (T a b) = T a b 

Sau khi giải cấu trúc trong mô hình kết hợp, không GHC tạo ra một đối tượng T mới có chứa tham chiếu đến cùng Int và String? Hay nó trả về cùng một đối tượng chính xác (với cùng một địa chỉ bộ nhớ) mà nó nhận được? Tôi hiểu chúng tương đương về mặt ngữ nghĩa, tôi chỉ tò mò thôi.

Trả lời

15

Nói chung GHC sẽ phân bổ một giá trị mới thay vì sử dụng lại đối số trong tình huống đó. Trong trường hợp cụ thể này, bạn có thể viết một cái gì đó như

f :: T -> T 
f [email protected](T x y) = t 

để sử dụng lại một cách rõ ràng đối số. Thật không may, một trong các trường hợp bạn muốn thực sự muốn điều này -

fmap :: (a -> b) -> Either e a -> Either e b 
fmap f (Right x) = Right (f x) 
fmap f (Left x) = Left x 

- GHC sẽ phân bổ một giá trị mới Left, và bạn có thể không chỉ đơn giản là tái sử dụng các đối số, bởi vì kết quả có một kiểu khác nhau . Theo như tôi biết không có cách nào để nói với GHC sử dụng lại đối số trong trường hợp này ngoài unsafeCoerce.

+0

Tôi hiểu. Đó là loại thất vọng. Tôi đã thực sự suy nghĩ về trường hợp bạn có một cấu trúc dữ liệu liên tục lồng nhau (như một cây nhị phân) và bạn muốn chèn một giá trị đã có sẵn. Bạn sẽ cần một hàm trợ giúp như 'insert :: (Ord a) => a -> Tree a -> Có thể (Tree a) 'trả về giá trị Không có gì nếu phần tử đã có mặt để tránh tái tạo đường dẫn của giá trị . –

+4

@Ramith Điều đó phá hủy sự lười biếng không may; tất cả các cuộc gọi trên đường dẫn đến nút lá sẽ phải chờ cuộc gọi cuối cùng quay trở lại trước khi họ biết liệu họ có trả về một tham chiếu đến nút xây dựng hiện có hay phân bổ một nút mới, có nghĩa là buộc gốc bước buộc mọi thứ. Vì vậy, nếu bạn muốn lựa chọn giữa các thuộc tính đó (sự lười biếng và tránh tái tạo cây giống hệt nhau), thì nó cần phải được lập trình rõ ràng (chẳng hạn như thông qua trình trợ giúp Có thể (Tree a)) hơn là hành vi ngầm của trình biên dịch. – Ben

+1

Có phải 'unsafeCoerce' an toàn trong trường hợp này không? Tôi có nghĩa là 'Hoặc là một' và 'hoặc là một c' có cùng một đối số để' trái' vì vậy nó có vẻ hợp lý rằng các 'trái' constructor có thể được ép buộc mà không có vấn đề (và có lẽ là), tuy nhiên là có * bảo đảm * về điều này? – Bakuriu

15

Bạn có thể kiểm tra điều này một cách dễ dàng đủ với -ddump-simpl. Việc phân bổ giá trị của một ADT sẽ hiển thị như một ứng dụng của một hàm tạo dữ liệu.

Trong trường hợp này, GHC không nhận ra rằng nó có thể tái sử dụng các giá trị, và thậm chí nó không phải thực hiện các mô hình kết hợp:

module I where 

data T = T Int String 

identity :: T -> T 
identity (T a b) = T a b 

-

[email protected]:/tmp$ ghc -ddump-simpl I 
[1 of 1] Compiling I    (I.hs, I.o) 

==================== Tidy Core ==================== 
Result size of Tidy Core = {terms: 3, types: 3, coercions: 0} 

I.identity :: I.T -> I.T 
[GblId, Arity=1, Caf=NoCafRefs, Str=DmdType] 
I.identity = \ (ds_dHN :: I.T) -> ds_dHN 

này xảy ra ngay cả mà không bật tối ưu hóa và nó cũng hoạt động trên các ADT với nhiều hơn một hàm tạo.

+0

Trường hợp khớp ảnh hưởng đến mức độ nghiêm ngặt. Các đặc điểm kỹ thuật ban đầu cho 'bản sắc' đòi hỏi nó phải được nghiêm ngặt, vì vậy GHC giữ độ nghiêm ngặt đó. – MathematicalOrchid

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