Dưới đây là ba ngôn ngữ cho phép bạn xác định toán tử của riêng mình, chúng thực hiện hai điều rưỡi khác nhau ! Cả Haskell và Coq đều không cho phép các loại shenanigans này - nhưng khác nhau - trong khi Agda cho phép loại hỗn hợp này của sự kết hợp.
Đầu tiên, trong Haskell , bạn chỉ đơn giản là không được phép làm điều này. Bạn có thể xác định các toán tử của riêng bạn và ưu tiên cho chúng (từ 0 Lỗi9) và tính kết hợp của sự lựa chọn của bạn. Tuy nhiên, Báo cáo Haskell không cho phép bạn trộn lẫn các kết hợp :
Các toán tử không liên kết liên tiếp có cùng mức ưu tiên phải là liên kết trái hoặc phải để tránh lỗi cú pháp. [Báo cáo Haskell 2010, Ch. 3]
Vì vậy, trong GHC , nếu chúng ta xác định infixl
toán tử liên kết trái ( ) <@
và toán tử liên kết phải @>
ở cùng mức ưu tiên - giả sử 0 - thì việc đánh giá x <@ y @> z
sẽ đưa ra lỗi
Lỗi phân tích cú pháp ưu tiên
không thể trộn ' <@
' [ infixl 0
] và ' @>
' [ infixr 0
] trong cùng một biểu thức infix
(Trên thực tế, bạn cũng có thể khai báo một toán tử là infix nhưng không liên kết, như ==
vậy, đó x == y == z
là một lỗi cú pháp!)
Mặt khác, có ngôn ngữ / định lý ngôn ngữ được gõ phụ thuộc Agda (mà, thừa nhận, là ít chính thống hơn đáng kể). Agda có một số cú pháp dễ uốn nhất của bất kỳ ngôn ngữ nào tôi biết, hỗ trợ các toán tử mixfix : thư viện chuẩn chứa hàm
if_then_else_ : ∀ {a} {A : Set a} → Bool → A → A → A
trong đó, khi được gọi, được viết
if b then t else f
với các đối số điền vào dấu gạch dưới! Tôi đề cập đến điều này bởi vì điều này có nghĩa là nó phải hỗ trợ phân tích cú pháp cực kỳ linh hoạt. Đương nhiên, Agda cũng có các khai báo tính cố định (mặc dù các mức độ ưu tiên của nó nằm trên các số tự nhiên tùy ý và thường ở 0 0100100) và Agda cho phép bạn kết hợp các toán tử có cùng mức ưu tiên nhưng các mức độ cố định khác nhau. Tuy nhiên, tôi không thể tìm thấy thông tin về điều này trong tài liệu, vì vậy tôi phải thử nghiệm.
Hãy sử dụng lại của chúng tôi <@
và @>
từ trên cao. Trong hai trường hợp đơn giản, chúng ta có
x <@ y @> z
phân tích cú pháp như x <@ (y @> z)
; và
x @> y <@ z
phân tích cú pháp như (x @> y) <@ z
.
Tôi nghĩ những gì Agda làm là nhóm dòng thành các phần "liên kết bên trái" và "liên kết bên phải", và - trừ khi tôi nghĩ về những điều sai trái - phần liên kết bên phải được "ưu tiên" trong việc nắm bắt các lập luận liền kề. Vì vậy, nó mang lại cho chúng tôi
a <@ b <@ c @> d @> e @> f <@ g
phân tích như
(((a <@ b) <@ (c @> (d @> (e @> f)))) <@ g
hoặc là
Tuy nhiên, mặc dù thử nghiệm của tôi, tôi đã đoán sai lần đầu tiên tôi viết nó ra, điều này có thể mang tính hướng dẫn :-)
.
Cuối cùng, có Coq ngôn ngữ prover-prover / gõ phụ thuộc , có cú pháp linh hoạt hơn Agda vì các phần mở rộng cú pháp của nó thực sự được thực hiện bằng cách đưa ra các đặc tả cho các cấu trúc cú pháp mới và sau đó viết lại chúng thành ngôn ngữ cốt lõi (giống như macro một cách mơ hồ , Tôi giả sử). Trong Coq, cú pháp danh sách [1; 2; 3]
là nhập tùy chọn từ thư viện chuẩn. Cú pháp mới thậm chí có thể liên kết các biến!
Một lần nữa, trong Coq, chúng ta có thể xác định các toán tử infix của riêng mình và cung cấp cho chúng các mức độ ưu tiên (từ 0, 99, chủ yếu) và các kết hợp. Tuy nhiên, trong Coq, mỗi cấp độ ưu tiên chỉ có thể có một kết hợp . Vì vậy, nếu chúng ta xác định <@
là liên kết trái và sau đó cố gắng xác định @>
là liên kết phải ở cùng cấp - giả sử, 50 - chúng ta nhận được
Lỗi: Cấp 50 đã được khai báo kết hợp bên trái trong khi hiện tại dự kiến sẽ là liên kết bên phải
Hầu hết các nhà khai thác trong Coq đều ở mức chia hết cho 10; nếu tôi gặp vấn đề về sự kết hợp (những sự kết hợp cấp độ này là toàn cầu), thì tôi thường chỉ vượt qua cấp độ một trong hai hướng (thường là lên).