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कि यह संपूर्ण नहीं है, क्योंकि यह उस मामले को कवर नहीं करता है जहां पीछे की सूची खाली है। अधिकांश मानक एमएल कार्यान्वयन इसके बारे में एक चेतावनी उत्पन्न करेंगे। हम जानते हैं कि पीछे की सूची संभवतः खाली नहीं हो सकती है, क्योंकि rotateपूर्व शर्त यह है कि पीछे की सूची एक तत्व सामने की धारा से अधिक लंबी है। लेकिन टाइप चेकर को पता नहीं है - और यह संभवतः नहीं जान सकता है, क्योंकि यह तथ्य एमएल के टाइप सिस्टम में अपरिहार्य है।

अभी, इस चेतावनी को दबाने का मेरा उपाय निम्नलिखित अप्रभावी हैक है:

  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

हालाँकि, मैं पूर्ण-निर्भर आश्रित प्रकार, या यहाँ तक कि GADTs, या किसी भी अन्य क्रेज़ी चीज़ों का उपयोग नहीं करना चाहता जो कुछ प्रोग्रामर उपयोग करते हैं। मैं केवल "नक्काशी बाहर" द्वारा उप-प्रकारों को परिभाषित करना चाहता हूं जो मौजूदा एमएल प्रकारों के व्यक्तिगत रूप से परिभाषित उप-समूह हैं। क्या यह संभव है?

जवाबों:


20

इस प्रकार के प्रकार - जहां आप स्वीकार्य मानों का व्याकरण देकर एक उपप्रकार (मूल रूप से) को परिभाषित करते हैं - उन्हें डेटासेट परिशोधन कहा जाता है


3
रोवन डेविस का कार्यान्वयन यहाँ उपलब्ध है: 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

आपके उत्तर के लिए धन्यवाद। मैं जीएचसी को TypeFamiliesपूरी तरह से रियायती आधारों पर नापसंद करता हूं : यह पारमार्थिकता और मुक्त सिद्धांत को नष्ट कर देता है। मैं जीएडीटी के साथ बहुत सहज नहीं हूं, क्योंकि जीएडीटी को देखते हुए Foo a, आपके पास दो आइसोमॉर्फिक प्रकार हो सकते हैं Barऔर Qux, जैसे कि Foo Barऔर आइसोमॉर्फिक Foo Quxनहीं। यह गणितीय अंतर्ज्ञान का खंडन करता है कि मानचित्र कार्य समान के बराबर होता है - और, प्रकार के स्तर पर, समतावाद समानता की सही धारणा है।
pyon

मैं आपके गुण को समझता हूं, लेकिन यह विशिष्ट सामान्यीकरण के लिए अनुमति देता है, कुछ ऐसा जो मुझे अभ्यास में काफी मूल्यवान लगता है।
शमूएल शेल्सिंगर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.