Другие предполагают изменение структуры данных, здесь другое Подход с использованием модели синонимов:
{-# Language GADTs, PatternSynonyms, ViewPatterns, TypeOperators #-}
import Data.Kind
data MyURL a where
GalleryURL :: URL -> MyURL URL
PictureURL :: URL -> MyURL URL
url :: MyURL a -> URL
url (GalleryURL u) = u -- Proof that: URL ~ a
url (PictureURL u) = u -- Proof that: URL ~ a
-- Works on ‘MyURL a’ for any ‘a’
pattern Url :: URL -> MyURL a
pattern Url u <- (url -> u)
Если другой конструктор добавить, что не содержит URL
мы должны добавить случай отказа для url
data MyURL a where
GalleryURL :: URL -> MyURL URL
PictureURL :: URL -> MyURL URL
I :: Int -> MyURL Int
url :: MyURL a -> Maybe URL
url (GalleryURL u) = Just u -- Proof that: URL ~ a
url (PictureURL u) = Just u -- Proof that: URL ~ a
url (I i) = Nothing -- Proof that: Int ~ a
pattern Url :: URL -> MyURL a
pattern Url u <- (url -> Just u)
showMyURL :: MyURL a -> String
showMyURL (Url u) = show u
showMyURL (I i) = show i -- Proof that: Int ~ a
Yet! - Давайте предположим, что мы хотим оценочную функцию, которая возвращает a
, когда данный MyURL a
- это работает, как предполагалось
eval :: MyURL a -> a
eval (GalleryURL url) = url -- Proof that: URL ~ a
eval (PictureURL url) = url -- Proof that: URL ~ a
eval (I int) = int -- Proof that: Int ~ a
но наш новый Url
шаблон синоним не удается!
eval :: MyURL a -> a
eval (Url url) = url
Мы не получим никакой новой информации оa
, когда мы шаблон матч на шаблон синонима
pattern Url :: URL -> MyURL a
связь между a
и URL
разорвано. Мы импортируем Data.Type.Equality и добавить доказательство Refl :: a :~: URL
, что a
равна URL
:
-- Gets ‘URL’ from a ‘MyURL URL’
--
-- ‘Refl’ is our proof that the input is ‘MyURL URL’
url :: MyURL a -> Maybe (a :~: URL, a)
url (GalleryURL url) = Just (Refl, url)
url (PictureURL url) = Just (Refl, url)
url (I int) = Nothing
Тогда мы говорим, что Url _
обеспечивает доказательство того, что a ~ URL
когда сопоставляется,
pattern Url ::() => a ~ URL => a -> MyURL a
pattern Url url <- (Url -> (Refl, url))
и URL
снова могут быть получены с один образец
eval :: MyURL a -> a
eval (Url url) = url -- Proof that: URL ~ a
eval (I int) = int -- Proof that: Int ~ a
Нет, нет реасо n использовать GADT, кроме того, что я только что узнал о них и хотел что-то с этим сделать. Как отметил Сирдек, это даже не решает мою проблему. По крайней мере, я знаю немного больше о GADT сейчас (и когда не использовать их). – somesoaccount
Я делаю очень похожий дизайн с клиентом nanomsg прямо сейчас, который использует GADT для ограничения сетевых адресов. На данный момент это очень прототипный уровень, но вы можете видеть, что GADT ограничивают URL-адреса только для входящих или исходящих подключений - его невозможно переключить. https://github.com/tel/hs-nanomsg/blob/master/src/Network/Nanomsg/C/Address.hs#L102 –