A SAFE and idiomatic (no corner cutting or strange stuff under the hood) implementation of an immutable array in Haskell aiming for an idiomatic low memory footprint by storing chunks of 256 elements in a fixed vector (data VF256 a = VF … , i00 :: a, … , iFF :: a }) by sharing a single constructor. A side-effect of this approach, is that we achieve O(log₂₅₆ n) asymptotic time complexity for most operations.

Futhermore, in order to avoid the usage of the following pattern data Present a = Yes a | No for when an element is present as it will add a constructor (overhead) for each element. This is achieved with the usage of (bottom) combined with Haskells lazy nature as well as a bitmap, where each of the 256 elements presence are stored as a single bit.

Remark: Please see the References below for Simon Marlows answer at Stack Overflow with regard of memory footprint of Haskell data types.

Basics

Step-by-step insert example with an Array Log₈ with height equal to 0

We have an empty array A of size 64:

                                   □□□□□□□□

▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭

> Remark: ▭ denotes ⊥ (bottom).

The array A is updated with a value of type α on index A₃₁, where index < 64:

                                   □□□▣□□□□

▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭■  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭


The array A is updated with a value of type α on index A₂₉, where index < 64:

                                   □□□▣□□□□

▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭■▭■  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭

The array A is updated with a value of type α on index A₆₃, where index < 64:

                                   □□□▣□□□▣

▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭■▭■  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭▭  ▭▭▭▭▭▭▭■

Step-by-step insert example with an Array Log₄ with height greater than 0

We want to insert a value of type α into index A₃₃ in an Array Log₄ of size 64

                                      □□□□

        □□□□                □□□□                □□□□                □□□□

▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭  ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭

> Remark: ▭ denotes ⊥ (bottom).

a) Update top bitmap index (node):

   33 .>. 4     = 2
    2 .&. (4-1) = 2

                                      □□▣□

        □□□□                □□□□                □□□□                □□□□

▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭  ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭

b) Update next bitmap index (node):

   33 .>. 2     = 8
    8 .&. (4-1) = 0

                                      □□▣□

        □□□□                □□□□                ▣□□□                □□□□

▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭  ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭

c) Insert value (leaf):

   33 .>. 0     = 33
   33 .&. (4-1) =  1

                                      □□▣□

        □□□□                □□□□                ▣□□□                □□□□

▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭  ▭■▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭ ▭▭▭▭

Code Snippet

src/Data/Array/Log256.hs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
--------------------------------------------------------------------------------
--
-- Data.Array.Log256, (c) 2020 SPISE MISU ApS
--
--------------------------------------------------------------------------------

