ชนิดย่อยเป็นชุดย่อยของประเภทข้อมูล SML


10

หนึ่งในสองสามสิ่งที่ฉันไม่ชอบเกี่ยวกับหนังสือของโอกาซากิในโครงสร้างข้อมูลที่ใช้งานได้อย่างหมดจดคือโค้ดของเขาเกลื่อนไปด้วยการจับคู่รูปแบบที่ไม่สิ้นสุด ตัวอย่างเช่นฉันจะให้การใช้คิวแบบเรียลไทม์ของเขา (ปรับปรุงใหม่เพื่อกำจัดการระงับที่ไม่จำเป็น):

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

อย่างที่เห็นrotateไม่หมดแรงเพราะมันไม่ครอบคลุมกรณีที่รายการด้านหลังว่างเปล่า การใช้งาน ML มาตรฐานส่วนใหญ่จะสร้างคำเตือนเกี่ยวกับมัน เรารู้ว่ารายการด้านหลังไม่สามารถว่างเปล่าได้เนื่องจากrotateเงื่อนไขเบื้องต้นคือรายการด้านหลังยาวกว่าส่วนหน้า แต่ตัวตรวจสอบชนิดไม่ทราบ - และไม่สามารถรู้ได้เพราะข้อเท็จจริงนี้ไม่สามารถอธิบายได้ในระบบประเภทของ ML

ตอนนี้ทางออกของฉันเพื่อระงับคำเตือนนี้คือแฮ็คที่ไม่เหมาะสมต่อไปนี้:

  fun rotate (x ::: $xs, y :: ys, zs) = x ::: $rotate (xs, ys, y ::: $zs)
    | rotate (_, ys, zs) = foldl (fn (x, xs) => x ::: $xs) zs ys

rotateแต่สิ่งที่ผมต้องการคือระบบการพิมพ์ที่สามารถเข้าใจว่าไม่ทุกแฝดเป็นข้อโต้แย้งที่ถูกต้อง ฉันต้องการระบบประเภทเพื่อให้ฉันกำหนดประเภทเช่น:

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)

แล้วสรุป:

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

อย่างไรก็ตามฉันไม่ต้องการประเภทที่ขึ้นอยู่กับการระเบิดเต็มรูปแบบหรือแม้กระทั่ง GADT หรือสิ่งอื่น ๆ ที่โปรแกรมเมอร์ใช้ ฉันแค่ต้องการกำหนดประเภทย่อยโดย“ แกะสลัก” ชุดย่อยที่กำหนดแบบเหนี่ยวนำของ ML ประเภทที่มีอยู่ เป็นไปได้หรือไม่

คำตอบ:


20

ประเภทเหล่านี้ - ที่คุณกำหนดประเภทย่อย (โดยทั่วไป) โดยให้ไวยากรณ์ของค่าที่ยอมรับได้ - เรียกว่าการปรับแต่งข้อมูล

  • พวกเขาได้รับการแนะนำให้รู้จักทิมฟรีแมนและแฟรงก์ Pfenning, ในปี 1991 กระดาษ PLDI ของพวกเขาประเภทการปรับแต่งสำหรับ ML

  • โรเดวีส์ศึกษาอนุมานชนิดประเภทการปรับแต่งในวิทยานิพนธ์ปริญญาเอกของเขาในทางปฏิบัติการปรับแต่งประเภทการตรวจสอบ เขายังนำมันไปใช้เป็นส่วนขยายให้กับ SML แต่ฉันไม่รู้ว่ามันมีอยู่ในระบบออนไลน์หรือไม่

  • โจชัว Dunfield ศึกษาวิธีการรวมการปรับแต่ง datasort มีประเภทการพึ่งพาน้ำหนักเบานักเล่นในวิทยานิพนธ์ของเขาแบบครบวงจรระบบประเภทการปรับแต่ง นอกจากนี้เขายังนำไปใช้เป็นภาษาสตาร์ดัสต์ซึ่งสามารถใช้งานออนไลน์ได้:

    http://www.mpi-sws.org/~joshua/stardust/


3
การใช้งานของ Rowan Davies มีให้ที่นี่: github.com/rowandavies/sml-cidre
Noam Zeilberger

1

ฉันสามารถใช้ GADTs, TypeFamilies, DataKinds และ TypeOperators (เพียงเพื่อความสวยงาม) และสร้างสิ่งที่คุณต้องการ:

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

ขอบคุณสำหรับคำตอบ. ฉันไม่ชอบ GHC TypeFamiliesอย่างหมดจดในพื้นที่ที่มีหลักการ: มันทำลายพารามิเตอร์และทฤษฎีบทเสรี ฉันก็ไม่พอใจ GADT เช่นกันเพราะได้รับ GADT Foo aคุณสามารถมี isomorphic สองประเภทBarและQuxเช่นนั้นFoo BarและFoo Quxไม่ใช่ isomorphic ที่ขัดแย้งกับสัญชาตญาณทางคณิตศาสตร์ที่ทำหน้าที่แผนที่เท่ากับเท่ากับ - และที่ระดับประเภท isomorphism เป็นแนวคิดที่ถูกต้องของความเท่าเทียมกัน
pyon

ฉันเข้าใจคุณวุฒิของคุณ แต่มันช่วยให้เห็นภาพรวมเฉพาะสิ่งที่ฉันคิดว่ามีประโยชน์ในทางปฏิบัติ
ซามูเอลชเลซิงเจอร์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.