如何使用 xor 在折叠中解决 Haskell 的 Int shift 参数?

How to work around Haskell's Int shift argument in a fold using xor?

我有一些代码(为了好玩而生成 Rijndael S-box)如下所示:

q0 = q  ⊕  shiftL q  1
q1 = q0 ⊕  shiftL q0 2
q2 = q1 ⊕  shiftL q1 4

这似乎有点愚蠢 - 这不是弃牌的完美情况吗?但是我不能使用折叠,因为 shiftL 需要 Int 来移动距离,当然 xor 需要 Bits.

对我来说,一个旨在对 Bits 进行操作的函数不会接受 Bits 的所有参数,这对我来说似乎很尴尬。我很想知道这样做的合理性,但我更想知道是否有任何优雅的方法来实现我想要的折叠。

foldl :: (b -> a -> b) -> b -> [a] -> b 迭代地将以 b 开头的函数应用于 a 的列表,直到列表耗尽,然后 returns 结果。在这种情况下,我们的 a 可以是 移位长度 。所以 124。我们可以用iterate :: (a -> a) -> a -> [a]构造这样一个列表。确实:

powers2 = iterate (2*) 1

现在我们可以将该列表提供给 foldlfoldl执行的函数是\qi s -> xor qi (shiftL qi s)。所以完整的函数是:

qn :: (Num a, Foldable t, Bits [a]) => Int -> r -> t Int -> [a]
qn n q = foldl (\qi s -> xor qi (shiftL qi s)) q $ take n $ iterate (2*) 1

因此,如果我们调用 qn 3 q,我们会在 q 上执行该函数三次,从而在您的示例中获得 q2。例如:

Prelude Data.Bits> qn 3 15
1285

开始于:

q           = 0000 0000 1111
shiftL q  1 = 0000 0001 1110
              --------------
q0          = 0000 0001 0001
shiftL q0 2 = 0000 0100 0100
              --------------
q1          = 0000 0101 0101
shiftL q1 4 = 0101 0101 0000
              --------------
q2          = 0101 0000 0101

这是 1285 的二进制等价物。

Jon Purdy 推断出我应该明确说明的内容 - 我想要一个无点函数传递给 fold,他提供了一个:liftA2 (.) xor shiftL.