Я хочу разработать функцию типа безопасного подстановка для следующего типа данных:Тип безопасный поиск гетерогенных списков в Haskell
data Attr (xs :: [(Symbol,*)]) where
Nil :: Attr '[]
(:*) :: KnownSymbol s => (Proxy s, t) -> Attr xs -> Attr ('(s , t) ': xs)
Очевидная функция поиска будет, как:
lookupAttr :: (KnownSymbol s, Lookup s env ~ 'Just t) => Proxy s -> Attr env -> t
lookupAttr s ((s',t) :* env')
= case sameSymbol s s' of
Just Refl -> t
Nothing -> lookupAttr s env'
где Lookup
тип семейства определяется в библиотеке одиночек. Это определение не удается ввести проверку на GHC 7.10.3 со следующим сообщением об ошибке:
Could not deduce (Lookup s xs ~ 'Just t)
from the context (KnownSymbol s, Lookup s env ~ 'Just t)
bound by the type signature for
lookupAttr :: (KnownSymbol s, Lookup s env ~ 'Just t) =>
Proxy s -> Attr env -> t
Это сообщение генерируется для рекурсивного вызова lookupAttr s env'
. Это разумно, так как мы имеем, что если
Lookup s ('(s',t') ': env) ~ 'Just t
держит, и
s :~: s'
не доказуемо, то
Lookup s env ~ 'Just t
должен держать. Мой вопрос: как я могу убедить проверку типа Haskell, что это действительно так?
Где именно находится 'sameSymbol'? Это из библиотеки синглтонов? – Kwarrtz
О, неважно. Найден его в [GHC.TypeLits] (https://hackage.haskell.org/package/base-4.8.2.0/docs/GHC-TypeLits.html). – Kwarrtz
При использовании строк для представления связанных переменных вы платите значительную цену за сложность реализации языка. Захват, избегающий замещения и альфа-эквивалентности, как известно, сложно сделать правильно, не говоря уже о стоимости битвы с довольно заторможенной реализацией «Символа» в GHC. Если вы создаете встроенный DSL-тип, который, как мне кажется, вам следует серьезно рассмотреть [HOAS] (https://en.wikipedia.org/wiki/Higher-order_abstract_syntax) в качестве более простой альтернативы. –