4
HFC에 대해 유형의 좋은 속성을 가진 map tagSelf :: [a] -> [Tagged a a]
및 을 구현하려고합니다. TF 버전이 가까워졌지만, 사례가 있는데, FD 버전이 유형을 간소화하는 동안 유형 기능이 멈추는 경우가 있습니다.함수 종속성을 사용하여 해당 유형을 단순화 할 수있는 유형 패밀리가 발생합니다.
여기에 doctest로 실행할 수있는 자체 포함 된 예가 나와 있습니다.
{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, MultiParamTypeClasses, TypeFamilies, TypeOperators #-}
{-# LANGUAGE PolyKinds, UndecidableInstances #-}
module NEquivTFFD where
{- $ex
These two types are equal, as they should be.
>>> :t \x -> hUntagFD $ HCons x HNil
\x -> hUntagFD $ HCons x HNil :: Tagged x x -> HList '[x]
>>> :t \x -> hUntagTF $ HCons x HNil
\x -> hUntagTF $ HCons x HNil :: Tagged t t -> HList '[t]
If I replace HCons with hBuild, the FD solution infers
the same type
>>> :t \x -> hUntagFD $ hBuild x
\x -> hUntagFD $ hBuild x :: Tagged x x -> HList '[x]
But the TF solution is unable to simplify the UntagR type family
in ghc-7.8.2:
>>> :t \x -> hUntagTF $ hBuild x
\x -> hUntagTF $ hBuild x
:: Tagged t t -> HList (UntagR '[Tagged t t])
while in ghc-7.6.2, there is some suggestion that hBuild is the
problem, and that -XPolyKinds is not a problem:
\x -> hUntagTF $ hBuild x
:: (HBuild' ('[] *) (t -> HList (TagR [*] a)), TagUntagTF a) =>
t -> HList a
If there 'x' type variable is fixed to something (like()), the two
functions are the same again
>>> :t hUntagFD $ hBuild (Tagged())
hUntagFD $ hBuild (Tagged()) :: HList '[()]
>>> :t hUntagTF $ hBuild (Tagged())
hUntagTF $ hBuild (Tagged()) :: HList '[()]
-}
-- * Type family implementation
type family TagR (xs :: k) :: k
type instance TagR '[] = '[]
type instance TagR (x ': xs) = TagR x ': TagR xs
type instance TagR (x :: *) = Tagged x x
-- | inverse of TagR
type family UntagR (xs :: k) :: k
type instance UntagR '[] = '[]
type instance UntagR (x ': xs) = UntagR x ': UntagR xs
type instance UntagR (Tagged x x) = x
class (UntagR (TagR a) ~ a) => TagUntagTF (a :: [*]) where
hTagTF :: HList a -> HList (TagR a)
hUntagTF :: HList (TagR a) -> HList a
instance TagUntagTF '[] where
hTagTF _ = HNil
hUntagTF _ = HNil
instance TagUntagTF xs => TagUntagTF (x ': xs) where
hTagTF (HCons x xs) = Tagged x `HCons` hTagTF xs
hUntagTF (HCons (Tagged x) xs) = x `HCons` hUntagTF xs
-- * Functional dependency implementation
class TagUntagFD a ta | a -> ta, ta -> a where
hTagFD :: HList a -> HList ta
hUntagFD :: HList ta -> HList a
instance TagUntagFD '[] '[] where
hTagFD _ = HNil
hUntagFD _ = HNil
instance (y ~ Tagged x x, TagUntagFD xs ys)
=> TagUntagFD (x ': xs) (y ': ys) where
hTagFD (HCons x xs) = Tagged x `HCons` hTagFD xs
hUntagFD (HCons (Tagged x) xs) = x `HCons` hUntagFD xs
-- * Parts of HList that are needed
data HList x where
HNil :: HList '[]
HCons :: a -> HList as -> HList (a ': as)
newtype Tagged x y = Tagged y
hBuild :: (HBuild' '[] r) => r
hBuild = hBuild' HNil
class HBuild' l r where
hBuild' :: HList l -> r
instance (l' ~ HRevApp l '[])
=> HBuild' l (HList l') where
hBuild' l = hReverse l
instance HBuild' (a ': l) r
=> HBuild' l (a->r) where
hBuild' l x = hBuild' (HCons x l)
type family HRevApp (l1 :: [k]) (l2 :: [k]) :: [k]
type instance HRevApp '[] l = l
type instance HRevApp (e ': l) l' = HRevApp l (e ': l')
hRevApp :: HList l1 -> HList l2 -> HList (HRevApp l1 l2)
hRevApp HNil l = l
hRevApp (HCons x l) l' = hRevApp l (HCons x l')
hReverse l = hRevApp l HNil
그것은 FD 버전으로 같은 동작을 유지하면서 TF의 더 나은 구문을 얻을 수 있습니까?
형식 작업에 주석을 달고 'let f = ...'라고 말한 다음 'let g = f'라고 말하면 'g'(그러나 'f'가 아닌)는 원하는 유형. 따라서 유형 계열에 제한된 양의 축소 만 적용되는 것 같습니다. – kosmikus
감소가 충분하지 않은 GHC 버그처럼 보입니다. ghc-7.6은'let f x = hUntagTF $ hBuild x'라는 정의를위한 더 간단한 타입을 찾아 낸다. – aavogt