此问题是以下问题的续集。首先参考它: Overlapping instances via Nat-kind
现在是创建Group Symmetric
实例的时候了。经过一番野蛮的数学运算后,我得出了一个原则上可以工作的实例,但实际上不起作用:
sIndex :: forall n. KnownNat n => Symmetric n -> Integer -> Integer
sIndex xs m = sIndex_ xs (m `mod` n)
where
n = toInteger (natVal (Proxy :: Proxy n))
sIndex_ :: Symmetric m -> Integer -> Integer
sIndex_ S1 _ = 0
sIndex_ (x :. _) 0 = cIndex x
sIndex_ (x :. xs) m = let
i = cIndex x + sIndex_ xs (m-1)
in if i < n then i else i - n
instance KnownNat n => Semigroup (Symmetric n) where
x <> y = go [] n where
n = toInteger (natVal (Proxy :: Proxy n))
go :: forall m. [(Integer,Integer)] -> Integer -> Symmetric m
go j m
| 0 == m = S1
| otherwise = let
i = sIndex y (sIndex x (n-m))
ix = foldr f i j
in cyclic ix :. go ((ix,m) :j) (m-1)
f (j,m) i = (i - j) `mod` m - 1
go
实例中的Semigroup
函数应通过Symmetric n
,Symmetric (n-1)
等递归直到Symmetric 1
来构建结果。但是GHC不知道该怎么做,并输出以下错误消息:
Group_Symmetric.hs:89:24: error:
• Couldn't match type ‘m’ with ‘1’
‘m’ is a rigid type variable bound by
the type signature for:
go :: forall (m :: Nat).
[(Integer, Integer)] -> Integer -> Symmetric m
at Group_Symmetric.hs:87:9-69
Expected type: Symmetric m
Actual type: Symmetric 1
那么解决方法是什么? go
是否可以返回Symmetric m
(m
从1到n
)的任何实例?
答案 0 :(得分:1)
go
和f
的微小变化解决了该问题:
instance KnownNat n => Semigroup (Symmetric n) where
x <> y = go x [] n where
n = toInteger (natVal (Proxy :: Proxy n))
go :: forall m. Symmetric m -> [(Integer,Integer)] -> Integer -> Symmetric m
go S1 _ _ = S1
go (_ :. xs) j m = let
i = sIndex x (sIndex y (n-m))
ix = foldr f i j
in Cyclic ix :. go xs ((ix,m) :j) (m-1)
f (j,m) i = let
ix = (i - j) `mod` m - 1
in if 0 <= ix then ix else ix + m
关键思想是引入一个虚拟参数。另请注意,使用的是Cyclic
而不是cyclic
。
不幸的是,事实证明我在数学上做错了。需要纠正。
编辑:以下是更正后的sIndex
,它可以完成实例:
sIndex :: forall n. KnownNat n => Symmetric n -> Integer -> Integer
sIndex xs m = let
n = toInteger (natVal (Proxy :: Proxy n))
in sIndex_ xs (m `mod` n) n
where
sIndex_ :: Symmetric m -> Integer -> Integer -> Integer
sIndex_ S1 _ _ = 0
sIndex_ (x :. _) 0 _ = cIndex x
sIndex_ (x :. xs) m n = let
i = cIndex x + sIndex_ xs (m-1) (n-1) + 1
in if n <= i then i - n else i
我还注意到x
和y
在<>
的定义中被交换了,然后在上面进行了修正。