如何自动将Data.Bits添加到Data.Modular?

时间:2015-04-28 04:37:27

标签: haskell polymorphism ghc

我需要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'模块化数字(减去一堆样板)....

1 个答案:

答案 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)

  1. bitSizeMaybe并没有很好的定义。它可能应该是表示n-1所需的位数,但考虑n = 10:那么我们声称有一个4位数,但这似乎是一个声明有16可能的数字mod 10!也许我们应该声称是log 2 10 = 3.32 ......位数? (缺乏整数位大小可以说是问题的根源。)

  2. bit需要具有模块感知能力,因此无法解除它:再次考虑n = 10bit 3 == 8bit 4 == 0 。这没关系,但是......

  3. setBit变得奇怪。再次考虑n = 103 = 0b0011。然后setBit 3 3无法计算0b1011 = 11;它取而代之的是0b0001 = 1,它甚至设置了更少的位。最后一点并不完全在那里!

  4. complement同样有点不可思议:在四位中,我们有complement 3 = complement 0b0011 = 0b1100 = 12。因此,在使用mod 10时,应该complement 3 = 2,以便complement 0b0011 = 0b0010?啊。

  5. 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)或者可以产生更大的数字,然后获取其剩余部分,并且这个剩余部分与按位运算不相关。

  6. 这个实例 的唯一情况是有意义的,因为({再次)mentioned by Reid Barton in a commentn是2的幂。那么你基本上会有一个基于mod的计算机式二进制编码,只是一个可能不同的大小(128位?256位?1024位?),简单的提升工作正常,奇怪的行为会消失,因为你的类型确实会有一个整数位。