Okasaki'nin tamamen işlevsel veri yapıları hakkındaki kitabı hakkında sevmediğim birkaç şeyden biri, kodunun kapsamlı olmayan desen eşleşmesi ile doludur. Örnek olarak, gerçek zamanlı kuyruklar uygulamasını uygulayacağım (gereksiz askıya alma işlemlerini ortadan kaldırmak için yeniden düzenlendi):
infixr 5 :::
datatype 'a stream = Nil | ::: of 'a * 'a stream lazy
structure RealTimeQueue :> QUEUE =
struct
(* front stream, rear list, schedule stream *)
type 'a queue = 'a stream * 'a list * 'a stream
(* the front stream is one element shorter than the rear list *)
fun rotate (x ::: $xs, y :: ys, zs) = x ::: $rotate (xs, ys, y ::: $zs)
| rotate (Nil, y :: nil, zs) = y ::: $zs
fun exec (xs, ys, _ ::: $zs) = (xs, ys, zs)
| exec args = let val xs = rotate args in (xs, nil, xs) end
(* public operations *)
val empty = (Nil, nil, Nil)
fun snoc ((xs, ys, zs), y) = exec (xs, y :: ys, zs)
fun uncons (x ::: $xs, ys, zs) = SOME (x, exec (xs, ys, zs))
| uncons _ = NONE
end
Görülebileceği gibi rotate
ayrıntılı değildir, çünkü arka listenin boş olduğu durumu kapsamaz. Çoğu Standart ML uygulaması bu konuda bir uyarı oluşturur. Biz , çünkü arka liste muhtemelen boş olamaz biliyoruz rotate
bireyin ön şart olduğunu arka liste bir unsuru uzun ön akışında aşıyor. Ancak tip denetleyicisi bilmiyor - ve muhtemelen bilmiyor, çünkü bu gerçek ML'nin tip sisteminde ifade edilemez.
Şu anda, bu uyarıyı bastırmak için benim çözümüm şu yetersiz kesmek:
fun rotate (x ::: $xs, y :: ys, zs) = x ::: $rotate (xs, ys, y ::: $zs)
| rotate (_, ys, zs) = foldl (fn (x, xs) => x ::: $xs) zs ys
Ama gerçekten istediğim, her üçlünün geçerli bir argüman olmadığını anlayabilen bir tür sistem rotate
. Yazı sistemini aşağıdaki gibi tanımlamama izin vermek istiyorum:
type 'a triplet = 'a stream * 'a list * 'a stream
subtype 'a queue of 'a triplet
= (Nil, nil, Nil)
| (xs, ys, zs) : 'a queue => (_ ::: $xs, _ :: ys, zs)
| (xs, ys, zs) : 'a queue => (_ ::: $xs, ys, _ ::: $zs)
Ve sonra çıkarımda bulunun:
subtype 'a rotatable of 'a triplet
= (xs, ys, _) : 'a rotatable => (_ ::: $xs, _ :: ys, _)
| (Nil, y :: nil, _)
subtype 'a executable of 'a triplet
= (xs, ys, zs) : 'a queue => (xs, ys, _ ::: $zs)
| (xs, ys, Nil) : 'a rotatable => (xs, ys, Nil)
val rotate : 'a rotatable -> 'a stream
val exec : 'a executable -> 'a queue
Ancak, tam gelişmiş bağımlı türler, hatta GADT'ler veya bazı programcıların kullandığı diğer çılgın şeyleri istemiyorum. Sadece mevcut ML tiplerinin indüktif olarak tanımlanmış alt kümelerini “yaparak” alt tipleri tanımlamak istiyorum. Bu uygulanabilir mi?