2009-12-20 43 views
8

Cho phép nói rằng tôi đang xây dựng trình phân tích cú pháp cho ngôn ngữ dành riêng cho miền trong F #.Mẫu thiết kế F #

tôi đã xác định một sự kết hợp kỳ thị để đại diện cho biểu thức:

type Expression = 
     | Equality of Expression*Expression 
     | NonEquality of Expression*Expression 
     | Or of Expression*Expression 
     | And of Expression*Expression 
     | If of Expression*Expression 
     | IfElse of Expression*Expression*Expression 
     | Bool of bool 
     | Variable of string 
     | StringLiteral of string 

Bây giờ, tôi đã xây dựng được một AST loại Expression và muốn tạo mã cho nó. Tôi có một chức năng mà gõ suy luận và gõ kiểm tra trên một biểu thức.

Nó được định nghĩa như

let rec InferType expr = 
     match expr with 
     | Equality(e1,e2) -> CheckTypes (InferType e1) (InferType e2) 
     | Or(e1,e2) -> CheckTypes (InferType e1) (InferType e2) 
     | And(e1,e2) -> CheckTypes (InferType e1) (InferType e2) 
     ... 

Và tôi có một chức năng để tạo ra mã mà sau một mô hình tương tự: Đi một biểu thức, viết báo cáo mẫu-phù hợp cho từng hạng mục trong đoàn.

Câu hỏi của tôi là: Đây có phải là cách thành ngữ để thực hiện điều đó trong F # không?

Dường như với tôi rằng nó sẽ sạch hơn nếu mỗi thành viên của liên minh xác định riêng InferTypeGenerateCode tại địa phương với nó.

Nếu tôi đang sử dụng C#, tôi sẽ xác định một số lớp cơ sở trừu tượng được gọi là Expression với các phương pháp ảo cho InferTypeGenerateCode rồi ghi đè chúng trong từng phân lớp.

Có cách nào khác để thực hiện việc này không?

Trả lời

17

Dường như với tôi rằng nó sẽ là sạch hơn nếu mỗi thành viên của công đoàn định nghĩa riêng của mình InferTypeGenerateCode cục bộ với nó.

Tôi tin bạn có nghĩa là "quen thuộc hơn" chứ không phải "sạch hơn".

Thực sự, có phải lý tưởng của bạn để bạn thực thi mã máy phát trên 10 lớp khác nhau không?

Chắc chắn có một sự căng thẳng cơ bản giữa việc bạn muốn nhóm mọi thứ "theo loại" hay "bằng cách hoạt động". Cách OO thông thường là "theo loại" trong khi cách thức FP (lập trình chức năng) là "bằng thao tác".

Trong trường hợp trình biên dịch/thông dịch viên (hoặc hầu hết mọi thứ trong OO dựa chủ yếu vào mẫu Khách truy cập), tôi nghĩ "hoạt động" là nhóm tự nhiên hơn. Trình tạo mã cho IfAndOr có thể có điểm chung chung; các typecheckers của các nút khác nhau sẽ tương tự nhau có tính tương đồng; nếu bạn tạo một máy in khá, có thể sẽ có các định dạng thường dùng cho tất cả các triển khai thực hiện in ấn nút. Ngược lại, in, đánh máy, và codegenning một IfElse thực sự không có nhiều để làm với nhau cả, vậy tại sao bạn muốn nhóm những người trong một lớp IfElse?

(Để trả lời các câu hỏi của bạn: có, đây là thành ngữ. Có cách nào khác - có, bạn có thể làm điều đó giống như bạn làm trong C#.Tôi nghĩ bạn sẽ thấy mình ít hài lòng hơn với cách C# và mã cũng sẽ lớn hơn 2-3 lần theo cách đó, không có lợi ích.)

+1

Cảm ơn - đây là câu trả lời tôi đang tìm kiếm . –

9

Là một lập trình viên OCaml, tôi muốn nói điều này hoàn toàn là thành ngữ. Ngẫu nhiên, điều này giúp bạn phân tách mối quan tâm tốt hơn nếu bạn đã viết một hệ thống phân cấp lớp với các phương thức lớp. Bạn sẽ có được mô đun tương tự trong ngôn ngữ OO với khách truy cập InferType, nhưng nó sẽ có nhiều mã hơn.

1

Điều khác mà bạn thường làm trong một ngôn ngữ chức năng là xác định hoạt động fold trên kiểu dữ liệu và sau đó xác định các chức năng tạo mã và tạo mã theo dạng gấp. Trong trường hợp cụ thể này, tôi không chắc chắn rằng nó mua cho bạn nhiều bởi vì hàm nếp gấp sẽ có nhiều đối số đến mức sẽ không dễ hiểu lắm:

let rec fold eqE nonE andE orE ... = function 
| Equality(e1,e2) -> eqE (e1 |> fold eqE nonE ...) (e2 |> fold eqE nonE ...) 
| NonEquality(e1,e2) -> nonE ... 
... 

let inferTypes = fold checkTypes checkTypes checkTypes ... 
+1

Đó có phải là "gấp" một cách xấu xí hơn để xây dựng khách truy cập không? Tôi vẫn thích phong cách của OP, trong đó inferTypes được định nghĩa trực tiếp bởi câu lệnh khớp mẫu. – Tobu

+2

@Tobu: Cá nhân tôi thấy nó ít xấu xí hơn so với mẫu Khách truy cập. Như tôi đã nói, trong ví dụ cụ thể này, có rất nhiều trường hợp khác nhau mà tôi không nghĩ rằng việc định nghĩa mọi thứ về mặt nếp gấp sẽ tốt hơn. Nói chung, mặc dù, nó thường làm cho tinh thần để xác định các hoạt động gấp trên datatypes đệ quy (chẳng hạn như F # 's built-in 'List.fold'). – kvb