Рассмотрим простое определение вектора, проиндексированного по длине:
data Nat = Z | S Nat
infixr 5 :>
data Vec (n :: Nat) a where
V0 :: Vec 'Z a
(:>) :: a -> Vec n a -> Vec ( n) a
Естественно, мне в какой-то момент понадобится следующая функция:
vec2list :: Vec n a -> [a]
Однако эта функция действительно просто причудливая идентичность. Я считаю, что представления во время выполнения этих двух типов одинаковы, поэтому
vec2list :: Vec n a -> [a]
vec2list = unsafeCoerce
должен работать. Увы, это не так:
>vec2list ('a' :> 'b' :> 'c' :> V0)
""
Каждый вход просто возвращает пустой список. Поэтому я полагаю, что моего понимания не хватает. Чтобы проверить его, я определяю следующее:
data List a = Nil | Cons a (List a) deriving (Show)
vec2list' :: Vec n a -> List a
vec2list' = unsafeCoerce
test1 = vec2list' ('a' :> 'b' :> 'c' :> V0)
data SomeVec a = forall n . SomeVec (Vec n a)
list'2vec :: List a -> SomeVec a
list'2vec x = SomeVec (unsafeCoerce x)
Удивительно, но это работает! Конечно, это не проблема с GADT (моя первоначальная мысль).
Я думаю, что тип List
действительно идентичен во время выполнения до []
. Я также пытаюсь проверить это:
list2list :: [a] -> List a
list2list = unsafeCoerce
test2 = list2list "abc"
и он работает! Исходя из этого факта, я должен заключить, что [a]
и List a
должны иметь одинаковое представление времени исполнения. И все же, следующие
list2list' :: List a -> [a]
list2list' = unsafeCoerce
test3 = list2list' (Cons 'a' (Cons 'b' (Cons 'c' Nil)))
не работает. list2list'
снова всегда возвращает пустой список. Я считаю, что "наличие идентичных представлений времени исполнения" должно быть симметричным отношением, поэтому это не имеет смысла.
Я начал думать, может быть, что-то смешное с "примитивными" типами, но я всегда считал, что []
является только синтаксически, а не семантически. Кажется, что случай:
data Pair a b = Pair a b deriving (Show, Eq, Ord)
tup2pair :: (a,b) -> Pair a b
tup2pair = unsafeCoerce
pair2tup :: Pair a b -> (a,b)
pair2tup = unsafeCoerce
Первая функция работает, а вторая - не такая же, как в случае List
и []
. Хотя в этом случае pair2tup
segfaults, а не всегда возвращает пустой список.
Кажется, он асимметричен по отношению к типам, которые используют "встроенный" синтаксис. Вернемся к примеру Vec
, следуя
list2vec :: [a] -> SomeVec a
list2vec x = SomeVec (unsafeCoerce x)
отлично работает! GADT действительно не особенный.
Вопрос: как представления представления типов, которые используют "встроенный" синтаксис, отличаются от тех, которые этого не делают?
В качестве альтернативы, как написать однозадачное принуждение от Vec n a
до [a]
? Это не отвечает на вопрос, но решает проблему.
Тестирование проводилось с помощью GHC 7.10.3.
Как заметил комментатор, это поведение присутствует только при интерпретации. При компиляции все функции работают должным образом. Вопрос по-прежнему применяется, только для представления времени выполнения при интерпретации.