我可以这样定义一个多形式的自然变换:
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)
还有其他技巧吗?
答案 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恐慌。所以讨厌的把戏可能很讨厌。仍然对其他方法感兴趣。