注意 的定义HAppendList
:
type family HAppendList (l1 :: [k]) (l2 :: [k]) :: [k]
type instance HAppendList '[] l = l
type instance HAppendList (e ': l) l' = e ': HAppendList l l'
你我都知道这[]
是 的左右标识++
,但编译器只知道左边标识:
happend' :: T a -> T b -> T (HAppendList a b)
happend' (T (Tagged a)) (T (Tagged b)) = (T (Tagged (a++b)))
-- Doesn't typecheck
leftIdentity' :: T a -> T '[] -> T a
leftIdentity' x y = happend' x y
rightIdentity' :: T '[] -> T a -> T a
rightIdentity' x y = happend' x y
你需要有
type instance HAppendList '[] l = l
type instance HAppendList l '[] = l
type instance HAppendList (e ': l) l' = e ': HAppendList l l'
让编译器知道左右身份;但这些会重叠,所以它不会进行类型检查。但是,您可以翻转争论:
(!+++!) :: T a -> T b -> T (HAppendList a b)
(!+++!) (T (Tagged x)) (T (Tagged y)) = T (Tagged (y ++ x))
(!++*) :: Foldable t => T a -> t (T '[]) -> T a
a !++* t = F.foldl (flip (!+++!)) a t
使用 ghc 7.8 中引入的封闭类型族,您可以解决此问题:
type family (++) (a :: [k]) (b :: [k]) :: [k] where
'[] ++ x = x
x ++ '[] = x
(x ': xs) ++ ys = x ': (xs ++ ys)
happend :: T a -> T b -> T (a ++ b)
happend (T (Tagged a)) (T (Tagged b)) = (T (Tagged (a++b)))
leftIdentity :: T a -> T '[] -> T a
leftIdentity x y = happend x y
rightIdentity :: T '[] -> T a -> T a
rightIdentity x y = happend x y