Masalah
Pertimbangkan masalah desain berikut ini di Haskell. Saya memiliki, EDSL simbolis sederhana di mana saya ingin mengekspresikan variabel dan ekspresi umum (polinomial multivariat) seperti x^2 * y + 2*z + 1
. Selain itu, saya ingin mengekspresikan persamaan simbolik tertentu atas ekspresi, katakanlah x^2 + 1 = 1
, serta definisi , seperti x := 2*y - 2
.
Tujuannya adalah untuk:
- Memiliki tipe terpisah untuk variabel dan ekspresi umum - fungsi tertentu mungkin diterapkan pada variabel dan bukan ekspresi kompleks. Misalnya, operator definisi
:=
mungkin bertipe(:=) :: Variable -> Expression -> Definition
dan seharusnya tidak mungkin untuk melewatkan ekspresi kompleks sebagai parameter sisi kiri (meskipun harus mungkin untuk melewatkan variabel sebagai parameter sisi kanannya, tanpa casting eksplisit ) . - Buatlah ekspresi dari instance
Num
, sehingga dimungkinkan untuk mempromosikan literal integer ke ekspresi dan menggunakan notasi yang nyaman untuk operasi aljabar umum seperti penambahan atau perkalian tanpa memperkenalkan beberapa operator pembungkus tambahan.
Dengan kata lain, saya ingin memiliki tipe cast (paksaan) variabel implisit dan statis untuk ekspresi. Sekarang, saya tahu bahwa dengan demikian, tidak ada gips tipe implisit di Haskell. Namun demikian, konsep pemrograman berorientasi objek tertentu (pewarisan sederhana, dalam hal ini) dapat diekspresikan dalam sistem tipe Haskell, baik dengan atau tanpa ekstensi bahasa. Bagaimana saya bisa memenuhi kedua poin di atas sambil mempertahankan sintaksis yang ringan? Apakah itu mungkin?
Diskusi
Jelas bahwa masalah utama di sini adalah Num
pembatasan jenis, misalnya
(+) :: Num a => a -> a -> a
Pada prinsipnya, dimungkinkan untuk menulis tipe data aljabar tunggal (umum) untuk variabel dan ekspresi. Kemudian, orang dapat menulis :=
sedemikian rupa, sehingga ungkapan sisi kiri didiskriminasi dan hanya konstruktor variabel yang diterima, dengan kesalahan run-time sebaliknya. Namun itu bukan solusi yang bersih, statis (mis. Waktu kompilasi) ...
Contoh
Idealnya, saya ingin mencapai sintaks yang ringan seperti
computation = do
x <- variable
t <- variable
t |:=| x^2 - 1
solve (t |==| 0)
Secara khusus, saya ingin melarang notasi seperti
t + 1 |:=| x^2 - 1
karena :=
harus memberikan definisi variabel dan bukan seluruh ekspresi sisi kiri.
FromVar
typeclass akan membantu. Saya ingin menghindari gips secara eksplisit sambil menjaga Expr
instance Num
. Saya mengedit pertanyaan dengan menambahkan contoh notasi yang ingin saya capai.
class FromVar e
dengan metodefromVar :: Variable -> e
dan memberikan contoh untukExpression
danVariable
, kemudian variabel Anda memiliki tipe polimorfikx :: FromVar e => e
dll. Saya belum menguji seberapa baik ini bekerja karena saya di ponsel saya sekarang.