是否可以定义可变类型的数据类型?
Is it possible to define variadic-kinded data types?
我可以像这样定义一个多元自然变换:
type family (~>) :: k -> k -> *
type instance (~>) = (->)
newtype NT a b = NT { apply :: forall x. a x ~> b x }
type instance (~>) = NT
它适用于各种类型,所以我可以定义例如
left :: Either ~> (,)
left = NT (NT (Left . fst))
这很酷,也很鼓舞人心。但是无论我玩多少花样,我似乎都无法在 return 类型中得到可变的东西。例如。我想要
type family (:*:) :: k -> k -> k
type instance (:*:) = (,)
type instance (:*:) = ???
这似乎是不可能的,因为类型族需要完全饱和,你只能在*
中引入类型构造函数。
我什至试过一些相当下流的把戏
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)
而且我不知道这是否有任何工作希望,因为我还没有想过更高级的东西 "represented"。但是 GHC 知道我在撒谎
• Couldn't match type ‘(,)’ with ‘Promote2 (,) a’
Inaccessible code in
a pattern with constructor: Refl :: forall k (a :: k). a :~: a,
还有其他技巧吗?
"axiomatic" 方法确实有效,我刚刚使用了错误的相等性:
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 恐慌。所以讨厌的技巧可能很讨厌。仍然对其他方法感兴趣。
我可以像这样定义一个多元自然变换:
type family (~>) :: k -> k -> *
type instance (~>) = (->)
newtype NT a b = NT { apply :: forall x. a x ~> b x }
type instance (~>) = NT
它适用于各种类型,所以我可以定义例如
left :: Either ~> (,)
left = NT (NT (Left . fst))
这很酷,也很鼓舞人心。但是无论我玩多少花样,我似乎都无法在 return 类型中得到可变的东西。例如。我想要
type family (:*:) :: k -> k -> k
type instance (:*:) = (,)
type instance (:*:) = ???
这似乎是不可能的,因为类型族需要完全饱和,你只能在*
中引入类型构造函数。
我什至试过一些相当下流的把戏
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)
而且我不知道这是否有任何工作希望,因为我还没有想过更高级的东西 "represented"。但是 GHC 知道我在撒谎
• Couldn't match type ‘(,)’ with ‘Promote2 (,) a’
Inaccessible code in
a pattern with constructor: Refl :: forall k (a :: k). a :~: a,
还有其他技巧吗?
"axiomatic" 方法确实有效,我刚刚使用了错误的相等性:
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 恐慌。所以讨厌的技巧可能很讨厌。仍然对其他方法感兴趣。