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
|
-------------------------------------------------------------
-- |
-- Module : Data.IntTrie
-- Copyright : (c) Luke Palmer 2010
-- License : BSD3
--
-- Maintainer : Luke Palmer <lrpalmer@gmail.com>
-- Stability : experimental
-- Portability : Haskell 2010
--
-- Provides a minimal infinite, lazy trie for integral types.
-- It intentionally leaves out ideas such as delete and
-- emptiness so that it can be used lazily, eg. as the target
-- of an infinite foldr. Essentially its purpose is to be an
-- efficient implementation of a function from integral type,
-- given point-at-a-time modifications.
-------------------------------------------------------------
module Data.IntTrie
( IntTrie, identity, apply, modify, modify', overwrite,
mirror, modifyAscList, modifyDescList )
where
import Control.Applicative
import Control.Arrow (first, second)
import Data.Bits
import Data.Function (fix)
import Data.Monoid (Monoid(..))
import Data.Semigroup (Semigroup(..))
-- | A trie from integers to values of type a.
--
-- Semantics: [[IntTrie a]] = Integer -> a
data IntTrie a = IntTrie (BitTrie a) a (BitTrie a) -- negative, 0, positive
data BitTrie a = BitTrie a (BitTrie a) (BitTrie a)
instance Functor BitTrie where
fmap f ~(BitTrie x l r) = BitTrie (f x) (fmap f l) (fmap f r)
instance Applicative BitTrie where
pure x = fix (\g -> BitTrie x g g)
~(BitTrie f fl fr) <*> ~(BitTrie x xl xr) = BitTrie (f x) (fl <*> xl) (fr <*> xr)
instance Semigroup a => Semigroup (BitTrie a) where
(<>) = liftA2 (<>)
instance Monoid a => Monoid (BitTrie a) where
mempty = pure mempty
mappend = liftA2 mappend
instance Functor IntTrie where
fmap f ~(IntTrie neg z pos) = IntTrie (fmap f neg) (f z) (fmap f pos)
instance Applicative IntTrie where
pure x = IntTrie (pure x) x (pure x)
IntTrie fneg fz fpos <*> IntTrie xneg xz xpos =
IntTrie (fneg <*> xneg) (fz xz) (fpos <*> xpos)
instance Semigroup a => Semigroup (IntTrie a) where
(<>) = liftA2 (<>)
instance Monoid a => Monoid (IntTrie a) where
mempty = pure mempty
mappend = liftA2 mappend
-- | Apply the trie to an argument. This is the semantic map.
apply :: (Ord b, Num b, Bits b) => IntTrie a -> b -> a
apply (IntTrie neg z pos) x =
case compare x 0 of
LT -> applyPositive neg (-x)
EQ -> z
GT -> applyPositive pos x
applyPositive :: (Num b, Bits b) => BitTrie a -> b -> a
applyPositive (BitTrie one even odd) x
| x == 1 = one
| testBit x 0 = applyPositive odd (x `shiftR` 1)
| otherwise = applyPositive even (x `shiftR` 1)
-- | The identity trie.
--
-- > apply identity = id
identity :: (Num a, Bits a) => IntTrie a
identity = IntTrie (fmap negate identityPositive) 0 identityPositive
identityPositive :: (Num a, Bits a) => BitTrie a
identityPositive = go
where
go = BitTrie 1 (fmap (`shiftL` 1) go) (fmap (\n -> (n `shiftL` 1) .|. 1) go)
-- | Modify the function at one point
--
-- > apply (modify x f t) i | i == x = f (apply t i)
-- > | otherwise = apply t i
modify :: (Ord b, Num b, Bits b) => b -> (a -> a) -> IntTrie a -> IntTrie a
modify x f ~(IntTrie neg z pos) =
case compare x 0 of
LT -> IntTrie (modifyPositive (-x) f neg) z pos
EQ -> IntTrie neg (f z) pos
GT -> IntTrie neg z (modifyPositive x f pos)
modifyPositive :: (Num b, Bits b) => b -> (a -> a) -> BitTrie a -> BitTrie a
modifyPositive x f ~(BitTrie one even odd)
| x == 1 = BitTrie (f one) even odd
| testBit x 0 = BitTrie one even (modifyPositive (x `shiftR` 1) f odd)
| otherwise = BitTrie one (modifyPositive (x `shiftR` 1) f even) odd
-- | Modify the function at one point (strict version)
modify' :: (Ord b, Num b, Bits b) => b -> (a -> a) -> IntTrie a -> IntTrie a
modify' x f (IntTrie neg z pos) =
case compare x 0 of
LT -> (IntTrie $! modifyPositive' (-x) f neg) z pos
EQ -> (IntTrie neg $! f z) pos
GT -> IntTrie neg z $! modifyPositive' x f pos
modifyPositive' :: (Num b, Bits b) => b -> (a -> a) -> BitTrie a -> BitTrie a
modifyPositive' x f (BitTrie one even odd)
| x == 1 = (BitTrie $! f one) even odd
| testBit x 0 = BitTrie one even $! modifyPositive' (x `shiftR` 1) f odd
| otherwise = (BitTrie one $! modifyPositive' (x `shiftR` 1) f even) odd
-- | Overwrite the function at one point
--
-- > overwrite i x = modify i (const x)
overwrite :: (Ord b, Num b, Bits b) => b -> a -> IntTrie a -> IntTrie a
overwrite i x = modify i (const x)
-- | Negate the domain of the function
--
-- > apply (mirror t) i = apply t (-i)
-- > mirror . mirror = id
mirror :: IntTrie a -> IntTrie a
mirror ~(IntTrie neg z pos) = IntTrie pos z neg
-- | Modify the function at a (potentially infinite) list of points in ascending order
--
-- > modifyAscList [(i0, f0)..(iN, fN)] = modify i0 f0 . ... . modify iN fN
modifyAscList :: (Ord b, Num b, Bits b) => [(b, a -> a)] -> IntTrie a -> IntTrie a
modifyAscList ifs ~t@(IntTrie neg z pos) =
case break ((>= 0) . fst) ifs of
([], []) -> t
(nifs, (0, f):pifs) -> IntTrie (modifyAscListNegative nifs neg) (f z)
(modifyAscListPositive pifs pos)
(nifs, pifs) -> IntTrie (modifyAscListNegative nifs neg) z
(modifyAscListPositive pifs pos)
where modifyAscListNegative = modifyAscListPositive . map (first negate) . reverse
-- | Modify the function at a (potentially infinite) list of points in descending order
modifyDescList :: (Ord b, Num b, Bits b) => [(b, a -> a)] -> IntTrie a -> IntTrie a
modifyDescList ifs = mirror . modifyAscList (map (first negate) ifs) . mirror
modifyAscListPositive :: (Ord b, Num b, Bits b) => [(b, a -> a)] -> BitTrie a -> BitTrie a
modifyAscListPositive [] t = t
modifyAscListPositive ((0, _):_) _ =
error "modifyAscList: expected strictly monotonic indices"
modifyAscListPositive ifs@((i, f):_) ~(BitTrie one even odd) = BitTrie one' even' odd' where
(one', ifs') = if i == 1 then (f one, tail ifs) else (one, ifs)
even' = modifyAscListPositive ifsEven even
odd' = modifyAscListPositive ifsOdd odd
(ifsOdd, ifsEven) = both (map $ first (`shiftR` 1)) $ partitionIndices ifs'
both f (x, y) = (f x, f y)
-- Like `partition (flip testBit 0 . fst)`, except that this version addresses the
-- problem of infinite lists of only odd or only even indices by injecting an `id`
-- into the other result list wherever there are two evens or two odds in a row.
-- This allows `modifyAscListPositive` to return a value as soon as the next index is
-- higher than the current location in the trie instead of scanning for the end of
-- the list, which for infinite lists may never be reached.
partitionIndices :: (Num b, Bits b) => [(b, a -> a)] -> ([(b, a -> a)], [(b, a -> a)])
partitionIndices [] = ([], [])
partitionIndices [x] = if testBit (fst x) 0 then ([x], []) else ([], [x])
partitionIndices (x:xs@(y:_)) = case testBit (fst x) 0 of
False -> (if testBit (fst y) 0 then odd else pad:odd, x:even)
True -> (x:odd, if testBit (fst y) 0 then pad:even else even)
where ~(odd, even) = partitionIndices xs
pad = (fst y - 1, id)
|