Berikut adalah tiga bahasa yang memungkinkan Anda menentukan operator Anda sendiri, yang melakukan dua setengah hal berbeda ! Haskell dan Coq sama-sama tidak mengizinkan shenanigans semacam ini - tetapi berbeda - sementara Agda memungkinkan pencampuran asosiasi ini.
Pertama, di Haskell , Anda tidak diizinkan melakukan ini. Anda dapat menentukan operator Anda sendiri dan memberi mereka prioritas (dari 0–9) dan asosiasi pilihan Anda. Namun, Laporan Haskell melarang Anda dari pencampuran asosiasi :
Operator tidak berurutan berturut-turut dengan prioritas yang sama harus keduanya asosiatif kiri atau kanan untuk menghindari kesalahan sintaksis. [Laporan Haskell 2010, Ch. 3]
Jadi, dalam GHC , jika kita mendefinisikan infixl
operator asosiasi kiri ( ) <@
dan operator asosiasi kanan @>
pada tingkat prioritas yang sama - katakanlah 0 - maka evaluasi x <@ y @> z
memberikan kesalahan
Kesalahan penguraian yang didahului
tidak dapat mencampur ' <@
' [ infixl 0
] dan ' @>
' [ infixr 0
] dalam ekspresi infiks yang sama
(Bahkan, Anda juga dapat mendeklarasikan operator sebagai infix tetapi non-asosiatif, seperti ==
, jadi itu x == y == z
adalah kesalahan sintaks!)
Di sisi lain, ada bahasa pengantar / teorema bertipe dependen Agda (yang, memang, dianggap kurang mainstream). Agda memiliki beberapa sintaks yang paling bisa ditiru dari bahasa apa pun yang saya tahu, mendukung operator mixfix : pustaka standar berisi fungsi
if_then_else_ : ∀ {a} {A : Set a} → Bool → A → A → A
yang, ketika dipanggil, ditulis
if b then t else f
dengan argumen yang mengisi garis bawah! Saya menyebutkan ini karena ini berarti harus mendukung parsing yang sangat fleksibel. Tentu, Agda juga memiliki deklarasi ketetapan (meskipun tingkat diutamakan yang berkisar bilangan lebih sewenang-wenang, dan biasanya di 0-100), dan Agda tidak mengizinkan Anda untuk mencampur operator didahulukan sama tetapi jepit yang berbeda. Namun, saya tidak dapat menemukan informasi tentang ini di dokumentasi, jadi saya harus bereksperimen.
Mari kita gunakan kembali <@
dan @>
dari atas. Dalam dua kasus sederhana, kita punya
x <@ y @> z
parsing sebagai x <@ (y @> z)
; dan
x @> y <@ z
parsing sebagai (x @> y) <@ z
.
Saya pikir apa yang dilakukan Agda adalah mengelompokkan garis menjadi potongan "asosiatif kiri" dan "asosiatif kanan", dan - kecuali jika saya memikirkan hal-hal yang salah - potongan asosiatif kanan mendapat "prioritas" dalam meraih argumen yang berdekatan. Jadi itu memberi kita
a <@ b <@ c @> d @> e @> f <@ g
parsing sebagai
(((a <@ b) <@ (c @> (d @> (e @> f)))) <@ g
atau
Namun, meskipun saya bereksperimen, saya salah menebak pertama kali saya menulis itu, yang mungkin bersifat instruktif :-)
(Dan Agda, seperti Haskell, memiliki operator non-asosiatif, yang dengan benar memberikan kesalahan parse, sehingga dimungkinkan untuk gabungan asosiatif untuk menghasilkan kesalahan parse juga.)
Akhirnya, ada teorema-prover / bahasa dependen-diketik Coq , yang memiliki bahkan sintaks yang lebih fleksibel daripada Agda karena ekstensi sintaks benar-benar diterapkan dengan memberikan spesifikasi untuk konstruksi sintaksis baru dan kemudian menulis ulang mereka ke dalam bahasa inti (samar-samar makro seperti , Saya seharusnya). Dalam Coq, sintaksis daftar [1; 2; 3]
adalah impor opsional dari pustaka standar. Sintaks baru bahkan dapat mengikat variabel!
Sekali lagi, dalam Coq, kita dapat mendefinisikan operator infiks kita sendiri dan memberi mereka tingkat prioritas (dari 0–99, sebagian besar) dan asosiatifitas. Namun, dalam Coq, setiap tingkat diutamakan hanya dapat memiliki satu asosiatif . Jadi jika kita mendefinisikan <@
sebagai asosiatif kiri dan kemudian mencoba mendefinisikan @>
sebagai asosiatif kanan pada tingkat yang sama - katakan, 50 - kita mendapatkan
Kesalahan: Level 50 sudah dinyatakan asosiatif kiri sementara sekarang diharapkan asosiatif benar
Sebagian besar operator dalam Coq berada pada level yang dapat dibagi 10; jika saya mempunyai masalah asosiatif (level asosiasi ini bersifat global), saya pada umumnya hanya menabrak level tersebut satu per satu arah (biasanya naik).