Das Problem ist, dass Sie einen abhängigen Quantifizierer benötigen, den Haskell derzeit nicht besitzt. I.e. der (x : A)(xs : Vec A (suc n)) → ...
Teil ist nicht direkt ausdrückbar. Sie können wahrscheinlich etwas mit Singletons kochen, aber es wird wirklich hässlich und kompliziert.
definieren würde ich nur
delete ∷ Eq a ⇒ a → Vec a (S n) → Maybe (Vec a n)
und mit ihm in Ordnung sein. Ich würde auch die Reihenfolge der Argumente zu Vec
ändern, um es möglich zu machen, Applicative
, Traversable
und andere Instanzen zur Verfügung zu stellen.
Eigentlich nein. Um delete
Sie gerade zu definieren müssen einen Index zur Verfügung zu stellen, bei dem löschen:
{-# LANGUAGE GADTs, DataKinds #-}
data Nat = Z | S Nat
data Index n where
IZ :: Index n
IS :: Index n -> Index (S n)
data Vec n a where
Nil :: Vec Z a
(:-) :: a -> Vec n a -> Vec (S n) a
delete :: Index n -> Vec (S n) a -> Vec n a
delete IZ (x :- xs) = xs
delete (IS n) (x :- (y :- xs)) = x :- delete n (y :- xs)
Beachten Sie, dass x ∈ xs
ist nichts anderes als ein reich getippt Index.
Hier ist eine Lösung mit Singletons:
{-# LANGUAGE GADTs, DataKinds, PolyKinds, KindSignatures, UndecidableInstances, TypeFamilies, RankNTypes, TypeOperators #-}
infixr 5 :-
data Nat = Z | S Nat
data family Sing (x :: a)
data instance Sing (b :: Bool) where
STrue :: Sing True
SFalse :: Sing False
data instance Sing (n :: Nat) where
SZ :: Sing Z
SS :: Sing n -> Sing (S n)
type family (:==) (x :: a) (y :: a) :: Bool
class SEq a where
(===) :: forall (x :: a) (y :: a). Sing x -> Sing y -> Sing (x :== y)
type instance Z :== Z = True
type instance S n :== Z = False
type instance Z :== S m = False
type instance S n :== S m = n :== m
instance SEq Nat where
SZ === SZ = STrue
SS n === SZ = SFalse
SZ === SS m = SFalse
SS n === SS m = n === m
data Vec xs a where
Nil :: Vec '[] a
(:-) :: Sing x -> Vec xs a -> Vec (x ': xs) a
type family If b x y where
If True x y = x
If False x y = y
type family Delete x xs where
Delete x '[] = '[]
Delete x (y ': xs) = If (x :== y) xs (y ': Delete x xs)
delete :: forall (x :: a) xs. SEq a => Sing x -> Vec xs a -> Vec (Delete x xs) a
delete x Nil = Nil
delete x (y :- xs) = case x === y of
STrue -> xs
SFalse -> y :- delete x xs
test :: Vec '[S Z, S (S (S Z)), Z] Nat
test = delete (SS (SS SZ)) (SS SZ :- SS (SS (SS SZ)) :- SS (SS SZ) :- SZ :- Nil)
Hier stellen wir Index Vec
s durch Listen ihrer Elemente und speichern Singletons als Elemente von Vektoren. Wir definieren auch SEq
, was eine Typklasse ist, die eine Methode enthält, die zwei Singletons empfängt und entweder einen Beweis der Gleichheit der von ihnen geförderten Werte oder ihre Ungleichheit zurückgibt. Als nächstes definieren wir eine Typfamilie Delete
, die wie üblich delete
für Listen ist, aber auf der Typenebene. Schließlich in der tatsächlichen delete
wir Muster übereinstimmen auf x === y
und damit offenbaren, ob x
ist gleich y
oder nicht, was die Art der Familie zu berechnen macht.
Sie können 'Entweder' verwenden, wobei' Links xs' den ursprünglichen Vektor ohne entfernte Werte darstellt und 'Rechts ...' einen neuen Vektor mit entferntem 'x' darstellt. – chepner
Ich rate nicht, mit Haskell abhängige Typen zu lernen. Haskell wurde nie als abhängig typisierte Sprache entworfen (obwohl der Fortschritt, den sie machen, bemerkenswert ist) und Tricks wie Singletons sind nichts weiter als Hacks, um zu helfen, abhängige Typen zu simulieren. Lerne die Begriffe in einer DT-Sprache wie Agda oder Idris kennen - dann wirst du die Kodierungen in Haskell viel leichter verstehen. –
Man könnte auch die Möglichkeit in Betracht ziehen, dass die für die Haskell-Bibliotheksfunktionen gewählte Schnittstelle ein Ergebnis dessen ist und dazu gedacht ist, nur für eine nicht abhängige Programmierung zu dienen.Anstatt diese Schnittstelle zu portieren, könnte man stattdessen darüber nachdenken. Ich würde niemals löschen. Ich würde die Ansicht implementieren, die Insert invertiert. – pigworker