2015-07-03 16 views
9

Trong mã bên dưới, cùng một mẫu khớp với (Nút n bên trái bên phải) được sử dụng bởi ba hàm khác nhau. Nếu tôi muốn thêm mẫu, ví dụ: (Nút n (Lá) (Lá)) hoặc thay đổi kiểu dữ liệu của tôi, tôi phải thay đổi tất cả các chức năng. Có cách nào để tái sử dụng các mẫu này, vì vậy tôi chỉ phải định nghĩa chúng một lần?Các mẫu tái sử dụng Haskell

data Tree = Node Int Tree Tree 
      | Leaf 

add :: Tree -> Int -> Tree 
add (Node n left right) x = Node (n+x) (add left x) (add right x) 
add (Leaf) x = Leaf 

subtract :: Tree -> Int -> Tree 
subtract (Node n left right) x = Node (n-x) (subtract left x) (subtract right x) 
subtract (Leaf) x = Leaf 

swap :: Tree -> Tree 
swap (Node n left right) = Node n right left 
swap (Leaf) = Leaf 

tôi đã cố gắng

matchNode = (PNode n left right) 
add matchNode x = Node (n+x) (add left x) (add right x) 

nhưng nó sẽ không cho phép tôi sử dụng mô hình _, và tôi không thể trích xuất n, tráiđúng từ nó.

+2

Nếu bạn sử dụng GHC, bạn có thể sử dụng [Record Wildcards] (http://downloads.haskell.org/~ghc/latest/docs/html/users_guide/syntax-extns.html#record-wildcards). – PyRulez

Trả lời

4

này chỉ trả lời cho phần:

Nếu tôi muốn [...] thay đổi kiểu dữ liệu của tôi, tôi phải thay đổi tất cả các chức năng.

Trong trường hợp đó, bạn có thể tránh thay đổi tất cả các chức năng của xác định một mô hình tùy chỉnh với pattern synonyms extension:

{-# LANGUAGE PatternSynonyms #-} 

-- The old type: 
-- data Tree = Node Int Tree Tree 
--   | Leaf 

-- The new type 
data Tree = NewNode Tree Int Tree -- changed name & argument order 
      | Leaf 

pattern Node n left right = NewNode left n right 

add :: Tree -> Int -> Tree 
add (Node n left right) x = Node (n+x) (add left x) (add right x) 
add (Leaf) x = Leaf 

-- etc. 

Ở trên, tôi đổi tên các nhà xây dựng cũ Node vào NewNode, cũng thay đổi thứ tự các đối số của nó. Sau đó, tôi đã xác định một cầu nối tương thích pattern Node, làm cho các mẫu cũ bên dưới hoạt động trở lại.


Câu hỏi đặt ra cũng hỏi:

Có cách nào để tái sử dụng những mô hình, vì vậy tôi chỉ phải xác định chúng một lần?

@PyRulez đã nhận xét về cách sử dụng ký tự đại diện để rút ngắn mẫu. Dưới đây là một cách có thể:

{-# LANGUAGE ViewPatterns, RecordWildCards #-} 

-- an auxiliary record type to define the custom pattern 
data R = RNode { left::Tree , n::Int, right::Tree } | RLeaf 
-- a function to convert a Tree to a R 
toR :: Tree -> R 
toR (NewNode l n r) = RNode l n r 
toR _ = RLeaf 

-- Here we use a shorter pattern: 
add2 :: Tree -> Int -> Tree 
add2 (toR -> RNode{..}) x = Node (n+x) (add2 left x) (add2 right x) 
    -- ^^^^^^^^^^^^^^^^^^^ this brings in scope left, n, right 
add2 (toR -> RLeaf) x = Leaf 

Trong trường hợp cụ thể này, không có sự gia tăng lớn về không gian. Tuy nhiên, dù mẫu có lớn bao nhiêu, sau khi định nghĩa bản ghi (và chức năng phụ trợ) chúng ta chỉ phải viết toR -> RNode{...}.

Tôi không chắc chắn tôi thực sự thích điều này, mặc dù.

Đầu tiên, bản ghi gây ô nhiễm không gian tên chung với ba (một phần!) Chức năng left :: R -> Tree, n :: R -> Int, right :: R -> Tree. Điều này sẽ kích hoạt một số cảnh báo nếu bạn cố gắng sử dụng ví dụ: n làm đối số của một hàm không liên quan khác (The local name shadows the global name n).

Thứ hai, phần mở rộng ký tự đại diện ghi lại phạm vi một số biến không được viết trong mã - người đọc phải biết (hoặc đoán) những biến này là gì. Cũng lưu ý rằng mẫu RNode{..} mang lại ví dụ: n thành phạm vi có loại khác với tên chung: Int thay vì R -> Int. Người đọc có thể nghĩ rằng n là thiết bị toàn cầu và bị nhầm lẫn ngay cả ở cấp loại.

Thứ ba, các mã trên sử dụng xem mẫu, và những hiện nhầm lẫn giữa kiểm tra exhaustiveness:

Patterns.hs:23:1: Warning: 
    Pattern match(es) are non-exhaustive 
    In an equation for ‘add2’: Patterns not matched: _ _ 

Trong trường hợp cụ thể này, chúng tôi chỉ đơn giản là có thể viết

add2 :: Tree -> Int -> Tree 
add2 (node -> RNode{..}) x = Node (n+x) (add2 left x) (add2 right x) 
add2 _ x = Leaf 

để tránh những cảnh báo, nhưng chúng tôi không luôn có lựa chọn đó, nói chung.

+0

Sửa lỗi nếu tôi sai, nhưng các từ đồng nghĩa mẫu không cho phép bạn xác định một từ đồng nghĩa "ngắn gọn" cho 'Node n left right' và sử dụng từ đồng nghĩa đó thay cho mẫu' Node n left right' trong LHS của phương trình. Ghi lại các thẻ mở rộng, theo đề xuất của PyRulez trong bình luận của anh, dường như gần hơn với những gì OP đang tìm kiếm. – Jubobs

+0

Ok; Tôi có thể thấy những gì bạn mô tả có thể hữu ích trong OP'case. – Jubobs

+1

@Jubobs Bây giờ tôi đã cố gắng áp dụng đề xuất PyRulez, vì vậy điều này cũng nên trả lời phần "rút ngắn". – chi

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