SML veri türlerinin alt kümeleri olarak alt türler


10

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 rotateayrı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 rotatebireyin ö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?

Yanıtlar:


20

Bu tür türlere - kabul edilebilir değerlerin gramerini vererek bir alt türü (temel olarak) tanımladığınız - bu tür veri veri ayrıntılandırmaları olarak adlandırılır .


3
Rowan Davies'in uygulaması burada mevcuttur: github.com/rowandavies/sml-cidre
Noam Zeilberger

1

GADT'leri, TypeFamilies, DataKinds ve TypeOperators (sadece estetik için) kullanabilir ve sonra ne var oluşturmak:

data Term0 varb lamb letb where
    Lam :: lamb -> Term0 varb lamb letb -> Term0 varb lamb letb
    Let :: letb -> Term0 varb lamb letb -> Term0 varb lamb letb -> Term0 varb lamb letb
    Var :: varb -> Term0 varb lamb letb
    App :: Term0 varb lamb letb -> Term0 varb lamb letb -> Term0 varb lamb letb

type Term b = Term0 b b b

data Terms = Lets | Lams | Vars

type family  t /// (ty :: Terms) where
    Term0 a b c /// Vars = Term0 Void b c
    Term0 a b c /// Lams = Term0 a Void c
    Term0 a b c /// Lets = Term0 a b Void

Now, I can write functions with more refined types:

unlet :: Term b -> Term b /// Lets

Cevabınız için teşekkürler. GHC'nin TypeFamiliesyalnızca ilkeli temellerden hoşlanmıyorum : parametrikliği ve serbest teoremleri yok ediyor. Ayrıca GADT'lerle çok rahat değilim, çünkü bir GADT verildiğinde Foo a, iki izomorfik tipiniz olabilir Barve Quxöyle Foo Barve Foo Quxizomorfik değilsiniz. Bu, haritanın işlevlerini yerine getiren matematiksel sezgilerle eşittir - ve tip düzeyinde, izomorfizm eşitlik nosyonudur.
pyon

Niteliklerinizi anlıyorum, ancak uygulamada oldukça değerli bulduğum bir şey olan özel genellemelere izin veriyor.
Samuel Schlesinger
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.