2010-03-04 24 views
9

Tôi có một chức năng của mẫuSử dụng một biến trong mô hình kết hợp trong Ocaml hoặc F #

'a -> ('a * int) list -> int 

let rec getValue identifier bindings = 
    match bindings with 
    | (identifier, value)::tail -> value 
    | (_, _)::tail -> getValue identifier tail 
    | [] -> -1 

tôi có thể nói rằng identifier không bị ràng buộc theo cách tôi muốn nó và đang hành động như là một biến mới trong biểu thức đối sánh. Làm thế nào để tôi nhận được identifier là những gì được chuyển vào chức năng?

Ok! Tôi đã sửa nó với một bảo vệ mẫu, tức là | (i, value)::tail when i = indentifier -> value nhưng tôi thấy điều này xấu xí so với cách tôi muốn làm điều đó (tôi chỉ sử dụng những ngôn ngữ này vì chúng khá ...). Có suy nghĩ gì không?

+0

Cách tiếp cận ban đầu của bạn nhắc tôi về sự thống nhất của Prolog, nó khá tuyên bố hơn là chức năng. – ron

Trả lời

10

Bạn có thể sử dụng mẫu F # hoạt động để tạo mẫu sẽ thực hiện chính xác những gì bạn cần. F # hỗ trợ các mẫu hoạt động được tham số hóa lấy giá trị mà bạn đang đối sánh, nhưng cũng có tham số bổ sung.

Dưới đây là một ví dụ khá ngu ngốc mà không khi value là zero và nếu không thành công và trả về việc bổ sung giá trị và tham số quy định:

let (|Test|_|) arg value = 
    if value = 0 then None else Some(value + arg) 

Bạn có thể chỉ định các tham số trong mô hình kết hợp như thế này:

match 1 with 
| Test 100 res -> res // 'res' will be 101 

Bây giờ, chúng ta có thể dễ dàng xác định mẫu đang hoạt động sẽ so sánh giá trị khớp với đối số đầu vào của mẫu đang hoạt động. Các mô hình hoạt động trả unit option, có nghĩa là nó không ràng buộc bất kỳ giá trị mới (trong ví dụ trên, nó trở lại một số giá trị mà chúng ta gán cho một biểu tượng res):

let (|Equals|_|) arg x = 
    if (arg = x) then Some() else None 

let foo x y = 
    match x with 
    | Equals y -> "equal" 
    | _ -> "not equal" 

Bạn có thể sử dụng điều này như một lồng nhau mẫu, vì vậy bạn có thể viết lại ví dụ của mình bằng cách sử dụng mẫu hoạt động Equals.

+0

Thú vị (việc viết các mẫu hoạt động cho một loại phải cảm thấy giống như bản mẫu, nhưng bạn chỉ viết chúng một lần và tận dụng chúng nhiều lần). Làm thế nào để chúng hiển thị trong một chữ ký mô-đun? –

+0

Mẫu hoạt động 'Equals' là chung và hoạt động với bất kỳ loại nào hỗ trợ so sánh (một ràng buộc đặc biệt đối với các biến kiểu có sẵn trong F #). Các mẫu hoạt động hiển thị dưới dạng một hàm của tên đặc biệt trong chữ ký. Chữ ký trông như thế này: 'val (| Equals | _ |): 'a ->' a -> tùy chọn đơn vị khi 'a: equality' –

3

Đây là khiếu nại phổ biến, nhưng tôi không nghĩ rằng có cách giải quyết tốt nói chung; một mô hình bảo vệ thường là thỏa hiệp tốt nhất. Tuy nhiên, trong một số trường hợp cụ thể, có các lựa chọn thay thế, chẳng hạn như đánh dấu các chữ với thuộc tính [<Literal>] trong F # để chúng có thể được so khớp với.

5

Đây không phải là câu trả lời trực tiếp cho câu hỏi: cách khớp mẫu với giá trị của biến. Nhưng nó không hoàn toàn không liên quan.

Nếu bạn muốn xem cách đối sánh mẫu mạnh mẽ có thể bằng ngôn ngữ giống như ML tương tự như F # hoặc OCaml, hãy xem Moca.

Bạn cũng có thể xem mã được tạo bởi Moca :) (không có gì sai với trình biên dịch đang làm rất nhiều thứ cho bạn ở phía sau của bạn. muốn cảm thấy họ biết họ sẽ viết chi phí hoạt động nào).

