Проблема в том, что вам нужен зависимый квантор, который в настоящее время отсутствует в Haskell. То есть часть (x : A)(xs : Vec A (suc n)) → ...
прямо не выражается. Вы, вероятно, можете приготовить что-то, используя одиночные игры, но это будет очень уродливо и сложно.
Я бы просто определить
delete ∷ Eq a ⇒ a → Vec a (S n) → Maybe (Vec a n)
и хорошо с ним. Я также изменил бы порядок аргументов на Vec
, чтобы предоставить Applicative
, Traversable
и другие экземпляры.
Собственно, нет. Для того чтобы определить delete
вам просто необходимо обеспечить индекс, при котором для удаления:
{-# 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)
Обратите внимание, что x ∈ xs
является не более чем богато типизированным индекс.
Вот решение с одноплодной:
{-# 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)
Здесь индекс Vec
s по спискам их элементов и хранить одиночек в качестве элементов векторов. Мы также определяем SEq
, который является типом класса, который содержит метод, который получает два синглтона и возвращает либо доказательство равенства ценностей, которые они продвигают, либо их неравенство. Затем мы определяем семейство типов Delete
, которое, как обычно, delete
для списков, но на уровне типа. Наконец, в фактическом delete
мы сопоставляем шаблон по x === y
и таким образом показываем, равен ли x
y
или нет, что делает вычисление семейства типов.
Вы можете использовать 'Either', с' Left xs', представляющим исходный вектор без удаленных значений, и 'Right ...', представляющий новый вектор с' x' удаленным. – chepner
Я не советую использовать Haskell для изучения зависимых типов. Haskell никогда не был разработан как язык, зависящий от языка (хотя прогресс, который они делают, замечателен), а трюки, подобные синглонам, - это не что иное, как хаки, которые помогают имитировать зависимые типы. Изучите концепции на языке DT, например, Agda или Idris, - тогда вам будет намного легче понять кодировки в Haskell. –
Можно также рассмотреть возможность того, что интерфейс, выбранный для библиотечных функций Haskell, является результатом и предназначен только для того, чтобы быть полезным для программирования не зависимым образом.Вместо того, чтобы переносить этот интерфейс, можно подумать дважды об этом. Я, например, никогда не выполнил бы удаление. Я бы выполнил представление, которое инвертирует вставку. – pigworker