我想表示一个最多大约120位的字符串,速度至关重要。我需要能够通过重复的snoc
操作来构建一个位串,然后通过重复的uncons
操作来使用它。一个想法是从Word128
窃取data-dword
的实现,并使用类似的东西来构建:
empty = 1
snoc xs x = (xs `shiftL` 1) .|. x
但是,这种无情似乎变得有点难看,不得不首先countLeadingZeros
并向左移动以消除它们,然后才能通过移位和屏蔽高位来读取元素。
是否有一些更令人愉快的方式,至少同样快,或更快的方式,不是太不愉快?
Phil Ruffwind为lens
提出了at
Data.Map
的版本,但到目前为止所有实现都比目前的初始实现lens
要慢得多当关键比较便宜时使用。如果我可以在查找条目时生成一个非常便宜的条目路径表示,然后使用insert
或delete
的专用版本非常有效地使用它,那么也许我可以使这个值得。
答案 0 :(得分:2)
我不确定这是否合格。我担心我会以某种形式重新实施countLeadingZeros
......
无论如何,这个想法是从左边狙击,向右移动。然后,我们可以使用x
和XOR“计算”x-1
的尾随零。 “count”的结果是一个掩码“00..01..11”,它大致是尾随零的一元表示。我们不会将这个一元变换为二元,因为我们没有必要:通过一些位工作,我们可以解开。
未经测试和未经证实的代码如下。
import Data.Word
import Data.Bits
import Text.Printf
type T = Word64 -- can be adapted to any WordN
-- for pretty printing
pr :: T -> String
pr x = printf "%064b\n" x
empty :: T
empty = shiftL 1 63
snoc :: T -> T -> T
snoc x xs = shiftR xs 1 .|. (shiftL x 63)
-- returns (head, tail)
-- head is not normalized (0 or 1), only (0 or /=0)
uncons :: T -> (T, T)
uncons xs =
let -- example
-- 0101001100000000000 xs
y = (xs `xor` (xs - 1))
-- 0000000111111111111 y
z = shiftR y 1 + 1
-- 0000000100000000000 z
z' = shiftL z 1
-- 0000001000000000000 z'
in (xs .&. z' , (xs .&. complement z) .|. z' )