+0

+1: cool! Có vẻ như là một lựa chọn thú vị để triển khai DSL. – Juliet

6

Một trong những nét đẹp của ngôn ngữ chức năng là các hàm bậc cao hơn. Sử dụng các chức năng đó, chúng tôi thực hiện đệ quy và chỉ tập trung vào những gì bạn thực sự muốn làm. Mà là để có được giá trị của tuple đầu tiên phù hợp định danh của bạn nếu không trở về -1:

let getValue identifier list = 
match List.tryFind (fun (x,y) -> x = identifier) list with 
    | None  -> -1 
    | Some(x,y) -> y 

//val getValue : 'a -> (('a * int) list -> int) when 'a : equality 

này paper bởi Graham Hutton thật tuyệt vời với những gì bạn có thể làm với chức năng bậc cao.

+1

* mắt phát nổ * Kiểu không điểm là thông minh, nhưng không đọc được và không thể đọc được. 'fun x -> x |> List.map fst |> List.filter (vui y -> y = identifier)' thể hiện cùng một điều mà không bị mất khả năng đọc. – Juliet

+0

Điểm chụp. Tôi hy vọng bản sửa đổi này là tốt hơn. :) –

+0

True, tryFind sẽ là sử dụng tốt nhất của ngôn ngữ kể từ khi tôi chỉ tạm thời sử dụng -1 như là một stand-in cho Không. Nhưng tôi rất vui vì tôi đã học được nhiều hơn một chút về mô hình phù hợp và ràng buộc biến. –

2

Điều bạn đang cố gắng thực hiện được gọi là mẫu bình đẳng và không được cung cấp bởi Mục tiêu Caml. Các mẫu Caml của khách quan là cấu trúc tĩnh và thuần túy. Tức là, một giá trị phù hợp với mẫu có phụ thuộc hoàn toàn vào cấu trúc của giá trị hay không và theo cách được xác định tại thời gian biên dịch. Ví dụ: (_, _)::tail là mẫu phù hợp với bất kỳ danh sách không trống nào có đầu là một cặp. (identifier, value)::tail khớp chính xác với cùng một giá trị; khác biệt duy nhất là sau này liên kết hai tên khác là identifiervalue.

Mặc dù một số ngôn ngữ có hình thức bình đẳng, có những cân nhắc thực tế không tầm thường làm cho chúng trở nên rắc rối. Bình đẳng nào? Tính bình đẳng vật lý (== trong Ocaml), bình đẳng về cấu trúc (= trong Ocaml), hoặc một số phương trình tùy chỉnh phụ thuộc vào loại? Hơn nữa, trong Ocaml, có một chỉ dẫn cú pháp rõ ràng về tên nào là các chất kết dính và tên nào được tham chiếu đến các giá trị bị ràng buộc trước đây: bất kỳ số nhận dạng chữ thường nào trong một mẫu là một chất kết dính. Hai lý do này giải thích lý do tại sao Ocaml không có các mô hình bình đẳng được nung vào. Cách thành ngữ để thể hiện một mô hình bình đẳng trong Ocaml là cảnh giác. Bằng cách đó, nó ngay lập tức rõ ràng rằng kết hợp không phải là cấu trúc, rằng identifier không bị ràng buộc bởi mô hình này phù hợp, và bình đẳng đang được sử dụng. Đối với xấu xí, đó là trong mắt của khán giả - như một lập trình viên Ocaml thói quen, tôi tìm thấy các mô hình bình đẳng xấu xí (vì những lý do trên).

match bindings with 
| (id, value)::tail when id = identifier -> value 
| (_, _)::tail -> getValue identifier tail 
| [] -> -1 

Trong F #, bạn có một khả năng: active patterns, cho phép bạn xác định trước lính gác mà liên quan đến một trang web duy nhất trong một mẫu.

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