我需要xor
几个mod号码(来自Data.Modular)....
let x = 4 :: Integer `Mod` 10
y = 6 :: Integer `Mod` 10
print $ x `xor` y
....但是,这不起作用,因为Mod x y
不是Data.Bits的实例。
我可以,或者当然,将值转换为整数,xor,然后转换回来。或者,我甚至可以通过编写所有类函数来手动创建Mod x y
Bits实例,但这都是丑陋的样板代码,应该是自动化的。 StandaloneDeriving扩展程序将是实现此目的的方法,但它似乎无法工作....
{-# LANGUAGE DataKinds, TypeOperators, TypeSysonymInstances, FlexibleInstances, StandaloneDeriving #-}
import Data.Bits
import Data.Modular
import GHC.TypeLits
deriving instance Bits (Int `Mod` 10)
产量
"无法创建' Bits(Mod Int 10)的衍生实例':' Mod'的数据构造函数。不在范围内,因此您无法为其导出实例"
我没有和StandaloneDeriving结婚,我只是希望任何解决方案能够提供我的xor'模块化数字(减去一堆样板)....
答案 0 :(得分:4)
您不能仅仅通过xorring底层位来实现模块化数字xor
;你会得到超出范围的数字。例如:
ghci> 9 `xor` 4 :: Integer
13
这是派生实例的功能,这意味着它无论如何都不会起作用。这就是隐藏Mod
的构造函数的原因:因此"小于n
"可以通过智能构造函数维护不变量。
但是这里的情况更糟:模块化数字真的不是 Bits
的合理实例!通常,在这种情况下,你编写的代码而不是自动类型类实例化只是使用一堆提升函数,如
mapMod :: (KnownNat n, Integral j) => (i -> j) -> i `Mod` n -> j `Mod` n
mapMod f = toMod . f . unMod
liftMod2 :: (KnownNat n, Integral k)
=> (i -> j -> k) -> i `Mod` n -> j `Mod` n -> k `Mod` n
liftMod2 f x y = toMod $ f (unMod x) (unMod y)
然后以(.&.) = liftMod2 (.&.)
等方式实现一大堆方法(包括xor = liftMod2 xor
)。
不幸的是,这产生了一大堆问题。这是一个不一定详尽无遗的清单。给定一个实例Bits (i `Mod` n)
:
bitSizeMaybe
并没有很好的定义。它可能应该是表示n-1
所需的位数,但考虑n = 10
:那么我们声称有一个4位数,但这似乎是一个声明有16可能的数字mod 10!也许我们应该声称是log 2 10 = 3.32 ......位数? (缺乏整数位大小可以说是问题的根源。)
bit
需要具有模块感知能力,因此无法解除它:再次考虑n = 10
,bit 3 == 8
但bit 4 == 0
。这没关系,但是......
setBit
变得奇怪。再次考虑n = 10
和3 = 0b0011
。然后setBit 3 3
无法计算0b1011 = 11
;它取而代之的是0b0001 = 1
,它甚至设置了更少的位。最后一点并不完全在那里!
complement
同样有点不可思议:在四位中,我们有complement 3 = complement 0b0011 = 0b1100 = 12
。因此,在使用mod 10时,应该complement 3 = 2
,以便complement 0b0011 = 0b0010
?啊。
As Reid Barton said in a comment,生成的xor
操作不具有关联性。给定xorM = liftMod2 xor
,我们有
ghci> (9 `xorM` 4) `xorM` 3 :: Integer `Mod` 10
0
ghci> 9 `xorM` (4 `xorM` 3) :: Integer `Mod` 10
4
按位或类似地断开(虽然按位并且很好,我相信)。这是因为按位(x)或者可以产生更大的数字,然后获取其剩余部分,并且这个剩余部分与按位运算不相关。
这个实例 的唯一情况是有意义的,因为({再次)mentioned by Reid Barton in a comment,n
是2的幂。那么你基本上会有一个基于mod的计算机式二进制编码,只是一个可能不同的大小(128位?256位?1024位?),简单的提升工作正常,奇怪的行为会消失,因为你的类型确实会有一个整数位。