Naturals Search
I came across this interesting pattern a while ago, while taking my first substantial steps in Haskell, and thought I’d blog it.
It’s a logarithmic time search over the Naturals, for any predicate where we can tell if a number’s too big. I use it here to implement square-root:
We define an ITree
as a
tree of integers. Each node can either be a leaf, containing an Integer
, or a
node containing an Integer
and
two sub-trees:
data ITree = IL Integer | IN Integer ITree ITree
This tells us how to show an ITree
so that
we can use printf-debugging:
instance Show ITree where
show (IL x) = "(" ++ show x ++ ")"
show (IN x l r) = "(" ++ show x ++ " " ++ show l ++ " " ++ show r ++ ")"
This is an ITree
, and in
fact is the only one we need. It is constructed lazily, and has the
following shape:
1
/ \
1 2
/ \
2 4
/ \
3 \
/ \ \
3 4 \
8
/ \
6 \
/ \ .
/ \ .
5 7 .
/ \ / \
5 6 7 8
The idea is that the right-most branches count up in powers of 2
forever. The
branches coming off on the left contain a leaf for each of the numbers
between this power of 2
and the
previous (eg. the branch coming off 8
contains
leaves for 5
, 6
, 7
and 8
). These are
spread out by splitting into above/below the average value which we
stick on the node.
= let biTree l h | l == h = IL l
iTree | otherwise = let m = avgI l h in
IN m (biTree l m) (biTree (m + 1) h)
= IN (2^x) (biTree (2^(x-1) + 1) (2^x)) (from (x+1)) in
from x IN 1 (IL 1) $ IN 2 (IL 2) $ from 2
This function finds the largest number which doesn’t trigger the
given tooHigh
function. It does
this by traversing iTree
: it
keeps going right until tooHigh
becomes True
, then it
snakes down the left sub-tree, hugging the tooHigh
boundary until it hits a
leaf.
= let f (IN x l r) = if tooHigh x
find tooHigh then f l
else f r
IL x) = x in
f ( f iTree
This is a simple example which uses iTree
to find the integer square root
of a number.
sqrtI :: Integer -> Integer
| n <= 1 = 1
sqrtI n | otherwise = find $ (> n) . (^ 2) sqrtI n
Here’s a QuickCheck
property to verify that it’s correct.
= let root = sqrtI n
prop_sqrtI n = (root - 1)^2
lower = (root + 1)^2 in
higher > 0 ==> lower <= n && higher >= n n
Anyone know what this iTree
structure is called?