Stichworte von getaggten Gewerkschaften sollten erstklassige Werte sein, und mit ein bisschen Mühe sind sie.
Schmu Alarm:
{-# LANGUAGE GADTs, DataKinds, KindSignatures,
TypeFamilies, PolyKinds, FlexibleInstances,
PatternSynonyms
#-}
Erster Schritt: Typ-Level-Versionen der Tags definieren.
Schritt zwei: Definieren Sie Zeugen auf Werteebene für die Darstellbarkeit der Tags auf Textebene. Richard Eisenbergs Singletons-Bibliothek wird dies für Sie tun. Ich meine etwas in der Art:
data Tag :: TagType -> * where
EmptyT :: Tag EmptyTag
SingleT :: Tag SingleTag
PairT :: Tag PairTag
LotsT :: Tag LotsTag
Und jetzt können wir sagen, welche Sachen, die wir erwarten, mit einem gegebenen Tag verbunden zu finden.
type family Stuff (t :: TagType) :: * where
Stuff EmptyTag =()
Stuff SingleTag = Int
Stuff PairTag = (Int, Int)
Stuff LotsTag = [Int]
So können wir die Art du erster Gedanke von
data NumCol :: * where
(:&) :: Tag t -> Stuff t -> NumCol
und PatternSynonyms
das Verhalten zu erholen verwenden Refactoring Sie im Sinn hatte:
pattern Empty = EmptyT :& ()
pattern Single i = SingleT :& i
pattern Pair i j = PairT :& (i, j)
pattern Lots is = LotsT :& is
So was passiert ist, dass jeder Konstruktor für NumCol
hat sich in ein Tag verwandelt, das nach der Art des Tags indiziert ist. Das heißt, Konstruktortags leben nun getrennt von den übrigen Daten, synchronisiert durch einen gemeinsamen Index, der sicherstellt, dass das mit einem Tag verbundene Material mit dem Tag selbst übereinstimmt.
Aber wir können über Tags allein sprechen.
data Ex :: (k -> *) -> * where -- wish I could say newtype here
Witness :: p x -> Ex p
Nun Ex Tag
, ist die Art der "Laufzeit-Tags mit einem Typ-Ebene Pendant". Es hat eine Eq
Instanz
instance Eq (Ex Tag) where
Witness EmptyT == Witness EmptyT = True
Witness SingleT == Witness SingleT = True
Witness PairT == Witness PairT = True
Witness LotsT == Witness LotsT = True
_ == _ = False
Darüber hinaus können wir den Tag eines NumCol
leicht extrahieren.
numColTag :: NumCol -> Ex Tag
numColTag (n :& _) = Witness n
Und das erlaubt uns, Ihre Spezifikation zu erfüllen.
filter ((Witness PairT ==) . numColTag) :: [NumCol] -> [NumCol]
Das wirft die Frage auf, ob Ihre Spezifikation tatsächlich das ist, was Sie brauchen. Der Punkt ist, dass das Erkennen eines Tags Ihnen eine Erwartung des Tags dieses Tags gibt. Die Ausgabeart [NumCol]
wird der Tatsache nicht gerecht, dass Sie wissen, dass Sie nur die Paare haben.
Wie könnten Sie den Typ Ihrer Funktion verschärfen und trotzdem liefern?
Ah, List-Filter-via-Muster-Matching. Dies ist eine der wenigen Tugenden, die "scheitern" lassen. –
@DanBurton Nun, technisch verwendet das nicht "fail", da Listen-Comprehensions eine separat beschriebene Entschuldigung aus "Do" -Notation haben. Und ich bin mir sicher, dass sie lieber das 'do' ändern, das' mzero' verwendet, als es direkt zu löschen. –
Was genau passiert in der ersten Funktion 'get_pairs' Was bedeutet die Syntax' {} '? Ich habe nur geschweifte Klammern in "Record Syntax" gesehen – lsund