我该如何编写这个 GEq 实例?
How can I write this GEq instance?
我有数据类型 Tup2List
和 GTag
(来自对 的回答)
我想为 GTag t
编写一个 GEq
实例,我认为这也需要为 Tup2List
编写一个实例。这个实例怎么写?
我猜它为什么不起作用是因为不存在部分 Refl
- 你需要一次匹配整个结构,编译器才能给你 Refl,而我我正在尝试解包最外层的构造函数然后递归。
这是我的代码,undefined
填写我不会写的部分。
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
module Foo where
import Data.GADT.Compare
import Generics.SOP
import qualified GHC.Generics as GHC
data Tup2List :: * -> [*] -> * where
Tup0 :: Tup2List () '[]
Tup1 :: Tup2List x '[ x ]
TupS :: Tup2List r (x ': xs) -> Tup2List (a, r) (a ': x ': xs)
instance GEq (Tup2List t) where
geq Tup0 Tup0 = Just Refl
geq Tup1 Tup1 = Just Refl
geq (TupS x) (TupS y) =
case x `geq` y of
Just Refl -> Just Refl
Nothing -> Nothing
newtype GTag t i = GTag { unTag :: NS (Tup2List i) (Code t) }
instance GEq (GTag t) where
geq (GTag (Z x)) (GTag (Z y)) = undefined -- x `geq` y
geq (GTag (S _)) (GTag (Z _)) = Nothing
geq (GTag (Z _)) (GTag (S _)) = Nothing
geq (GTag (S x)) (GTag (S y)) = undefined -- x `geq` y
编辑:我已经改变了我的数据类型,但我仍然面临同样的核心问题。当前的定义是
data Quux i xs where Quux :: Quux (NP I xs) xs
newtype GTag t i = GTag { unTag :: NS (Quux i) (Code t) }
instance GEq (GTag t) where
-- I don't know how to do this
geq (GTag (S x)) (GTag (S y)) = undefined
这是我对此的看法。就个人而言,我认为允许为具有 0 个或多个字段的总和类型派生标记类型没有多大意义,因此我将简化 Tup2List
。它的存在与手头的问题正交。
所以我要定义GTag
如下:
type GTag t = GTag_ (Code t)
newtype GTag_ t a = GTag { unGTag :: NS ((:~:) '[a]) t }
pattern P0 :: () => (ys ~ ('[t] ': xs)) => GTag_ ys t
pattern P0 = GTag (Z Refl)
pattern P1 :: () => (ys ~ (x0 ': '[t] ': xs)) => GTag_ ys t
pattern P1 = GTag (S (Z Refl))
pattern P2 :: () => (ys ~ (x0 ': x1 ': '[t] ': xs)) => GTag_ ys t
pattern P2 = GTag (S (S (Z Refl)))
pattern P3 :: () => (ys ~ (x0 ': x1 ': x2 ': '[t] ': xs)) => GTag_ ys t
pattern P3 = GTag (S (S (S (Z Refl))))
pattern P4 :: () => (ys ~ (x0 ': x1 ': x2 ': x3 ': '[t] ': xs)) => GTag_ ys t
pattern P4 = GTag (S (S (S (S (Z Refl)))))
主要区别在于定义 GTag_
时没有出现 Code
。这将使递归更容易,因为您不需要递归情况必须再次表达为 Code
的应用程序。
如前所述,第二个区别是使用 (:~:) '[a]
来强制使用单参数构造函数,而不是更复杂的 Tup2List
.
这是原始示例的变体:
data SomeUserType = Foo Int | Bar Char | Baz (Bool, String)
deriving (GHC.Generic)
instance Generic SomeUserType
Baz
的参数现在明确写成一对,以遵守 "single argument" 要求。
示例相关总和:
ex1, ex2, ex3 :: DSum (GTag SomeUserType) Maybe
ex1 = P0 ==> 3
ex2 = P1 ==> 'x'
ex3 = P2 ==> (True, "foo")
现在实例:
instance GShow (GTag_ t) where
gshowsPrec _n = go 0
where
go :: Int -> GTag_ t a -> ShowS
go k (GTag (Z Refl)) = showString ("P" ++ show k)
go k (GTag (S i)) = go (k + 1) (GTag i)
instance All2 (Compose Show f) t => ShowTag (GTag_ t) f where
showTaggedPrec (GTag (Z Refl)) = showsPrec
showTaggedPrec (GTag (S i)) = showTaggedPrec (GTag i)
instance GEq (GTag_ t) where
geq (GTag (Z Refl)) (GTag (Z Refl)) = Just Refl
geq (GTag (S i)) (GTag (S j)) = geq (GTag i) (GTag j)
geq _ _ = Nothing
instance All2 (Compose Eq f) t => EqTag (GTag_ t) f where
eqTagged (GTag (Z Refl)) (GTag (Z Refl)) = (==)
eqTagged (GTag (S i)) (GTag (S j)) = eqTagged (GTag i) (GTag j)
eqTagged _ _ = \ _ _ -> False
以及它们的一些使用示例:
GHCi> (ex1, ex2, ex3)
(P0 :=> Just 3,P1 :=> Just 'x',P2 :=> Just (True,"foo"))
GHCi> ex1 == ex1
True
GHCi> ex1 == ex2
False
我有数据类型 Tup2List
和 GTag
(来自对
我想为 GTag t
编写一个 GEq
实例,我认为这也需要为 Tup2List
编写一个实例。这个实例怎么写?
我猜它为什么不起作用是因为不存在部分 Refl
- 你需要一次匹配整个结构,编译器才能给你 Refl,而我我正在尝试解包最外层的构造函数然后递归。
这是我的代码,undefined
填写我不会写的部分。
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
module Foo where
import Data.GADT.Compare
import Generics.SOP
import qualified GHC.Generics as GHC
data Tup2List :: * -> [*] -> * where
Tup0 :: Tup2List () '[]
Tup1 :: Tup2List x '[ x ]
TupS :: Tup2List r (x ': xs) -> Tup2List (a, r) (a ': x ': xs)
instance GEq (Tup2List t) where
geq Tup0 Tup0 = Just Refl
geq Tup1 Tup1 = Just Refl
geq (TupS x) (TupS y) =
case x `geq` y of
Just Refl -> Just Refl
Nothing -> Nothing
newtype GTag t i = GTag { unTag :: NS (Tup2List i) (Code t) }
instance GEq (GTag t) where
geq (GTag (Z x)) (GTag (Z y)) = undefined -- x `geq` y
geq (GTag (S _)) (GTag (Z _)) = Nothing
geq (GTag (Z _)) (GTag (S _)) = Nothing
geq (GTag (S x)) (GTag (S y)) = undefined -- x `geq` y
编辑:我已经改变了我的数据类型,但我仍然面临同样的核心问题。当前的定义是
data Quux i xs where Quux :: Quux (NP I xs) xs
newtype GTag t i = GTag { unTag :: NS (Quux i) (Code t) }
instance GEq (GTag t) where
-- I don't know how to do this
geq (GTag (S x)) (GTag (S y)) = undefined
这是我对此的看法。就个人而言,我认为允许为具有 0 个或多个字段的总和类型派生标记类型没有多大意义,因此我将简化 Tup2List
。它的存在与手头的问题正交。
所以我要定义GTag
如下:
type GTag t = GTag_ (Code t)
newtype GTag_ t a = GTag { unGTag :: NS ((:~:) '[a]) t }
pattern P0 :: () => (ys ~ ('[t] ': xs)) => GTag_ ys t
pattern P0 = GTag (Z Refl)
pattern P1 :: () => (ys ~ (x0 ': '[t] ': xs)) => GTag_ ys t
pattern P1 = GTag (S (Z Refl))
pattern P2 :: () => (ys ~ (x0 ': x1 ': '[t] ': xs)) => GTag_ ys t
pattern P2 = GTag (S (S (Z Refl)))
pattern P3 :: () => (ys ~ (x0 ': x1 ': x2 ': '[t] ': xs)) => GTag_ ys t
pattern P3 = GTag (S (S (S (Z Refl))))
pattern P4 :: () => (ys ~ (x0 ': x1 ': x2 ': x3 ': '[t] ': xs)) => GTag_ ys t
pattern P4 = GTag (S (S (S (S (Z Refl)))))
主要区别在于定义 GTag_
时没有出现 Code
。这将使递归更容易,因为您不需要递归情况必须再次表达为 Code
的应用程序。
如前所述,第二个区别是使用 (:~:) '[a]
来强制使用单参数构造函数,而不是更复杂的 Tup2List
.
这是原始示例的变体:
data SomeUserType = Foo Int | Bar Char | Baz (Bool, String)
deriving (GHC.Generic)
instance Generic SomeUserType
Baz
的参数现在明确写成一对,以遵守 "single argument" 要求。
示例相关总和:
ex1, ex2, ex3 :: DSum (GTag SomeUserType) Maybe
ex1 = P0 ==> 3
ex2 = P1 ==> 'x'
ex3 = P2 ==> (True, "foo")
现在实例:
instance GShow (GTag_ t) where
gshowsPrec _n = go 0
where
go :: Int -> GTag_ t a -> ShowS
go k (GTag (Z Refl)) = showString ("P" ++ show k)
go k (GTag (S i)) = go (k + 1) (GTag i)
instance All2 (Compose Show f) t => ShowTag (GTag_ t) f where
showTaggedPrec (GTag (Z Refl)) = showsPrec
showTaggedPrec (GTag (S i)) = showTaggedPrec (GTag i)
instance GEq (GTag_ t) where
geq (GTag (Z Refl)) (GTag (Z Refl)) = Just Refl
geq (GTag (S i)) (GTag (S j)) = geq (GTag i) (GTag j)
geq _ _ = Nothing
instance All2 (Compose Eq f) t => EqTag (GTag_ t) f where
eqTagged (GTag (Z Refl)) (GTag (Z Refl)) = (==)
eqTagged (GTag (S i)) (GTag (S j)) = eqTagged (GTag i) (GTag j)
eqTagged _ _ = \ _ _ -> False
以及它们的一些使用示例:
GHCi> (ex1, ex2, ex3)
(P0 :=> Just 3,P1 :=> Just 'x',P2 :=> Just (True,"foo"))
GHCi> ex1 == ex1
True
GHCi> ex1 == ex2
False