是否可以定义可变参数类型的数据类型?

时间:2018-09-11 04:57:14

标签: haskell type-families polykinds

我可以这样定义一个多形式的自然变换:

highlight

哪一种都可以工作,所以我可以定义例如

type family (~>) :: k -> k -> *
type instance (~>) = (->)

newtype NT a b = NT { apply :: forall x. a x ~> b x }
type instance (~>) = NT

这很酷,令人鼓舞。但是,无论我玩了多少把戏, return 类型的东西似乎都无法变幻莫测。例如。我想要

left :: Either ~> (,)
left = NT (NT (Left . fst))

这似乎是不可能的,因为类型族需要完全饱和,并且您只能在type family (:*:) :: k -> k -> k type instance (:*:) = (,) type instance (:*:) = ??? 中引入类型构造函数。

我什至尝试了一些相当讨厌的把戏

*

而且我不知道这是否还有工作的希望,因为我还没有考虑过“代表”什么样的善良事物。但是GHC知道我还是在撒谎

type instance (:*:) = Promote2 (:*:)

type family Promote2 :: (j -> k -> l) -> (a -> j) -> (a -> k) -> (a -> l) where

promote2_law :: Promote2 f x y z :~: f (x z) (y z)
promote2_law = unsafeCoerce Refl

fstP :: forall (a :: k -> *) (b :: k -> *) (c :: k). (a :*: b) c -> a c
fstP = case promote2_law @(:~:) @a @b @c of Refl -> NT (\(a,b) -> a)

还有其他技巧吗?

1 个答案:

答案 0 :(得分:2)

“公理化”方法确实有效,我刚才用等式错误:

fstP :: forall (a :: j -> k) (b :: j -> k) (x :: j). (a :*: b) x -> a x
fstP = castWith (Refl ~% promote2_law @(:*:) @a @b @x ~% Refl) fst
    where
    infixl 9 ~%
    (~%) = Data.Type.Equality.apply

使用Equality.apply对于通知类型检查器应在何处应用公理至关重要。我在这里制作了a full development种类更多的产品以供参考。

被警告,因为我在玩这个游戏,所以我一次出现了GHC恐慌。所以讨厌的把戏可能很讨厌。仍然对其他方法感兴趣。