Các kiểu con là tập hợp con của kiểu dữ liệu SML


10

Một trong số ít những điều mà tôi không thích về cuốn sách của Okasaki về các cấu trúc dữ liệu chức năng thuần túy là mã của anh ta bị lấp đầy bởi sự phù hợp với mô hình không đầy đủ. Ví dụ, tôi sẽ cho anh ta thực hiện các hàng đợi thời gian thực (được tái cấu trúc để loại bỏ các đình chỉ không cần thiết):

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

Như có thể thấy rotatelà không đầy đủ, bởi vì nó không bao gồm trường hợp danh sách phía sau trống. Hầu hết các triển khai ML tiêu chuẩn sẽ tạo ra một cảnh báo về nó. Chúng tôi biết rằng danh sách phía sau có thể trống, bởi vì rotateđiều kiện tiên quyết là danh sách phía sau dài hơn một phần tử so với luồng phía trước. Nhưng trình kiểm tra loại không biết - và không thể biết được, vì thực tế này không thể diễn tả được trong hệ thống loại ML.

Ngay bây giờ, giải pháp của tôi để ngăn chặn cảnh báo này là hack không liên tục sau đây:

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

Nhưng những gì tôi thực sự muốn là một hệ thống loại có thể hiểu rằng không phải mọi bộ ba là một đối số hợp lệ rotate. Tôi muốn hệ thống loại cho phép tôi xác định các loại như:

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)

Và sau đó suy ra:

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

Tuy nhiên, tôi không muốn các loại phụ thuộc toàn diện, hoặc thậm chí GADT, hoặc bất kỳ thứ điên rồ nào khác mà các lập trình viên nhất định sử dụng. Tôi chỉ muốn xác định các kiểu con bằng cách khắc ra các tập hợp con được xác định theo quy tắc của các kiểu ML hiện có. Điều này có khả thi không?

Câu trả lời:


20

Các loại loại này - nơi bạn xác định một kiểu con (về cơ bản) bằng cách đưa ra một ngữ pháp của các giá trị có thể chấp nhận - được gọi là các sàng lọc dữ liệu .


3
Triển khai của Rowan Davies có sẵn tại đây: github.com/rowandavies/sml-cidre
Noam Zeilberger

1

Tôi có thể sử dụng GADT, TypeFamflower, DataKinds và TypeOperators (chỉ để thẩm mỹ) và tạo ra những gì bạn đang theo đuổi:

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

Cảm ơn câu trả lời của bạn. Tôi không thích GHC TypeFamilieshoàn toàn dựa trên nguyên tắc: nó phá hủy tính chất tham số và định lý tự do. Tôi cũng không quá thoải mái với GADT, vì được cấp GADT Foo a, bạn có thể có hai loại đẳng cấu BarQuxnhư vậy Foo BarFoo Quxkhông phải là đẳng cấu. Điều đó mâu thuẫn với trực giác toán học có chức năng ánh xạ bằng với - và, ở cấp độ loại, đẳng cấu là khái niệm đúng về đẳng thức.
pyon

Tôi hiểu đức tính của bạn, nhưng nó cho phép khái quát hóa chuyên ngành, một điều mà tôi thấy khá có giá trị trong thực tế.
Samuel Schlesinger
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.