{-# LANGUAGE Safe #-}

--------------------------------------------------------------------------------

module Data.Array.Log256
  ( AL256
  --
  , height
  , length
  --
  , create
  , update
  , exists
  , lookup
  , remove
  --
  , pprint
  , tuples
  , tolist
  --
  , amount
  , sparse
  , defrag
  , sliver
  , expand
  , reduce
  )
where

--------------------------------------------------------------------------------

import           Prelude              hiding
  ( length
  , lookup
  )

import           Data.Bits
  ( Bits
  , shiftL
  , shiftR
  , (.&.)
  )
import           Data.List
  ( dropWhile
  , foldl'
  , takeWhile
  )
import           Data.Ratio
  ( Rational
  , (%)
  )
import           Data.Word
  ( Word8
  )

import           Data.Vector.Fixed256
  ( VF256
  )
import qualified Data.Vector.Fixed256 as VF

--------------------------------------------------------------------------------

data AL256 a
  = A !Integer !(Tree a)

data Tree a
  = L !(VF256       a)
  | N !(VF256 (Tree a))

instance Show a => Show (AL256 a) where
  show (A _ t) = show t

instance Show a => Show (Tree a) where
  show = show . helper []

--------------------------------------------------------------------------------

instance Foldable Tree where
  foldMap f (L vfa) = foldMap          f  vfa
  foldMap f (N vft) = foldMap (foldMap f) vft

instance Foldable AL256 where
  foldMap f (A _ t) = foldMap f t

instance Functor Tree where
  fmap f (L vfa) = L $ fmap       f  vfa
  fmap f (N vft) = N $ fmap (fmap f) vft

instance Functor AL256 where
  fmap f (A l t) = A l $ fmap f t

--------------------------------------------------------------------------------

length
  :: AL256 a
  -> Integer
height
  :: AL256 a
  -> Integer

{-# INLINE length #-}
{-# INLINE height #-}

length (A l _) =
  l

height (A l _) =
  log256 $ l - 1

--------------------------------------------------------------------------------

create
  :: Integer
  -> AL256 a
update
  :: Integer
  ->       a
  -> AL256 a
  -> AL256 a
exists
  :: Integer
  -> AL256 a
  -> Bool
lookup
  :: Integer
  -> AL256 a
  ->       a
remove
  :: Integer
  -> AL256 a
  -> AL256 a

{-# INLINE create #-}
{-# INLINE update #-}
{-# INLINE exists #-}
{-# INLINE lookup #-}
{-# INLINE remove #-}

{-| Length must be greater than 0. Devs responsability to call inside bounds
-}
create l
  | l  >  aux =                    A l $ N VF.create
  | otherwise = assert (l > 0) msg A l $ L VF.create
  where
    aux = logmod + 1
    msg = "The length of an array must be greater than 0"

{-| Length can be read in O(1). Devs responsability to call inside bounds
-}
update i a (A l t) =
  assert (i < l) msg
  A l $ aux (loglvl l) t
  where
    aux _ (L fv) =
      L $ k `seq` VF.update k a fv
      where
        k = i2wrd8 i .&. logmod
    aux j (N fv) =
      N $ v `seq` VF.update k v fv
      where
        k = i2wrd8 $ i .>. j .&. logmod
        n = j - lograt
        c =
          if   VF.exists k fv
          then VF.lookup k fv
          else branch n
        v = aux n c
    msg =
      "Index " ++ show i ++ " is out of bounds (length " ++ show l ++ ")"

{-| Length can be read in O(1). Devs responsability to call inside bounds
-}
exists i (A l t) =
  assert (i < l) msg
  aux (loglvl l) t
  where
    aux _ (L fv) =
      VF.exists k fv
      where
        k = i2wrd8 i .&. logmod
    aux j (N fv) =
      e && b
      where
        k = i2wrd8 $ i .>. j .&. logmod
        e = VF.exists k fv
        n = j - lograt
        b = aux n $ VF.lookup k fv
    msg =
      "Index " ++ show i ++ " is out of bounds (length " ++ show l ++ ")"

{-| * Length can be read in O(1). Devs responsability to call inside bounds
    * Existence can be checked in O(log₂₅₆ n). Devs responsability to check
-}
lookup i al@(A l t) =
  assert (i < l)       msg0
  assert (exists i al) msg1
  aux (loglvl l) t
  where
    aux _ (L fv) =
      VF.lookup k fv
      where
        k = i2wrd8 $ i .&. logmod
    aux j (N fv) =
      aux n c
      where
        k = i2wrd8 $ i .>. j .&. logmod
        n = j - lograt
        c = VF.lookup k fv
    msg0 =
      "Index " ++ show i ++ " is out of bounds (length " ++ show l ++ ")"
    msg1 =
      "Index " ++ show i ++ " doesn't contain any element"

{-| * Length can be read in O(1). Devs responsability to call inside bounds
    * Existence can be checked in O(log₂₅₆ n). Devs responsability to check
-}
remove i al@(A l t) =
  assert (i < l)       msg0
  assert (exists i al) msg1
  A l $ aux (loglvl l) t
  where
    aux _ (L fv) =
      L r
      where
        k = i2wrd8 $ i .&. logmod
        r = VF.remove k fv
    aux j (N fv) =
      N a
      where
        k = i2wrd8 $ i .>. j .&. logmod
        n = j - lograt
        c = VF.lookup k fv
        b = aux n c
        a =
          if      vacant b
          then VF.remove k fv
          else VF.update k b fv
    msg0 =
      "Index " ++ show i ++ " is out of bounds (length " ++ show l ++ ")"
    msg1 =
      "Index " ++ show i ++ " doesn't contain any element"

--------------------------------------------------------------------------------

pprint
  :: AL256 a
  -> String
tuples
  :: AL256 a
  -> [(Integer, a)]
tolist
  :: AL256 a
  -> [a]

{-# INLINE pprint #-}
{-# INLINE tuples #-}
{-# INLINE tolist #-}

pprint (A l t) =
  "├ " ++ show l ++ aux 0 t
  where
    rep i   = concat $ replicate i "│ "
    bmp f v =
      map f $
      VF.bitmap v
    aux i (L fv) =
      "\n" ++ rep i ++ "├ " ++ bmp (\x -> if x then '■' else '▭') fv
    aux i (N fv) =
      "\n" ++ rep i ++ "├ " ++ bmp (\x -> if x then '▣' else '□') fv ++ sub
      where
        sub = concat $ map (aux (i+1) . snd) $ VF.tuples fv

tuples (A _ t) =
  helper [] t

tolist (A _ t) =
  map snd $ helper [] t

--------------------------------------------------------------------------------

amount :: AL256 a -> Integer
sparse :: AL256 a -> Rational
defrag :: AL256 a -> AL256 a
sliver
  :: Integer
  -> Integer
  -> AL256 a
  -> AL256 a
expand :: Integer -> AL256 a -> AL256 a
reduce :: Integer -> AL256 a -> AL256 a

{-# INLINE amount #-}
{-# INLINE sparse #-}
{-# INLINE defrag #-}
{-# INLINE sliver #-}
{-# INLINE expand #-}
{-# INLINE reduce #-}

amount (A _ t) =
  aux t
  where
    aux (L fv) = VF.amount fv
    aux (N fv) =
      if   0 == VF.amount fv
      then 0
      else foldl' (+) 0 $ map (aux . snd) $ VF.tuples fv

sparse    (A 0 _) = 0
sparse al@(A l _) = amount al % l

defrag al =
  -- Reduces the degree of fragmentation. Check sparsity first
  foldl (\a (i,x) -> update i x a) (create n) $
  zip [ 0 .. ] $
  tolist al
  where
    n = amount al

{-| * Length can be read in O(1). Devs responsability to call inside bounds
    * Index + offset must be: i+o<=l. Devs responsability to call inside bounds
-}
sliver i o al@(A l _) =
  assert (i + o <= l) msg
  foldl (\a (j,x) -> update (j-i) x a) (create o) $
  takeWhile ((i + o >) . fst) $
  dropWhile ((i     >) . fst) $
  tuples al
  where
    msg =
      "Index i+o ("                    ++ show (i+o) ++
      ") must be less or equal to l (" ++ show  l    ++
      ")"

{-| Length can be read in O(1). Devs responsability to call inside bounds
-}
expand n (A l t) =
  assert (n > l) msg
  A n $ aux $ log256 n
  where
    msg =
      "New length " ++ show n ++ " must be greater than previous " ++ show l
    aux i
      | i  >  lvl = N $ VF.update 0 (aux $ i - 1) VF.create
      | otherwise = t
    lvl = log256 l

{-| Length can be read in O(1). Devs responsability to call inside bounds
-}
reduce n al@(A l _) =
  assert (n < l) msg
  sliver 0 n al
  where
    msg =
      "New length " ++ show n ++ " must be less than previous " ++ show l

--------------------------------------------------------------------------------

-- HELPERS

helper
  :: [Integer]
  -> Tree a
  -> [(Integer, a)]

{-# INLINE helper #-}

helper ns (L fv) =
  map (\(i,a) -> (fromIntegral i + (aux lograt ns), a)) $
  VF.tuples fv
  where
    aux _ [    ] = 0
    aux i (x:xs) = (1 .<. i) * x + (aux (i + lograt) xs)
helper ns (N fv) =
  concat $
  map (\(i,x) -> helper (fromIntegral i:ns) x) $
  VF.tuples fv

--------------------------------------------------------------------------------

assert
  :: Bool
  -> String
  -> a
  -> a

{-# INLINE assert #-}

assert True  ___ a = a
assert False msg _ = error msg

--------------------------------------------------------------------------------

branch
  :: Int
  -> Tree a
vacant
  :: Tree a
  -> Bool

{-# INLINE branch #-}
{-# INLINE vacant #-}

branch 0 = L VF.create
branch _ = N VF.create

vacant (L fv) = VF.amount fv == 0
vacant (N fv) = VF.amount fv == 0

--------------------------------------------------------------------------------

(.<.)
  :: Bits a
  =>      a
  -> Int
  ->      a
(.>.)
  :: Bits a
  =>      a
  -> Int
  ->      a

{-# INLINE (.<.) #-}
{-# INLINE (.>.) #-}

(.<.) = shiftL

(.>.) = shiftR

--------------------------------------------------------------------------------

lograt
  :: Int
logmod
  :: Num a
  =>     a
loglvl
  :: Integer
  -> Int
i2wrd8
  :: Integral a
  =>          a
  -> Word8

{-# INLINE lograt #-}
{-# INLINE logmod #-}
{-# INLINE loglvl #-}
{-# INLINE i2wrd8 #-}

lograt = 0x08

logmod = 0xFF

loglvl = ((*) lograt) . fromIntegral . log256 . (flip (-) 1)

i2wrd8 = fromIntegral

--------------------------------------------------------------------------------

-- http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
--
-- log_{2^b} n ≈ m (floor)

log02b
  ::
    ( Bits a
    , Num  a
    )
  => Int
  ->       a
  ->       a
log256
  ::
    ( Bits a
    , Num  a
    )
  =>       a
  ->       a

{-# INLINE log02b #-}
{-# INLINE log256 #-}

log02b b n =
  aux 0 (n .>. b)
  where
    aux acc 0 = acc
    aux acc x = aux (acc + 1) (x .>. b)

log256 =
  log02b lograt

src/Data/Vector/Fixed256.hs

--------------------------------------------------------------------------------
--
-- Data.Vector.Fixed256, (c) 2020 SPISE MISU ApS
--
--------------------------------------------------------------------------------

{-# LANGUAGE Safe #-}

--------------------------------------------------------------------------------

module Data.Vector.Fixed256
  ( VF256
  --
  , create
  , exists
  , lookup
  , update
  , remove
  --
  , amount
  , bitmap
  , pprint
  , tuples
  , tolist
  ) where

--------------------------------------------------------------------------------

import           Prelude   hiding
  ( lookup
  )

import           Data.Bits
  ( Bits
  , clearBit
  , popCount
  , setBit
  , testBit
  , (.&.)
  )
import           Data.Word
  ( Word64
  , Word8
  )

--------------------------------------------------------------------------------

data VF256 a = VF
  { bm0 :: !Word64
  , bm1 :: !Word64
  , bm2 :: !Word64
  , bm3 :: !Word64
  , i00 :: a, i01 :: a, i02 :: a, i03 :: a
  , i04 :: a, i05 :: a, i06 :: a, i07 :: a
  , i08 :: a, i09 :: a, i0A :: a, i0B :: a
  , i0C :: a, i0D :: a, i0E :: a, i0F :: a
  , i10 :: a, i11 :: a, i12 :: a, i13 :: a
  , i14 :: a, i15 :: a, i16 :: a, i17 :: a
  , i18 :: a, i19 :: a, i1A :: a, i1B :: a
  , i1C :: a, i1D :: a, i1E :: a, i1F :: a
  , i20 :: a, i21 :: a, i22 :: a, i23 :: a
  , i24 :: a, i25 :: a, i26 :: a, i27 :: a
  , i28 :: a, i29 :: a, i2A :: a, i2B :: a
  , i2C :: a, i2D :: a, i2E :: a, i2F :: a
  , i30 :: a, i31 :: a, i32 :: a, i33 :: a
  , i34 :: a, i35 :: a, i36 :: a, i37 :: a
  , i38 :: a, i39 :: a, i3A :: a, i3B :: a
  , i3C :: a, i3D :: a, i3E :: a, i3F :: a
  , i40 :: a, i41 :: a, i42 :: a, i43 :: a
  , i44 :: a, i45 :: a, i46 :: a, i47 :: a
  , i48 :: a, i49 :: a, i4A :: a, i4B :: a
  , i4C :: a, i4D :: a, i4E :: a, i4F :: a
  , i50 :: a, i51 :: a, i52 :: a, i53 :: a
  , i54 :: a, i55 :: a, i56 :: a, i57 :: a
  , i58 :: a, i59 :: a, i5A :: a, i5B :: a
  , i5C :: a, i5D :: a, i5E :: a, i5F :: a
  , i60 :: a, i61 :: a, i62 :: a, i63 :: a
  , i64 :: a, i65 :: a, i66 :: a, i67 :: a
  , i68 :: a, i69 :: a, i6A :: a, i6B :: a
  , i6C :: a, i6D :: a, i6E :: a, i6F :: a
  , i70 :: a, i71 :: a, i72 :: a, i73 :: a
  , i74 :: a, i75 :: a, i76 :: a, i77 :: a
  , i78 :: a, i79 :: a, i7A :: a, i7B :: a
  , i7C :: a, i7D :: a, i7E :: a, i7F :: a
  , i80 :: a, i81 :: a, i82 :: a, i83 :: a
  , i84 :: a, i85 :: a, i86 :: a, i87 :: a
  , i88 :: a, i89 :: a, i8A :: a, i8B :: a
  , i8C :: a, i8D :: a, i8E :: a, i8F :: a
  , i90 :: a, i91 :: a, i92 :: a, i93 :: a
  , i94 :: a, i95 :: a, i96 :: a, i97 :: a
  , i98 :: a, i99 :: a, i9A :: a, i9B :: a
  , i9C :: a, i9D :: a, i9E :: a, i9F :: a
  , iA0 :: a, iA1 :: a, iA2 :: a, iA3 :: a
  , iA4 :: a, iA5 :: a, iA6 :: a, iA7 :: a
  , iA8 :: a, iA9 :: a, iAA :: a, iAB :: a
  , iAC :: a, iAD :: a, iAE :: a, iAF :: a
  , iB0 :: a, iB1 :: a, iB2 :: a, iB3 :: a
  , iB4 :: a, iB5 :: a, iB6 :: a, iB7 :: a
  , iB8 :: a, iB9 :: a, iBA :: a, iBB :: a
  , iBC :: a, iBD :: a, iBE :: a, iBF :: a
  , iC0 :: a, iC1 :: a, iC2 :: a, iC3 :: a
  , iC4 :: a, iC5 :: a, iC6 :: a, iC7 :: a
  , iC8 :: a, iC9 :: a, iCA :: a, iCB :: a
  , iCC :: a, iCD :: a, iCE :: a, iCF :: a
  , iD0 :: a, iD1 :: a, iD2 :: a, iD3 :: a
  , iD4 :: a, iD5 :: a, iD6 :: a, iD7 :: a
  , iD8 :: a, iD9 :: a, iDA :: a, iDB :: a
  , iDC :: a, iDD :: a, iDE :: a, iDF :: a
  , iE0 :: a, iE1 :: a, iE2 :: a, iE3 :: a
  , iE4 :: a, iE5 :: a, iE6 :: a, iE7 :: a
  , iE8 :: a, iE9 :: a, iEA :: a, iEB :: a
  , iEC :: a, iED :: a, iEE :: a, iEF :: a
  , iF0 :: a, iF1 :: a, iF2 :: a, iF3 :: a
  , iF4 :: a, iF5 :: a, iF6 :: a, iF7 :: a
  , iF8 :: a, iF9 :: a, iFA :: a, iFB :: a
  , iFC :: a, iFD :: a, iFE :: a, iFF :: a
  }

instance Show a => Show (VF256 a) where
  show = show . tuples

instance Foldable VF256 where
  foldMap f =
    foldMap f .
    tolist

instance Functor VF256 where
  fmap f =
    foldl (\ a (i,x) -> update i   x a) create .
    fmap  (\   (i,x) ->       (i,f x )) .
    tuples

--------------------------------------------------------------------------------

create
  :: VF256 a
exists
  :: Word8
  -> VF256 a
  -> Bool
lookup
  :: Word8
  -> VF256 a
  ->       a
update
  :: Word8
  ->       a
  -> VF256 a
  -> VF256 a
remove
  :: Word8
  -> VF256 a
  -> VF256 a

{-# INLINE create #-}
{-# INLINE exists #-}
{-# INLINE lookup #-}
{-# INLINE update #-}
{-# INLINE remove #-}

--------------------------------------------------------------------------------

amount
  :: VF256 a
  -> Integer
bitmap
  :: VF256 a
  -> [ Bool ]
pprint
  :: VF256 a
  -> String
tuples
  :: VF256 a
  -> [ (Word8, a) ]
tolist
  :: VF256 a
  -> [a]

{-# INLINE amount #-}
{-# INLINE bitmap #-}
{-# INLINE pprint #-}
{-# INLINE tuples #-}
{-# INLINE tolist #-}

--------------------------------------------------------------------------------

create =
  VF
  0 0 0 0
  b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
  b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
  b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
  b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
  b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
  b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
  b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
  b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
  where
    b = undefined -- ⊥

exists i vf =
  bmp `seq` j `seq` bmp .?. j
  where
    (bmp,j)
      | i  <  064 = (bm0 vf, fromIntegral  i        )
      | i  <  128 = (bm1 vf, fromIntegral (i .&. 63))
      | i  <  192 = (bm2 vf, fromIntegral (i .&. 63))
      | otherwise = (bm3 vf, fromIntegral (i .&. 63))

lookup i vf =
  case i of
    000 -> i00 vf
    001 -> i01 vf
    002 -> i02 vf
    003 -> i03 vf
    004 -> i04 vf
    005 -> i05 vf
    006 -> i06 vf
    007 -> i07 vf
    008 -> i08 vf
    009 -> i09 vf
    010 -> i0A vf
    011 -> i0B vf
    012 -> i0C vf
    013 -> i0D vf
    014 -> i0E vf
    015 -> i0F vf
    016 -> i10 vf
    017 -> i11 vf
    018 -> i12 vf
    019 -> i13 vf
    020 -> i14 vf
    021 -> i15 vf
    022 -> i16 vf
    023 -> i17 vf
    024 -> i18 vf
    025 -> i19 vf
    026 -> i1A vf
    027 -> i1B vf
    028 -> i1C vf
    029 -> i1D vf
    030 -> i1E vf
    031 -> i1F vf
    032 -> i20 vf
    033 -> i21 vf
    034 -> i22 vf
    035 -> i23 vf
    036 -> i24 vf
    037 -> i25 vf
    038 -> i26 vf
    039 -> i27 vf
    040 -> i28 vf
    041 -> i29 vf
    042 -> i2A vf
    043 -> i2B vf
    044 -> i2C vf
    045 -> i2D vf
    046 -> i2E vf
    047 -> i2F vf
    048 -> i30 vf
    049 -> i31 vf
    050 -> i32 vf
    051 -> i33 vf
    052 -> i34 vf
    053 -> i35 vf
    054 -> i36 vf
    055 -> i37 vf
    056 -> i38 vf
    057 -> i39 vf
    058 -> i3A vf
    059 -> i3B vf
    060 -> i3C vf
    061 -> i3D vf
    062 -> i3E vf
    063 -> i3F vf
    064 -> i40 vf
    065 -> i41 vf
    066 -> i42 vf
    067 -> i43 vf
    068 -> i44 vf
    069 -> i45 vf
    070 -> i46 vf
    071 -> i47 vf
    072 -> i48 vf
    073 -> i49 vf
    074 -> i4A vf
    075 -> i4B vf
    076 -> i4C vf
    077 -> i4D vf
    078 -> i4E vf
    079 -> i4F vf
    080 -> i50 vf
    081 -> i51 vf
    082 -> i52 vf
    083 -> i53 vf
    084 -> i54 vf
    085 -> i55 vf
    086 -> i56 vf
    087 -> i57 vf
    088 -> i58 vf
    089 -> i59 vf
    090 -> i5A vf
    091 -> i5B vf
    092 -> i5C vf
    093 -> i5D vf
    094 -> i5E vf
    095 -> i5F vf
    096 -> i60 vf
    097 -> i61 vf
    098 -> i62 vf
    099 -> i63 vf
    100 -> i64 vf
    101 -> i65 vf
    102 -> i66 vf
    103 -> i67 vf
    104 -> i68 vf
    105 -> i69 vf
    106 -> i6A vf
    107 -> i6B vf
    108 -> i6C vf
    109 -> i6D vf
    110 -> i6E vf
    111 -> i6F vf
    112 -> i70 vf
    113 -> i71 vf
    114 -> i72 vf
    115 -> i73 vf
    116 -> i74 vf
    117 -> i75 vf
    118 -> i76 vf
    119 -> i77 vf
    120 -> i78 vf
    121 -> i79 vf
    122 -> i7A vf
    123 -> i7B vf
    124 -> i7C vf
    125 -> i7D vf
    126 -> i7E vf
    127 -> i7F vf
    128 -> i80 vf
    129 -> i81 vf
    130 -> i82 vf
    131 -> i83 vf
    132 -> i84 vf
    133 -> i85 vf
    134 -> i86 vf
    135 -> i87 vf
    136 -> i88 vf
    137 -> i89 vf
    138 -> i8A vf
    139 -> i8B vf
    140 -> i8C vf
    141 -> i8D vf
    142 -> i8E vf
    143 -> i8F vf
    144 -> i90 vf
    145 -> i91 vf
    146 -> i92 vf
    147 -> i93 vf
    148 -> i94 vf
    149 -> i95 vf
    150 -> i96 vf
    151 -> i97 vf
    152 -> i98 vf
    153 -> i99 vf
    154 -> i9A vf
    155 -> i9B vf
    156 -> i9C vf
    157 -> i9D vf
    158 -> i9E vf
    159 -> i9F vf
    160 -> iA0 vf
    161 -> iA1 vf
    162 -> iA2 vf
    163 -> iA3 vf
    164 -> iA4 vf
    165 -> iA5 vf
    166 -> iA6 vf
    167 -> iA7 vf
    168 -> iA8 vf
    169 -> iA9 vf
    170 -> iAA vf
    171 -> iAB vf
    172 -> iAC vf
    173 -> iAD vf
    174 -> iAE vf
    175 -> iAF vf
    176 -> iB0 vf
    177 -> iB1 vf
    178 -> iB2 vf
    179 -> iB3 vf
    180 -> iB4 vf
    181 -> iB5 vf
    182 -> iB6 vf
    183 -> iB7 vf
    184 -> iB8 vf
    185 -> iB9 vf
    186 -> iBA vf
    187 -> iBB vf
    188 -> iBC vf
    189 -> iBD vf
    190 -> iBE vf
    191 -> iBF vf
    192 -> iC0 vf
    193 -> iC1 vf
    194 -> iC2 vf
    195 -> iC3 vf
    196 -> iC4 vf
    197 -> iC5 vf
    198 -> iC6 vf
    199 -> iC7 vf
    200 -> iC8 vf
    201 -> iC9 vf
    202 -> iCA vf
    203 -> iCB vf
    204 -> iCC vf
    205 -> iCD vf
    206 -> iCE vf
    207 -> iCF vf
    208 -> iD0 vf
    209 -> iD1 vf
    210 -> iD2 vf
    211 -> iD3 vf
    212 -> iD4 vf
    213 -> iD5 vf
    214 -> iD6 vf
    215 -> iD7 vf
    216 -> iD8 vf
    217 -> iD9 vf
    218 -> iDA vf
    219 -> iDB vf
    220 -> iDC vf
    221 -> iDD vf
    222 -> iDE vf
    223 -> iDF vf
    224 -> iE0 vf
    225 -> iE1 vf
    226 -> iE2 vf
    227 -> iE3 vf
    228 -> iE4 vf
    229 -> iE5 vf
    230 -> iE6 vf
    231 -> iE7 vf
    232 -> iE8 vf
    233 -> iE9 vf
    234 -> iEA vf
    235 -> iEB vf
    236 -> iEC vf
    237 -> iED vf
    238 -> iEE vf
    239 -> iEF vf
    240 -> iF0 vf
    241 -> iF1 vf
    242 -> iF2 vf
    243 -> iF3 vf
    244 -> iF4 vf
    245 -> iF5 vf
    246 -> iF6 vf
    247 -> iF7 vf
    248 -> iF8 vf
    249 -> iF9 vf
    250 -> iFA vf
    251 -> iFB vf
    252 -> iFC vf
    253 -> iFD vf
    254 -> iFE vf
    255 -> iFF vf
    ___ -> undefined -- Literal is out of Word8 range

update i a vf =
  case i of
    000 -> vf { bm0 = bm0 vf .. 00, i00 = a }
    001 -> vf { bm0 = bm0 vf .. 01, i01 = a }
    002 -> vf { bm0 = bm0 vf .. 02, i02 = a }
    003 -> vf { bm0 = bm0 vf .. 03, i03 = a }
    004 -> vf { bm0 = bm0 vf .. 04, i04 = a }
    005 -> vf { bm0 = bm0 vf .. 05, i05 = a }
    006 -> vf { bm0 = bm0 vf .. 06, i06 = a }
    007 -> vf { bm0 = bm0 vf .. 07, i07 = a }
    008 -> vf { bm0 = bm0 vf .. 08, i08 = a }
    009 -> vf { bm0 = bm0 vf .. 09, i09 = a }
    010 -> vf { bm0 = bm0 vf .. 10, i0A = a }
    011 -> vf { bm0 = bm0 vf .. 11, i0B = a }
    012 -> vf { bm0 = bm0 vf .. 12, i0C = a }
    013 -> vf { bm0 = bm0 vf .. 13, i0D = a }
    014 -> vf { bm0 = bm0 vf .. 14, i0E = a }
    015 -> vf { bm0 = bm0 vf .. 15, i0F = a }
    016 -> vf { bm0 = bm0 vf .. 16, i10 = a }
    017 -> vf { bm0 = bm0 vf .. 17, i11 = a }
    018 -> vf { bm0 = bm0 vf .. 18, i12 = a }
    019 -> vf { bm0 = bm0 vf .. 19, i13 = a }
    020 -> vf { bm0 = bm0 vf .. 20, i14 = a }
    021 -> vf { bm0 = bm0 vf .. 21, i15 = a }
    022 -> vf { bm0 = bm0 vf .. 22, i16 = a }
    023 -> vf { bm0 = bm0 vf .. 23, i17 = a }
    024 -> vf { bm0 = bm0 vf .. 24, i18 = a }
    025 -> vf { bm0 = bm0 vf .. 25, i19 = a }
    026 -> vf { bm0 = bm0 vf .. 26, i1A = a }
    027 -> vf { bm0 = bm0 vf .. 27, i1B = a }
    028 -> vf { bm0 = bm0 vf .. 28, i1C = a }
    029 -> vf { bm0 = bm0 vf .. 29, i1D = a }
    030 -> vf { bm0 = bm0 vf .. 30, i1E = a }
    031 -> vf { bm0 = bm0 vf .. 31, i1F = a }
    032 -> vf { bm0 = bm0 vf .. 32, i20 = a }
    033 -> vf { bm0 = bm0 vf .. 33, i21 = a }
    034 -> vf { bm0 = bm0 vf .. 34, i22 = a }
    035 -> vf { bm0 = bm0 vf .. 35, i23 = a }
    036 -> vf { bm0 = bm0 vf .. 36, i24 = a }
    037 -> vf { bm0 = bm0 vf .. 37, i25 = a }
    038 -> vf { bm0 = bm0 vf .. 38, i26 = a }
    039 -> vf { bm0 = bm0 vf .. 39, i27 = a }
    040 -> vf { bm0 = bm0 vf .. 40, i28 = a }
    041 -> vf { bm0 = bm0 vf .. 41, i29 = a }
    042 -> vf { bm0 = bm0 vf .. 42, i2A = a }
    043 -> vf { bm0 = bm0 vf .. 43, i2B = a }
    044 -> vf { bm0 = bm0 vf .. 44, i2C = a }
    045 -> vf { bm0 = bm0 vf .. 45, i2D = a }
    046 -> vf { bm0 = bm0 vf .. 46, i2E = a }
    047 -> vf { bm0 = bm0 vf .. 47, i2F = a }
    048 -> vf { bm0 = bm0 vf .. 48, i30 = a }
    049 -> vf { bm0 = bm0 vf .. 49, i31 = a }
    050 -> vf { bm0 = bm0 vf .. 50, i32 = a }
    051 -> vf { bm0 = bm0 vf .. 51, i33 = a }
    052 -> vf { bm0 = bm0 vf .. 52, i34 = a }
    053 -> vf { bm0 = bm0 vf .. 53, i35 = a }
    054 -> vf { bm0 = bm0 vf .. 54, i36 = a }
    055 -> vf { bm0 = bm0 vf .. 55, i37 = a }
    056 -> vf { bm0 = bm0 vf .. 56, i38 = a }
    057 -> vf { bm0 = bm0 vf .. 57, i39 = a }
    058 -> vf { bm0 = bm0 vf .. 58, i3A = a }
    059 -> vf { bm0 = bm0 vf .. 59, i3B = a }
    060 -> vf { bm0 = bm0 vf .. 60, i3C = a }
    061 -> vf { bm0 = bm0 vf .. 61, i3D = a }
    062 -> vf { bm0 = bm0 vf .. 62, i3E = a }
    063 -> vf { bm0 = bm0 vf .. 63, i3F = a }
    064 -> vf { bm1 = bm1 vf .. 00, i40 = a }
    065 -> vf { bm1 = bm1 vf .. 01, i41 = a }
    066 -> vf { bm1 = bm1 vf .. 02, i42 = a }
    067 -> vf { bm1 = bm1 vf .. 03, i43 = a }
    068 -> vf { bm1 = bm1 vf .. 04, i44 = a }
    069 -> vf { bm1 = bm1 vf .. 05, i45 = a }
    070 -> vf { bm1 = bm1 vf .. 06, i46 = a }
    071 -> vf { bm1 = bm1 vf .. 07, i47 = a }
    072 -> vf { bm1 = bm1 vf .. 08, i48 = a }
    073 -> vf { bm1 = bm1 vf .. 09, i49 = a }
    074 -> vf { bm1 = bm1 vf .. 10, i4A = a }
    075 -> vf { bm1 = bm1 vf .. 11, i4B = a }
    076 -> vf { bm1 = bm1 vf .. 12, i4C = a }
    077 -> vf { bm1 = bm1 vf .. 13, i4D = a }
    078 -> vf { bm1 = bm1 vf .. 14, i4E = a }
    079 -> vf { bm1 = bm1 vf .. 15, i4F = a }
    080 -> vf { bm1 = bm1 vf .. 16, i50 = a }
    081 -> vf { bm1 = bm1 vf .. 17, i51 = a }
    082 -> vf { bm1 = bm1 vf .. 18, i52 = a }
    083 -> vf { bm1 = bm1 vf .. 19, i53 = a }
    084 -> vf { bm1 = bm1 vf .. 20, i54 = a }
    085 -> vf { bm1 = bm1 vf .. 21, i55 = a }
    086 -> vf { bm1 = bm1 vf .. 22, i56 = a }
    087 -> vf { bm1 = bm1 vf .. 23, i57 = a }
    088 -> vf { bm1 = bm1 vf .. 24, i58 = a }
    089 -> vf { bm1 = bm1 vf .. 25, i59 = a }
    090 -> vf { bm1 = bm1 vf .. 26, i5A = a }
    091 -> vf { bm1 = bm1 vf .. 27, i5B = a }
    092 -> vf { bm1 = bm1 vf .. 28, i5C = a }
    093 -> vf { bm1 = bm1 vf .. 29, i5D = a }
    094 -> vf { bm1 = bm1 vf .. 30, i5E = a }
    095 -> vf { bm1 = bm1 vf .. 31, i5F = a }
    096 -> vf { bm1 = bm1 vf .. 32, i60 = a }
    097 -> vf { bm1 = bm1 vf .. 33, i61 = a }
    098 -> vf { bm1 = bm1 vf .. 34, i62 = a }
    099 -> vf { bm1 = bm1 vf .. 35, i63 = a }
    100 -> vf { bm1 = bm1 vf .. 36, i64 = a }
    101 -> vf { bm1 = bm1 vf .. 37, i65 = a }
    102 -> vf { bm1 = bm1 vf .. 38, i66 = a }
    103 -> vf { bm1 = bm1 vf .. 39, i67 = a }
    104 -> vf { bm1 = bm1 vf .. 40, i68 = a }
    105 -> vf { bm1 = bm1 vf .. 41, i69 = a }
    106 -> vf { bm1 = bm1 vf .. 42, i6A = a }
    107 -> vf { bm1 = bm1 vf .. 43, i6B = a }
    108 -> vf { bm1 = bm1 vf .. 44, i6C = a }
    109 -> vf { bm1 = bm1 vf .. 45, i6D = a }
    110 -> vf { bm1 = bm1 vf .. 46, i6E = a }
    111 -> vf { bm1 = bm1 vf .. 47, i6F = a }
    112 -> vf { bm1 = bm1 vf .. 48, i70 = a }
    113 -> vf { bm1 = bm1 vf .. 49, i71 = a }
    114 -> vf { bm1 = bm1 vf .. 50, i72 = a }
    115 -> vf { bm1 = bm1 vf .. 51, i73 = a }
    116 -> vf { bm1 = bm1 vf .. 52, i74 = a }
    117 -> vf { bm1 = bm1 vf .. 53, i75 = a }
    118 -> vf { bm1 = bm1 vf .. 54, i76 = a }
    119 -> vf { bm1 = bm1 vf .. 55, i77 = a }
    120 -> vf { bm1 = bm1 vf .. 56, i78 = a }
    121 -> vf { bm1 = bm1 vf .. 57, i79 = a }
    122 -> vf { bm1 = bm1 vf .. 58, i7A = a }
    123 -> vf { bm1 = bm1 vf .. 59, i7B = a }
    124 -> vf { bm1 = bm1 vf .. 60, i7C = a }
    125 -> vf { bm1 = bm1 vf .. 61, i7D = a }
    126 -> vf { bm1 = bm1 vf .. 62, i7E = a }
    127 -> vf { bm1 = bm1 vf .. 63, i7F = a }
    128 -> vf { bm2 = bm2 vf .. 00, i80 = a }
    129 -> vf { bm2 = bm2 vf .. 01, i81 = a }
    130 -> vf { bm2 = bm2 vf .. 02, i82 = a }
    131 -> vf { bm2 = bm2 vf .. 03, i83 = a }
    132 -> vf { bm2 = bm2 vf .. 04, i84 = a }
    133 -> vf { bm2 = bm2 vf .. 05, i85 = a }
    134 -> vf { bm2 = bm2 vf .. 06, i86 = a }
    135 -> vf { bm2 = bm2 vf .. 07, i87 = a }
    136 -> vf { bm2 = bm2 vf .. 08, i88 = a }
    137 -> vf { bm2 = bm2 vf .. 09, i89 = a }
    138 -> vf { bm2 = bm2 vf .. 10, i8A = a }
    139 -> vf { bm2 = bm2 vf .. 11, i8B = a }
    140 -> vf { bm2 = bm2 vf .. 12, i8C = a }
    141 -> vf { bm2 = bm2 vf .. 13, i8D = a }
    142 -> vf { bm2 = bm2 vf .. 14, i8E = a }
    143 -> vf { bm2 = bm2 vf .. 15, i8F = a }
    144 -> vf { bm2 = bm2 vf .. 16, i90 = a }
    145 -> vf { bm2 = bm2 vf .. 17, i91 = a }
    146 -> vf { bm2 = bm2 vf .. 18, i92 = a }
    147 -> vf { bm2 = bm2 vf .. 19, i93 = a }
    148 -> vf { bm2 = bm2 vf .. 20, i94 = a }
    149 -> vf { bm2 = bm2 vf .. 21, i95 = a }
    150 -> vf { bm2 = bm2 vf .. 22, i96 = a }
    151 -> vf { bm2 = bm2 vf .. 23, i97 = a }
    152 -> vf { bm2 = bm2 vf .. 24, i98 = a }
    153 -> vf { bm2 = bm2 vf .. 25, i99 = a }
    154 -> vf { bm2 = bm2 vf .. 26, i9A = a }
    155 -> vf { bm2 = bm2 vf .. 27, i9B = a }
    156 -> vf { bm2 = bm2 vf .. 28, i9C = a }
    157 -> vf { bm2 = bm2 vf .. 29, i9D = a }
    158 -> vf { bm2 = bm2 vf .. 30, i9E = a }
    159 -> vf { bm2 = bm2 vf .. 31, i9F = a }
    160 -> vf { bm2 = bm2 vf .. 32, iA0 = a }
    161 -> vf { bm2 = bm2 vf .. 33, iA1 = a }
    162 -> vf { bm2 = bm2 vf .. 34, iA2 = a }
    163 -> vf { bm2 = bm2 vf .. 35, iA3 = a }
    164 -> vf { bm2 = bm2 vf .. 36, iA4 = a }
    165 -> vf { bm2 = bm2 vf .. 37, iA5 = a }
    166 -> vf { bm2 = bm2 vf .. 38, iA6 = a }
    167 -> vf { bm2 = bm2 vf .. 39, iA7 = a }
    168 -> vf { bm2 = bm2 vf .. 40, iA8 = a }
    169 -> vf { bm2 = bm2 vf .. 41, iA9 = a }
    170 -> vf { bm2 = bm2 vf .. 42, iAA = a }
    171 -> vf { bm2 = bm2 vf .. 43, iAB = a }
    172 -> vf { bm2 = bm2 vf .. 44, iAC = a }
    173 -> vf { bm2 = bm2 vf .. 45, iAD = a }
    174 -> vf { bm2 = bm2 vf .. 46, iAE = a }
    175 -> vf { bm2 = bm2 vf .. 47, iAF = a }
    176 -> vf { bm2 = bm2 vf .. 48, iB0 = a }
    177 -> vf { bm2 = bm2 vf .. 49, iB1 = a }
    178 -> vf { bm2 = bm2 vf .. 50, iB2 = a }
    179 -> vf { bm2 = bm2 vf .. 51, iB3 = a }
    180 -> vf { bm2 = bm2 vf .. 52, iB4 = a }
    181 -> vf { bm2 = bm2 vf .. 53, iB5 = a }
    182 -> vf { bm2 = bm2 vf .. 54, iB6 = a }
    183 -> vf { bm2 = bm2 vf .. 55, iB7 = a }
    184 -> vf { bm2 = bm2 vf .. 56, iB8 = a }
    185 -> vf { bm2 = bm2 vf .. 57, iB9 = a }
    186 -> vf { bm2 = bm2 vf .. 58, iBA = a }
    187 -> vf { bm2 = bm2 vf .. 59, iBB = a }
    188 -> vf { bm2 = bm2 vf .. 60, iBC = a }
    189 -> vf { bm2 = bm2 vf .. 61, iBD = a }
    190 -> vf { bm2 = bm2 vf .. 62, iBE = a }
    191 -> vf { bm2 = bm2 vf .. 63, iBF = a }
    192 -> vf { bm3 = bm3 vf .. 00, iC0 = a }
    193 -> vf { bm3 = bm3 vf .. 01, iC1 = a }
    194 -> vf { bm3 = bm3 vf .. 02, iC2 = a }
    195 -> vf { bm3 = bm3 vf .. 03, iC3 = a }
    196 -> vf { bm3 = bm3 vf .. 04, iC4 = a }
    197 -> vf { bm3 = bm3 vf .. 05, iC5 = a }
    198 -> vf { bm3 = bm3 vf .. 06, iC6 = a }
    199 -> vf { bm3 = bm3 vf .. 07, iC7 = a }
    200 -> vf { bm3 = bm3 vf .. 08, iC8 = a }
    201 -> vf { bm3 = bm3 vf .. 09, iC9 = a }
    202 -> vf { bm3 = bm3 vf .. 10, iCA = a }
    203 -> vf { bm3 = bm3 vf .. 11, iCB = a }
    204 -> vf { bm3 = bm3 vf .. 12, iCC = a }
    205 -> vf { bm3 = bm3 vf .. 13, iCD = a }
    206 -> vf { bm3 = bm3 vf .. 14, iCE = a }
    207 -> vf { bm3 = bm3 vf .. 15, iCF = a }
    208 -> vf { bm3 = bm3 vf .. 16, iD0 = a }
    209 -> vf { bm3 = bm3 vf .. 17, iD1 = a }
    210 -> vf { bm3 = bm3 vf .. 18, iD2 = a }
    211 -> vf { bm3 = bm3 vf .. 19, iD3 = a }
    212 -> vf { bm3 = bm3 vf .. 20, iD4 = a }
    213 -> vf { bm3 = bm3 vf .. 21, iD5 = a }
    214 -> vf { bm3 = bm3 vf .. 22, iD6 = a }
    215 -> vf { bm3 = bm3 vf .. 23, iD7 = a }
    216 -> vf { bm3 = bm3 vf .. 24, iD8 = a }
    217 -> vf { bm3 = bm3 vf .. 25, iD9 = a }
    218 -> vf { bm3 = bm3 vf .. 26, iDA = a }
    219 -> vf { bm3 = bm3 vf .. 27, iDB = a }
    220 -> vf { bm3 = bm3 vf .. 28, iDC = a }
    221 -> vf { bm3 = bm3 vf .. 29, iDD = a }
    222 -> vf { bm3 = bm3 vf .. 30, iDE = a }
    223 -> vf { bm3 = bm3 vf .. 31, iDF = a }
    224 -> vf { bm3 = bm3 vf .. 32, iE0 = a }
    225 -> vf { bm3 = bm3 vf .. 33, iE1 = a }
    226 -> vf { bm3 = bm3 vf .. 34, iE2 = a }
    227 -> vf { bm3 = bm3 vf .. 35, iE3 = a }
    228 -> vf { bm3 = bm3 vf .. 36, iE4 = a }
    229 -> vf { bm3 = bm3 vf .. 37, iE5 = a }
    230 -> vf { bm3 = bm3 vf .. 38, iE6 = a }
    231 -> vf { bm3 = bm3 vf .. 39, iE7 = a }
    232 -> vf { bm3 = bm3 vf .. 40, iE8 = a }
    233 -> vf { bm3 = bm3 vf .. 41, iE9 = a }
    234 -> vf { bm3 = bm3 vf .. 42, iEA = a }
    235 -> vf { bm3 = bm3 vf .. 43, iEB = a }
    236 -> vf { bm3 = bm3 vf .. 44, iEC = a }
    237 -> vf { bm3 = bm3 vf .. 45, iED = a }
    238 -> vf { bm3 = bm3 vf .. 46, iEE = a }
    239 -> vf { bm3 = bm3 vf .. 47, iEF = a }
    240 -> vf { bm3 = bm3 vf .. 48, iF0 = a }
    241 -> vf { bm3 = bm3 vf .. 49, iF1 = a }
    242 -> vf { bm3 = bm3 vf .. 50, iF2 = a }
    243 -> vf { bm3 = bm3 vf .. 51, iF3 = a }
    244 -> vf { bm3 = bm3 vf .. 52, iF4 = a }
    245 -> vf { bm3 = bm3 vf .. 53, iF5 = a }
    246 -> vf { bm3 = bm3 vf .. 54, iF6 = a }
    247 -> vf { bm3 = bm3 vf .. 55, iF7 = a }
    248 -> vf { bm3 = bm3 vf .. 56, iF8 = a }
    249 -> vf { bm3 = bm3 vf .. 57, iF9 = a }
    250 -> vf { bm3 = bm3 vf .. 58, iFA = a }
    251 -> vf { bm3 = bm3 vf .. 59, iFB = a }
    252 -> vf { bm3 = bm3 vf .. 60, iFC = a }
    253 -> vf { bm3 = bm3 vf .. 61, iFD = a }
    254 -> vf { bm3 = bm3 vf .. 62, iFE = a }
    255 -> vf { bm3 = bm3 vf .. 63, iFF = a }
    ___ -> undefined -- Literal is out of Word8 range

remove i vf =
  case i of
    000 -> vf { bm0 = bm0 vf .. 00, i00 = b }
    001 -> vf { bm0 = bm0 vf .. 01, i01 = b }
    002 -> vf { bm0 = bm0 vf .. 02, i02 = b }
    003 -> vf { bm0 = bm0 vf .. 03, i03 = b }
    004 -> vf { bm0 = bm0 vf .. 04, i04 = b }
    005 -> vf { bm0 = bm0 vf .. 05, i05 = b }
    006 -> vf { bm0 = bm0 vf .. 06, i06 = b }
    007 -> vf { bm0 = bm0 vf .. 07, i07 = b }
    008 -> vf { bm0 = bm0 vf .. 08, i08 = b }
    009 -> vf { bm0 = bm0 vf .. 09, i09 = b }
    010 -> vf { bm0 = bm0 vf .. 10, i0A = b }
    011 -> vf { bm0 = bm0 vf .. 11, i0B = b }
    012 -> vf { bm0 = bm0 vf .. 12, i0C = b }
    013 -> vf { bm0 = bm0 vf .. 13, i0D = b }
    014 -> vf { bm0 = bm0 vf .. 14, i0E = b }
    015 -> vf { bm0 = bm0 vf .. 15, i0F = b }
    016 -> vf { bm0 = bm0 vf .. 16, i10 = b }
    017 -> vf { bm0 = bm0 vf .. 17, i11 = b }
    018 -> vf { bm0 = bm0 vf .. 18, i12 = b }
    019 -> vf { bm0 = bm0 vf .. 19, i13 = b }
    020 -> vf { bm0 = bm0 vf .. 20, i14 = b }
    021 -> vf { bm0 = bm0 vf .. 21, i15 = b }
    022 -> vf { bm0 = bm0 vf .. 22, i16 = b }
    023 -> vf { bm0 = bm0 vf .. 23, i17 = b }
    024 -> vf { bm0 = bm0 vf .. 24, i18 = b }
    025 -> vf { bm0 = bm0 vf .. 25, i19 = b }
    026 -> vf { bm0 = bm0 vf .. 26, i1A = b }
    027 -> vf { bm0 = bm0 vf .. 27, i1B = b }
    028 -> vf { bm0 = bm0 vf .. 28, i1C = b }
    029 -> vf { bm0 = bm0 vf .. 29, i1D = b }
    030 -> vf { bm0 = bm0 vf .. 30, i1E = b }
    031 -> vf { bm0 = bm0 vf .. 31, i1F = b }
    032 -> vf { bm0 = bm0 vf .. 32, i20 = b }
    033 -> vf { bm0 = bm0 vf .. 33, i21 = b }
    034 -> vf { bm0 = bm0 vf .. 34, i22 = b }
    035 -> vf { bm0 = bm0 vf .. 35, i23 = b }
    036 -> vf { bm0 = bm0 vf .. 36, i24 = b }
    037 -> vf { bm0 = bm0 vf .. 37, i25 = b }
    038 -> vf { bm0 = bm0 vf .. 38, i26 = b }
    039 -> vf { bm0 = bm0 vf .. 39, i27 = b }
    040 -> vf { bm0 = bm0 vf .. 40, i28 = b }
    041 -> vf { bm0 = bm0 vf .. 41, i29 = b }
    042 -> vf { bm0 = bm0 vf .. 42, i2A = b }
    043 -> vf { bm0 = bm0 vf .. 43, i2B = b }
    044 -> vf { bm0 = bm0 vf .. 44, i2C = b }
    045 -> vf { bm0 = bm0 vf .. 45, i2D = b }
    046 -> vf { bm0 = bm0 vf .. 46, i2E = b }
    047 -> vf { bm0 = bm0 vf .. 47, i2F = b }
    048 -> vf { bm0 = bm0 vf .. 48, i30 = b }
    049 -> vf { bm0 = bm0 vf .. 49, i31 = b }
    050 -> vf { bm0 = bm0 vf .. 50, i32 = b }
    051 -> vf { bm0 = bm0 vf .. 51, i33 = b }
    052 -> vf { bm0 = bm0 vf .. 52, i34 = b }
    053 -> vf { bm0 = bm0 vf .. 53, i35 = b }
    054 -> vf { bm0 = bm0 vf .. 54, i36 = b }
    055 -> vf { bm0 = bm0 vf .. 55, i37 = b }
    056 -> vf { bm0 = bm0 vf .. 56, i38 = b }
    057 -> vf { bm0 = bm0 vf .. 57, i39 = b }
    058 -> vf { bm0 = bm0 vf .. 58, i3A = b }
    059 -> vf { bm0 = bm0 vf .. 59, i3B = b }
    060 -> vf { bm0 = bm0 vf .. 60, i3C = b }
    061 -> vf { bm0 = bm0 vf .. 61, i3D = b }
    062 -> vf { bm0 = bm0 vf .. 62, i3E = b }
    063 -> vf { bm0 = bm0 vf .. 63, i3F = b }
    064 -> vf { bm1 = bm1 vf .. 00, i40 = b }
    065 -> vf { bm1 = bm1 vf .. 01, i41 = b }
    066 -> vf { bm1 = bm1 vf .. 02, i42 = b }
    067 -> vf { bm1 = bm1 vf .. 03, i43 = b }
    068 -> vf { bm1 = bm1 vf .. 04, i44 = b }
    069 -> vf { bm1 = bm1 vf .. 05, i45 = b }
    070 -> vf { bm1 = bm1 vf .. 06, i46 = b }
    071 -> vf { bm1 = bm1 vf .. 07, i47 = b }
    072 -> vf { bm1 = bm1 vf .. 08, i48 = b }
    073 -> vf { bm1 = bm1 vf .. 09, i49 = b }
    074 -> vf { bm1 = bm1 vf .. 10, i4A = b }
    075 -> vf { bm1 = bm1 vf .. 11, i4B = b }
    076 -> vf { bm1 = bm1 vf .. 12, i4C = b }
    077 -> vf { bm1 = bm1 vf .. 13, i4D = b }
    078 -> vf { bm1 = bm1 vf .. 14, i4E = b }
    079 -> vf { bm1 = bm1 vf .. 15, i4F = b }
    080 -> vf { bm1 = bm1 vf .. 16, i50 = b }
    081 -> vf { bm1 = bm1 vf .. 17, i51 = b }
    082 -> vf { bm1 = bm1 vf .. 18, i52 = b }
    083 -> vf { bm1 = bm1 vf .. 19, i53 = b }
    084 -> vf { bm1 = bm1 vf .. 20, i54 = b }
    085 -> vf { bm1 = bm1 vf .. 21, i55 = b }
    086 -> vf { bm1 = bm1 vf .. 22, i56 = b }
    087 -> vf { bm1 = bm1 vf .. 23, i57 = b }
    088 -> vf { bm1 = bm1 vf .. 24, i58 = b }
    089 -> vf { bm1 = bm1 vf .. 25, i59 = b }
    090 -> vf { bm1 = bm1 vf .. 26, i5A = b }
    091 -> vf { bm1 = bm1 vf .. 27, i5B = b }
    092 -> vf { bm1 = bm1 vf .. 28, i5C = b }
    093 -> vf { bm1 = bm1 vf .. 29, i5D = b }
    094 -> vf { bm1 = bm1 vf .. 30, i5E = b }
    095 -> vf { bm1 = bm1 vf .. 31, i5F = b }
    096 -> vf { bm1 = bm1 vf .. 32, i60 = b }
    097 -> vf { bm1 = bm1 vf .. 33, i61 = b }
    098 -> vf { bm1 = bm1 vf .. 34, i62 = b }
    099 -> vf { bm1 = bm1 vf .. 35, i63 = b }
    100 -> vf { bm1 = bm1 vf .. 36, i64 = b }
    101 -> vf { bm1 = bm1 vf .. 37, i65 = b }
    102 -> vf { bm1 = bm1 vf .. 38, i66 = b }
    103 -> vf { bm1 = bm1 vf .. 39, i67 = b }
    104 -> vf { bm1 = bm1 vf .. 40, i68 = b }
    105 -> vf { bm1 = bm1 vf .. 41, i69 = b }
    106 -> vf { bm1 = bm1 vf .. 42, i6A = b }
    107 -> vf { bm1 = bm1 vf .. 43, i6B = b }
    108 -> vf { bm1 = bm1 vf .. 44, i6C = b }
    109 -> vf { bm1 = bm1 vf .. 45, i6D = b }
    110 -> vf { bm1 = bm1 vf .. 46, i6E = b }
    111 -> vf { bm1 = bm1 vf .. 47, i6F = b }
    112 -> vf { bm1 = bm1 vf .. 48, i70 = b }
    113 -> vf { bm1 = bm1 vf .. 49, i71 = b }
    114 -> vf { bm1 = bm1 vf .. 50, i72 = b }
    115 -> vf { bm1 = bm1 vf .. 51, i73 = b }
    116 -> vf { bm1 = bm1 vf .. 52, i74 = b }
    117 -> vf { bm1 = bm1 vf .. 53, i75 = b }
    118 -> vf { bm1 = bm1 vf .. 54, i76 = b }
    119 -> vf { bm1 = bm1 vf .. 55, i77 = b }
    120 -> vf { bm1 = bm1 vf .. 56, i78 = b }
    121 -> vf { bm1 = bm1 vf .. 57, i79 = b }
    122 -> vf { bm1 = bm1 vf .. 58, i7A = b }
    123 -> vf { bm1 = bm1 vf .. 59, i7B = b }
    124 -> vf { bm1 = bm1 vf .. 60, i7C = b }
    125 -> vf { bm1 = bm1 vf .. 61, i7D = b }
    126 -> vf { bm1 = bm1 vf .. 62, i7E = b }
    127 -> vf { bm1 = bm1 vf .. 63, i7F = b }
    128 -> vf { bm2 = bm2 vf .. 00, i80 = b }
    129 -> vf { bm2 = bm2 vf .. 01, i81 = b }
    130 -> vf { bm2 = bm2 vf .. 02, i82 = b }
    131 -> vf { bm2 = bm2 vf .. 03, i83 = b }
    132 -> vf { bm2 = bm2 vf .. 04, i84 = b }
    133 -> vf { bm2 = bm2 vf .. 05, i85 = b }
    134 -> vf { bm2 = bm2 vf .. 06, i86 = b }
    135 -> vf { bm2 = bm2 vf .. 07, i87 = b }
    136 -> vf { bm2 = bm2 vf .. 08, i88 = b }
    137 -> vf { bm2 = bm2 vf .. 09, i89 = b }
    138 -> vf { bm2 = bm2 vf .. 10, i8A = b }
    139 -> vf { bm2 = bm2 vf .. 11, i8B = b }
    140 -> vf { bm2 = bm2 vf .. 12, i8C = b }
    141 -> vf { bm2 = bm2 vf .. 13, i8D = b }
    142 -> vf { bm2 = bm2 vf .. 14, i8E = b }
    143 -> vf { bm2 = bm2 vf .. 15, i8F = b }
    144 -> vf { bm2 = bm2 vf .. 16, i90 = b }
    145 -> vf { bm2 = bm2 vf .. 17, i91 = b }
    146 -> vf { bm2 = bm2 vf .. 18, i92 = b }
    147 -> vf { bm2 = bm2 vf .. 19, i93 = b }
    148 -> vf { bm2 = bm2 vf .. 20, i94 = b }
    149 -> vf { bm2 = bm2 vf .. 21, i95 = b }
    150 -> vf { bm2 = bm2 vf .. 22, i96 = b }
    151 -> vf { bm2 = bm2 vf .. 23, i97 = b }
    152 -> vf { bm2 = bm2 vf .. 24, i98 = b }
    153 -> vf { bm2 = bm2 vf .. 25, i99 = b }
    154 -> vf { bm2 = bm2 vf .. 26, i9A = b }
    155 -> vf { bm2 = bm2 vf .. 27, i9B = b }
    156 -> vf { bm2 = bm2 vf .. 28, i9C = b }
    157 -> vf { bm2 = bm2 vf .. 29, i9D = b }
    158 -> vf { bm2 = bm2 vf .. 30, i9E = b }
    159 -> vf { bm2 = bm2 vf .. 31, i9F = b }
    160 -> vf { bm2 = bm2 vf .. 32, iA0 = b }
    161 -> vf { bm2 = bm2 vf .. 33, iA1 = b }
    162 -> vf { bm2 = bm2 vf .. 34, iA2 = b }
    163 -> vf { bm2 = bm2 vf .. 35, iA3 = b }
    164 -> vf { bm2 = bm2 vf .. 36, iA4 = b }
    165 -> vf { bm2 = bm2 vf .. 37, iA5 = b }
    166 -> vf { bm2 = bm2 vf .. 38, iA6 = b }
    167 -> vf { bm2 = bm2 vf .. 39, iA7 = b }
    168 -> vf { bm2 = bm2 vf .. 40, iA8 = b }
    169 -> vf { bm2 = bm2 vf .. 41, iA9 = b }
    170 -> vf { bm2 = bm2 vf .. 42, iAA = b }
    171 -> vf { bm2 = bm2 vf .. 43, iAB = b }
    172 -> vf { bm2 = bm2 vf .. 44, iAC = b }
    173 -> vf { bm2 = bm2 vf .. 45, iAD = b }
    174 -> vf { bm2 = bm2 vf .. 46, iAE = b }
    175 -> vf { bm2 = bm2 vf .. 47, iAF = b }
    176 -> vf { bm2 = bm2 vf .. 48, iB0 = b }
    177 -> vf { bm2 = bm2 vf .. 49, iB1 = b }
    178 -> vf { bm2 = bm2 vf .. 50, iB2 = b }
    179 -> vf { bm2 = bm2 vf .. 51, iB3 = b }
    180 -> vf { bm2 = bm2 vf .. 52, iB4 = b }
    181 -> vf { bm2 = bm2 vf .. 53, iB5 = b }
    182 -> vf { bm2 = bm2 vf .. 54, iB6 = b }
    183 -> vf { bm2 = bm2 vf .. 55, iB7 = b }
    184 -> vf { bm2 = bm2 vf .. 56, iB8 = b }
    185 -> vf { bm2 = bm2 vf .. 57, iB9 = b }
    186 -> vf { bm2 = bm2 vf .. 58, iBA = b }
    187 -> vf { bm2 = bm2 vf .. 59, iBB = b }
    188 -> vf { bm2 = bm2 vf .. 60, iBC = b }
    189 -> vf { bm2 = bm2 vf .. 61, iBD = b }
    190 -> vf { bm2 = bm2 vf .. 62, iBE = b }
    191 -> vf { bm2 = bm2 vf .. 63, iBF = b }
    192 -> vf { bm3 = bm3 vf .. 00, iC0 = b }
    193 -> vf { bm3 = bm3 vf .. 01, iC1 = b }
    194 -> vf { bm3 = bm3 vf .. 02, iC2 = b }
    195 -> vf { bm3 = bm3 vf .. 03, iC3 = b }
    196 -> vf { bm3 = bm3 vf .. 04, iC4 = b }
    197 -> vf { bm3 = bm3 vf .. 05, iC5 = b }
    198 -> vf { bm3 = bm3 vf .. 06, iC6 = b }
    199 -> vf { bm3 = bm3 vf .. 07, iC7 = b }
    200 -> vf { bm3 = bm3 vf .. 08, iC8 = b }
    201 -> vf { bm3 = bm3 vf .. 09, iC9 = b }
    202 -> vf { bm3 = bm3 vf .. 10, iCA = b }
    203 -> vf { bm3 = bm3 vf .. 11, iCB = b }
    204 -> vf { bm3 = bm3 vf .. 12, iCC = b }
    205 -> vf { bm3 = bm3 vf .. 13, iCD = b }
    206 -> vf { bm3 = bm3 vf .. 14, iCE = b }
    207 -> vf { bm3 = bm3 vf .. 15, iCF = b }
    208 -> vf { bm3 = bm3 vf .. 16, iD0 = b }
    209 -> vf { bm3 = bm3 vf .. 17, iD1 = b }
    210 -> vf { bm3 = bm3 vf .. 18, iD2 = b }
    211 -> vf { bm3 = bm3 vf .. 19, iD3 = b }
    212 -> vf { bm3 = bm3 vf .. 20, iD4 = b }
    213 -> vf { bm3 = bm3 vf .. 21, iD5 = b }
    214 -> vf { bm3 = bm3 vf .. 22, iD6 = b }
    215 -> vf { bm3 = bm3 vf .. 23, iD7 = b }
    216 -> vf { bm3 = bm3 vf .. 24, iD8 = b }
    217 -> vf { bm3 = bm3 vf .. 25, iD9 = b }
    218 -> vf { bm3 = bm3 vf .. 26, iDA = b }
    219 -> vf { bm3 = bm3 vf .. 27, iDB = b }
    220 -> vf { bm3 = bm3 vf .. 28, iDC = b }
    221 -> vf { bm3 = bm3 vf .. 29, iDD = b }
    222 -> vf { bm3 = bm3 vf .. 30, iDE = b }
    223 -> vf { bm3 = bm3 vf .. 31, iDF = b }
    224 -> vf { bm3 = bm3 vf .. 32, iE0 = b }
    225 -> vf { bm3 = bm3 vf .. 33, iE1 = b }
    226 -> vf { bm3 = bm3 vf .. 34, iE2 = b }
    227 -> vf { bm3 = bm3 vf .. 35, iE3 = b }
    228 -> vf { bm3 = bm3 vf .. 36, iE4 = b }
    229 -> vf { bm3 = bm3 vf .. 37, iE5 = b }
    230 -> vf { bm3 = bm3 vf .. 38, iE6 = b }
    231 -> vf { bm3 = bm3 vf .. 39, iE7 = b }
    232 -> vf { bm3 = bm3 vf .. 40, iE8 = b }
    233 -> vf { bm3 = bm3 vf .. 41, iE9 = b }
    234 -> vf { bm3 = bm3 vf .. 42, iEA = b }
    235 -> vf { bm3 = bm3 vf .. 43, iEB = b }
    236 -> vf { bm3 = bm3 vf .. 44, iEC = b }
    237 -> vf { bm3 = bm3 vf .. 45, iED = b }
    238 -> vf { bm3 = bm3 vf .. 46, iEE = b }
    239 -> vf { bm3 = bm3 vf .. 47, iEF = b }
    240 -> vf { bm3 = bm3 vf .. 48, iF0 = b }
    241 -> vf { bm3 = bm3 vf .. 49, iF1 = b }
    242 -> vf { bm3 = bm3 vf .. 50, iF2 = b }
    243 -> vf { bm3 = bm3 vf .. 51, iF3 = b }
    244 -> vf { bm3 = bm3 vf .. 52, iF4 = b }
    245 -> vf { bm3 = bm3 vf .. 53, iF5 = b }
    246 -> vf { bm3 = bm3 vf .. 54, iF6 = b }
    247 -> vf { bm3 = bm3 vf .. 55, iF7 = b }
    248 -> vf { bm3 = bm3 vf .. 56, iF8 = b }
    249 -> vf { bm3 = bm3 vf .. 57, iF9 = b }
    250 -> vf { bm3 = bm3 vf .. 58, iFA = b }
    251 -> vf { bm3 = bm3 vf .. 59, iFB = b }
    252 -> vf { bm3 = bm3 vf .. 60, iFC = b }
    253 -> vf { bm3 = bm3 vf .. 61, iFD = b }
    254 -> vf { bm3 = bm3 vf .. 62, iFE = b }
    255 -> vf { bm3 = bm3 vf .. 63, iFF = b }
    ___ -> undefined -- Literal is out of Word8 range
  where
    b = undefined -- ⊥

--------------------------------------------------------------------------------

amount vf =
  fromIntegral $
  (.#.) (bm0 vf) +
  (.#.) (bm1 vf) +
  (.#.) (bm2 vf) +
  (.#.) (bm3 vf)

bitmap vf =
  map (bm0 vf .?.) [ 0 .. 63 ] ++
  map (bm1 vf .?.) [ 0 .. 63 ] ++
  map (bm2 vf .?.) [ 0 .. 63 ] ++
  map (bm3 vf .?.) [ 0 .. 63 ]

pprint =
  map (\x -> if x then '▣' else '□') . bitmap

tuples vf =
  aux 0 $ bitmap vf
  where
    aux _ [          ] =                            []
    aux i (False : xs) = i `seq`          aux (i+1) xs
    aux i (True  : xs) = l `seq` (i, l) : aux (i+1) xs
      where
        l = lookup i vf

tolist =
  map snd . tuples

--------------------------------------------------------------------------------

-- HELPERS

(.?.)
  :: Bits a
  =>      a
  -> Int
  -> Bool
(..)
  :: Bits a
  =>      a
  -> Int
  ->      a
(..)
  :: Bits a
  =>      a
  -> Int
  ->      a
(.#.)
  :: Bits a
  =>      a
  -> Int

{-# INLINE (.?.) #-}
{-# INLINE (.■.) #-}
{-# INLINE (.□.) #-}
{-# INLINE (.#.) #-}

(.?.) = testBit
(..) = setBit
(..) = clearBit
(.#.) = popCount

exe/ArrayLog.hs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
--------------------------------------------------------------------------------
--
-- ArrayLog, (c) 2020 SPISE MISU ApS
--
--------------------------------------------------------------------------------

{-# LANGUAGE Safe #-}

--------------------------------------------------------------------------------

module Main (main) where

--------------------------------------------------------------------------------

import           Prelude           hiding
  ( length
  , lookup
  )

import           Data.Array.Log256

--------------------------------------------------------------------------------

main :: IO ()
main =
  (putStrLn "# Before fmap")     >>
  (putStrLn . show . tuples $ a) >>
  (putStrLn . pprint        $ a) >>
  (putStrLn "")                  >>

  (putStrLn "# After fmap")      >>
  (putStrLn . show . tuples $ b) >>
  (putStrLn . pprint        $ b) >>
  (putStrLn "")                  >>

  (putStrLn "# Sparse (create)") >>
  (putStrLn . show   $ sparse a) >>
  (putStrLn "")                  >>

  (putStrLn "# Sparse (sliver)") >>
  (putStrLn . show   $ sparse s) >>
  (putStrLn . pprint        $ s) >>
  (putStrLn "")                  >>

  (putStrLn "# Sparse (expand)") >>
  (putStrLn . show   $ sparse e) >>
  (putStrLn . pprint        $ e) >>
  (putStrLn "")                  >>

  (putStrLn "# Sparse (defrag)") >>
  (putStrLn . show   $ sparse d) >>
  (putStrLn . pprint        $ d)
  where
    n = 300
    m = 150
    --
    a = foldl (\ acc x -> update x x acc) (create n) $ take m [ 0 .. ]
    b = fmap (*2) a
    --
    i = 050
    o = 100
    s = sliver i o b
    --
    e = expand 65536 s
    --
    d = defrag e

arraylog.cabal

cabal-version:   2.2

--------------------------------------------------------------------------------
--
-- ArrayLog, (c) 2020 SPISE MISU ApS
--
--------------------------------------------------------------------------------

build-type:      Simple

name:            arraylog
version:         0.11.0.0

synopsis:        Data.Array.Log256 (SAFE, idiomatic and bottom).
description:     Data.Array.Log256 (SAFE, idiomatic and bottom). 

homepage:        https://gitlab.com/spisemisu/arraylog

license:         AGPL-3.0-only
license-file:    LICENSE.md

author:          Don Juan de la Cierva
maintainer:      Don Juan de la Cierva

category:        Safe and idiomatic Data Structures

                
--------------------------------------------------------------------------------
-- COMMON
--------------------------------------------------------------------------------

common both
  default-language:
      Haskell98
  ghc-options:
      --------------------------------------------------------------------------
      -- GHC 8.6.5 Users Guide
      -- 9. Using GHC > 9.2. Warnings and sanity-checking
      -- * Base: https://downloads.haskell.org/~ghc/8.6.5/docs/html/users_guide/
      -- * File: using-warnings.html
      -- Warnings that are not enabled by -Wall:
      --------------------------------------------------------------------------
      -Wall
      -Wincomplete-record-updates
      -- -Wmonomorphism-restriction
      -- -Wimplicit-prelude
      -- -Wmissing-local-signatures
      -Wmissing-exported-signatures
      -- -Wmissing-export-lists
      -- -Wmissing-import-lists
      -Wmissing-home-modules
      -Widentities
      -Wredundant-constraints
      -- Added since GHC 8.4
      -Wpartial-fields 
      -- -Wmissed-specialisations
      -- -Wall-missed-specialisations
      --------------------------------------------------------------------------
      -- Added to allow instance definition in other files, in order to keep the 
      -- Effect module SAFE so it can be imported by the Process
      --------------------------------------------------------------------------
      -Wno-orphans
      -- Makes any warning into a fatal error.
      -Werror
      --------------------------------------------------------------------------
      -- Deterministic builds (Uniques):
      -- * https://gitlab.haskell.org/ghc/ghc/wikis/deterministic-builds#progress
      -- * https://www.youtube.com/watch?v=FNzTk4P4fL4 (08 GHC Determinism ICFP)
      --------------------------------------------------------------------------
      -dinitial-unique=0
      -dunique-increment=1
      --------------------------------------------------------------------------
      -- GHC 8.6.5 Users Guide
      -- 19. Known bugs and infelicities >
      -- 19.1. Haskell standards vs. Glasgow Haskell: language non-compliance >
      -- 19.1.1.3. Expressions and patterns
      -- * Base: https://downloads.haskell.org/~ghc/8.6.5/docs/html/users_guide/
      -- * File: bugs.html
      --------------------------------------------------------------------------
      -fpedantic-bottoms
      -- To use when GHC uses to many ticks:
      -- -ddump-simpl-stats
      -- -fsimpl-tick-factor=100
      --------------------------------------------------------------------------
      
common libs
  default-extensions:
      Safe
  ghc-options:
      --------------------------------------------------------------------------
      -- GHC 8.6.5 Users Guide
      -- 12.40. Safe Haskell > ... > 12.40.1.1. Strict type-safety (good style)
      -- * Enforce good style, similar to the function of -Wall.
      -- Only Trustworthy packages can be trusted
      -- * Base: https://downloads.haskell.org/~ghc/8.6.5/docs/html/users_guide/
      -- * File: safe_haskell.html
      --------------------------------------------------------------------------
      -fpackage-trust
      -trust=base
      --------------------------------------------------------------------------
        
common bins
  default-extensions:
      Safe
  ghc-options:
      --------------------------------------------------------------------------
      -- GHC 8.6.5 Users Guide
      -- 12.40. Safe Haskell > ... > 12.40.1.1. Strict type-safety (good style)
      -- * Enforce good style, similar to the function of -Wall.
      -- Only Trustworthy packages can be trusted
      -- * Base: https://downloads.haskell.org/~ghc/8.6.5/docs/html/users_guide/
      -- * File: safe_haskell.html
      --------------------------------------------------------------------------
      -fpackage-trust
      -trust=base
      --------------------------------------------------------------------------
      -- GHC 8.6.5 Users Guide
      -- 9.3. Optimisation (code improvement)
      -- * Base: https://downloads.haskell.org/~ghc/8.6.5/docs/html/users_guide/
      -- * File: using-optimisation.html
      --------------------------------------------------------------------------
      -O2
      -- -threaded
      -- -rtsopts
      -- -with-rtsopts=-N
      --------------------------------------------------------------------------
      -- The -N flag built-in can be modified on runtime based on the system
      -- hosting the binary for optimal performance:
      -- - https://hackage.haskell.org/package/base/docs/GHC-Conc.html
      --   * getNumProcessors
      -- - https://hackage.haskell.org/package/base/docs/Control-Concurrent.html
      --   * setNumCapabilities
      --------------------------------------------------------------------------

      
--------------------------------------------------------------------------------
-- LIBRARY
--------------------------------------------------------------------------------

library 
  import:
      both
    , libs
  hs-source-dirs:
      src
  exposed-modules:
      Data.Array.Log256
    , Data.Vector.Fixed256
  build-depends:
      -- Prelude
      base >= 4 && < 5
                  

--------------------------------------------------------------------------------
-- EXECUTABLES
--------------------------------------------------------------------------------

executable arraylog
  import:
      both
    , bins
  main-is:
      ArrayLog.hs
  hs-source-dirs:
      exe
  build-depends:
      arraylog
      -- Prelude
    , base >= 4 && < 5

            
--------------------------------------------------------------------------------
-- REFERENCES
--------------------------------------------------------------------------------
-- HaskellStarter/haskell-starter.cabal:
-- https://github.com/joshcough/HaskellStarter/blob/master/haskell-starter.cabal
--------------------------------------------------------------------------------

stack.yaml

resolver: lts-14.27
packages:
  - .
nix:
  enable: true
  packages: []
  path: [
    "nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/d858110.tar.gz"
  ]
  
## Reference
# Stack:
# - https://www.stackage.org/lts-14.27
# NixOS:
# - https://github.com/NixOS/nixpkgs-channels/branches/active
# - https://github.com/NixOS/nixpkgs-channels/tree/nixos-19.09
# - https://github.com/NixOS/nixpkgs-channels/tree/d858110
# - https://github.com/NixOS/nixpkgs-channels/archive/d858110.tar.gz

build.bash (real: 30m7.777s, user: 29m52.651s and sys: 0m15.487s)

#!/usr/bin/env bash

clear

bld="$(pwd)/.stack-work/install/x86_64-linux-nix/"
tgt="$(pwd)/bin"

echo "### Ensure folders exist:"
mkdir -v -p $bld;
mkdir -v -p $tgt;
echo

echo "### Clearing binaries:"
find $bld -mindepth 1 -name "*" -delete -print
find $tgt -mindepth 1 -name "*" -delete -print
echo

echo "### Stack building:" 
#stack clean
#stack build --verbosity debug
#stack build --fast
stack build
echo

src="$(stack path --local-install-root)/bin"

echo "### Copying binaries to local $tgt:" 
cp -v $src/* $tgt/
echo

echo "### Repoducible hashes:"
cd $tgt
for f in *; do
    # skip all non-binaries
    [[ $f == *.* ]] && continue
    echo -e $(sha256sum $f | cut -d " " -f 1): $f
done;
echo

Code Output:

Terminal ouput of executing ./bin/arraylog

References: