/src/MemoTrie.hs

http://github.com/Eelis/geordi · Haskell · 78 lines · 41 code · 15 blank · 22 comment · 3 complexity · 93374f4e75627b05b695eda992eeff8d MD5 · raw file

  1. {-# LANGUAGE UnicodeSyntax, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances #-}
  2. {- Adapted from Conal Elliott's MemoTree package. ( http://haskell.org/haskellwiki/MemoTrie )
  3. We don't just use that package, because it is affected by this bug:
  4. http://hackage.haskell.org/trac/ghc/ticket/2888
  5. This implementation works around that bug by using functional dependencies and multi-param type classes instead of type families.
  6. -}
  7. module MemoTrie (Trie(..), memo, PairTrie(..), BoolTrie(..)) where
  8. import qualified Data.Char as Char
  9. import qualified Data.Bits as Bits
  10. class Trie a t | a t where
  11. trie :: (a b) (t b)
  12. untrie :: (t b) (a b)
  13. memo :: Trie b t (b a) (b a)
  14. memo = untrie . trie
  15. data UnitTrie a = UnitTrie a
  16. instance Trie () UnitTrie where
  17. trie f = UnitTrie (f ())
  18. untrie (UnitTrie a) = const a
  19. data BoolTrie a = BoolTrie a a
  20. instance Trie Bool BoolTrie where
  21. trie f = BoolTrie (f False) (f True)
  22. untrie (BoolTrie f t) b = if b then t else f
  23. data EitherTrie ta tb x = EitherTrie (ta x) (tb x)
  24. instance (Trie a ta, Trie b tb) Trie (Either a b) (EitherTrie ta tb) where
  25. trie f = EitherTrie (trie (f . Left)) (trie (f . Right))
  26. untrie (EitherTrie s t) = either (untrie s) (untrie t)
  27. data PairTrie ta tb x = PairTrie (ta (tb x))
  28. instance (Trie a ta, Trie b tb) Trie (a, b) (PairTrie ta tb) where
  29. trie f = PairTrie (trie (trie . curry f))
  30. untrie (PairTrie t) = uncurry (untrie . untrie t)
  31. data ListTrie tx x = ListTrie x (tx (ListTrie tx x))
  32. instance Trie x tx Trie [x] (ListTrie tx) where
  33. trie f = ListTrie (f []) (trie (\y trie $ f . (y:)))
  34. untrie (ListTrie p _) [] = p
  35. untrie (ListTrie _ q) (h:t) = untrie (untrie q h) t
  36. bits :: (Num t, Bits.Bits t) t [Bool]
  37. bits 0 = []
  38. bits x = Bits.testBit x 0 : bits (Bits.shiftR x 1)
  39. unbit :: Num t Bool t
  40. unbit False = 0
  41. unbit True = 1
  42. unbits :: (Num t, Bits.Bits t) [Bool] t
  43. unbits [] = 0
  44. unbits (x:xs) = (Bits..|.) (unbit x) (Bits.shiftL (unbits xs) 1)
  45. instance Trie Char (ListTrie BoolTrie) where
  46. trie f = trie (f . Char.chr . unbits)
  47. untrie t = untrie t . bits . Char.ord
  48. {- Test:
  49. f :: String Integer
  50. f = memo $ \l case l of
  51. [] 1
  52. (h:t) (if Char.isAlpha h then 2 else 1) * slow_func t + slow_func t
  53. out = slow_func $ take 21 $ cycle "a9d55"
  54. Replacing memo with id makes f much slower.
  55. -}