Saya ingin mewakili wiki (satu set dokumen yang terdiri dari grafik berarah) di Dhall. Dokumen-dokumen ini akan dirender ke HTML, dan saya ingin mencegah tautan rusak dari yang pernah dibuat. Seperti yang saya lihat, ini dapat dicapai baik dengan membuat grafik yang tidak valid (grafik dengan tautan ke node yang tidak ada) tidak dapat direpresentasikan melalui sistem tipe atau dengan menulis fungsi untuk mengembalikan daftar kesalahan dalam setiap grafik yang mungkin (misalnya "Dalam grafik yang mungkin X, Node A berisi tautan ke Node B yang tidak ada ").
Representasi daftar kedekatan yang naif mungkin terlihat seperti ini:
let Node : Type = {
id: Text,
neighbors: List Text
}
let Graph : Type = List Node
let example : Graph = [
{ id = "a", neighbors = ["b"] }
]
in example
Seperti contoh ini membuat jelas, tipe ini mengakui nilai yang tidak sesuai dengan grafik yang valid (tidak ada simpul dengan id "b", tetapi simpul dengan id "a" menetapkan tetangga dengan id "b"). Selain itu, tidak mungkin untuk membuat daftar masalah ini dengan melipat tetangga dari setiap Node, karena Dhall tidak mendukung perbandingan string dengan desain.
Apakah ada representasi yang memungkinkan perhitungan daftar tautan terputus atau pengecualian tautan terputus melalui sistem tipe?
UPDATE: Saya baru saja menemukan bahwa Natur dapat dibandingkan di Dhall. Jadi saya kira suatu fungsi dapat ditulis untuk mengidentifikasi setiap tepi yang tidak valid ("tautan terputus") dan menggandakan penggunaan pengidentifikasi jika pengidentifikasi adalah Naturals.
Namun, pertanyaan awal, apakah jenis Grafik dapat ditentukan, tetap ada.
sumber
Jawaban:
Ya, Anda dapat memodelkan grafik tipe-aman, terarah, mungkin-siklik, di Dhall, seperti ini:
Representasi ini menjamin tidak adanya tepi yang patah.
Saya juga mengubah jawaban ini menjadi paket yang dapat Anda gunakan:
Sunting: Berikut adalah sumber daya yang relevan dan penjelasan tambahan yang dapat membantu menerangi apa yang sedang terjadi:
Pertama, mulai dari jenis Haskell berikut untuk pohon :
Anda dapat menganggap tipe ini sebagai struktur data yang malas dan berpotensi tak terbatas yang mewakili apa yang akan Anda dapatkan jika Anda terus mengunjungi tetangga.
Sekarang, mari kita berpura-pura bahwa
Tree
representasi di atas adalah milik kitaGraph
hanya dengan mengubah nama tipe data menjadiGraph
:... tetapi bahkan jika kita ingin menggunakan tipe ini, kita tidak memiliki cara untuk secara langsung memodelkan tipe itu di Dhall karena bahasa Dhall tidak menyediakan dukungan bawaan untuk struktur data rekursif. Jadi apa yang kita lakukan?
Untungnya, sebenarnya ada cara untuk menanamkan struktur data rekursif dan fungsi rekursif dalam bahasa non-rekursif seperti Dhall. Sebenarnya, ada dua cara!
Hal pertama yang saya baca yang memperkenalkan saya pada trik ini adalah draft postingan berikut oleh Wadler:
... tapi saya bisa meringkas ide dasar menggunakan dua jenis Haskell berikut:
... dan:
Cara itu
LFix
danGFix
bekerja adalah bahwa Anda dapat memberi mereka "satu lapisan" dari tipe rekursif atau "korekur" yang Anda inginkan (yaituf
) dan mereka kemudian memberi Anda sesuatu yang sekuat jenis yang diinginkan tanpa memerlukan dukungan bahasa untuk rekursi atau korosi. .Mari kita gunakan daftar sebagai contoh. Kami dapat memodelkan "satu lapisan" dari daftar menggunakan
ListF
jenis berikut :Bandingkan definisi itu dengan bagaimana kita biasanya mendefinisikan
OrdinaryList
definisi datatype rekursif biasa:Perbedaan utama adalah yang
ListF
mengambil satu parameter tipe ekstra (next
), yang kami gunakan sebagai pengganti untuk semua kejadian rekursif / korosif jenis.Sekarang, dilengkapi dengan
ListF
, kita dapat mendefinisikan daftar rekursif dan korosif seperti ini:... dimana:
List
adalah daftar rekursif yang diimplementasikan tanpa dukungan bahasa untuk rekursiCoList
adalah daftar korektif yang diterapkan tanpa dukungan bahasa untuk korosiKedua jenis ini setara dengan ("isomorfik dengan")
[]
, yang berarti bahwa:List
dan[]
CoList
dan[]
Mari kita buktikan dengan mendefinisikan fungsi konversi tersebut!
Jadi langkah pertama dalam mengimplementasikan tipe Dhall adalah mengubah
Graph
tipe rekursif :... dengan representasi co-rekursif yang setara:
... walaupun untuk menyederhanakan jenisnya sedikit saya merasa lebih mudah untuk mengkhususkan
GFix
pada kasus di manaf = GraphF
:Haskell tidak memiliki catatan anonim seperti Dhall, tetapi jika itu dilakukan maka kita dapat menyederhanakan jenis lebih lanjut dengan menggariskan definisi
GraphF
:Sekarang ini mulai terlihat seperti tipe Dhall untuk
Graph
, terutama jika kita gantix
dengannode
:Namun, masih ada satu bagian rumit terakhir, yaitu bagaimana menerjemahkan
ExistentialQuantification
dari Haskell ke Dhall. Ternyata Anda selalu dapat menerjemahkan kuantifikasi eksistensial ke kuantifikasi universal (yaituforall
) menggunakan kesetaraan berikut:Saya percaya ini disebut "skolemisasi"
Untuk detail lebih lanjut, lihat:
... dan trik terakhir memberi Anda jenis Dhall:
... di mana
forall (Graph : Type)
memainkan peran yang sama sepertiforall x
pada rumus sebelumnya danforall (Node : Type)
memainkan peran yang sama sepertiforall y
pada rumus sebelumnya.sumber