chriswarbo-net: 9df81800d9b672a7612987eb22daee258d8a91d6

     1: ---
     2: title: Naturals Search
     3: ---
     4: I came across this interesting pattern a while ago, while taking
     5: my first substantial steps in Haskell, and thought I'd blog it.
     6: 
     7: It's a logarithmic time search over the Naturals, for any
     8: predicate where we can tell if a number's too big. I use it
     9: here to implement square-root:
    10: 
    11: We define an `ITree`{.haskell} as a tree of integers. Each node can either
    12: be a leaf, containing an `Integer`{.haskell}, or a node containing an
    13: `Integer`{.haskell} and two sub-trees:
    14: 
    15: ```haskell
    16: data ITree = IL Integer | IN Integer ITree ITree
    17: ```
    18: 
    19: This tells us how to show an `ITree`{.haskell} so that we can use
    20: printf-debugging:
    21: 
    22: ```haskell
    23: instance Show ITree where
    24:   show (IL x) = "(" ++ show x ++ ")"
    25:   show (IN x l r) = "(" ++ show x ++ " " ++ show l ++ " " ++ show r ++ ")"
    26: ```
    27: 
    28: This is an `ITree`{.haskell}, and in fact is the only one we need.
    29: It is constructed lazily, and has the following shape:
    30: 
    31: ```
    32:   1
    33:  / \
    34: 1   2
    35:    / \
    36:   2   4
    37:      / \
    38:     3   \
    39:    / \   \
    40:   3  4    \
    41:            8
    42:           / \
    43:          6   \
    44:         / \   .
    45:        /   \   .
    46:       5     7   .
    47:      / \   / \
    48:     5   6 7   8
    49: ```
    50: 
    51: The idea is that the right-most branches count up in powers of
    52: `2`{.haskell} forever. The branches coming off on the left contain a leaf
    53: for each of the numbers between this power of `2`{.haskell} and the previous
    54: (eg. the branch coming off `8`{.haskell} contains leaves for `5`{.haskell}, `6`{.haskell}, `7`{.haskell} and `8`{.haskell}).
    55: These are spread out by splitting into above/below the average
    56: value which we stick on the node.
    57: 
    58: ```haskell
    59: iTree = let biTree l h | l == h    = IL l
    60:                        | otherwise = let m = avgI l h in
    61:                                          IN m (biTree l m) (biTree (m + 1) h)
    62:             from x = IN (2^x) (biTree (2^(x-1) + 1) (2^x)) (from (x+1)) in
    63:             IN 1 (IL 1) $ IN 2 (IL 2) $ from 2
    64: ```
    65: 
    66: This function finds the largest number which doesn't trigger the
    67: given `tooHigh`{.haskell} function. It does this by traversing `iTree`{.haskell}: it
    68: keeps going right until `tooHigh`{.haskell} becomes `True`{.haskell}, then it snakes down
    69: the left sub-tree, hugging the `tooHigh`{.haskell} boundary until it hits a
    70: leaf.
    71: 
    72: ```haskell
    73: find tooHigh = let f (IN x l r) = if tooHigh x
    74:                                      then f l
    75:                                      else f r
    76:                    f (IL x)     = x in
    77:                    f iTree
    78: ```
    79: 
    80: This is a simple example which uses `iTree`{.haskell} to find the integer
    81: square root of a number.
    82: 
    83: ```haskell
    84: sqrtI :: Integer -> Integer
    85: sqrtI n | n <= 1    = 1
    86: sqrtI n | otherwise = find $ (> n) . (^ 2)
    87: ```
    88: 
    89: Here's a `QuickCheck`{.haskell} property to verify that it's correct.
    90: 
    91: ```haskell
    92: prop_sqrtI n = let root = sqrtI n
    93:                    lower = (root - 1)^2
    94:                    higher = (root + 1)^2 in
    95:                    n > 0 ==> lower <= n && higher >= n
    96: ```
    97: 
    98: Anyone know what this `iTree`{.haskell} structure is called?

Generated by git2html.