HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Searching a Join List for an index Attempt #2

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
indexsearchingjoinattemptforlist

Problem

Originally I posted this incorrect attempt - Searching a Join List for an index.

Given a JoinList:

data JoinList m a = Empty
                  | Single m a
                  | Append m (JoinList m a) (JoinList m a)
    deriving (Eq, Show)


where m represents the size of the JoinList, find the element (Maybe a) at the given index in the JoinList structure.

indexJ :: (Sized b, Monoid b) => Int -> JoinList b a -> Maybe a
indexJ _ Empty             = Nothing
indexJ i (Single _ x) 
  | i == 0                 = Just x
  | otherwise              = Nothing
indexJ i (Append _ left right)
  | leftHt > i             = indexJ i left
  | (rightHt + leftHt) > i = indexJ (i-leftHt) right
  | otherwise              = Nothing
  where leftHt  = (getSize. size . tag) left
        rightHt = (getSize. size . tag) right


where tag =

tag :: Monoid m => JoinList m a -> m
tag Empty          = mempty
tag (Single x _)   = x
tag (Append x _ _) = x


Testing

Data

jlIndex2 :: JoinList Size String
jlIndex2 = Append (Size 3) 
                       (Single (Size 1) "foo") 
                       (Append (Size 2) 
                             (Single (Size 1) "bar") 
                             (Single (Size 1) "baz"))

jlIndex3 :: JoinList Size String
jlIndex3 = Append (Size 4) (Single 1 "biz") jlIndex2


Tests

*JoinList> indexJ 3 jlIndex3
Just "baz"
*JoinList> indexJ 0 jlIndex3
Just "biz"
*JoinList> indexJ 100 jlIndex3
Nothing


Note - I would've used QuickCheck, but I'm not sure how to use it with algebraic data types.

Solution

Your code is completely fine, although the suffix Ht for the sublist sizes is a little bit strange.

For the tests you can use

genJoinList :: Arbitrary a => Int -> Gen (JoinList Size a)
genJoinList 0 = pure Empty
genJoinList 1 = Single (Size 1)  arbitrary
genJoinList n = do
  left  (genJoinList left)  (genJoinList (n - left))

toList :: JoinList b a -> [a]
toList Empty          = []
toList (Single _ x)   = [x]
toList (Append _ l r) = toList l ++ toList r


You can now check whether indexJ n js returns the same value as toList js !! n:

prop_index :: (Eq a, Sized m, Monoid m) => Int -> JoinList m a -> Bool
prop_index n js = indexJ n js == indexI n (toList js)
  where
    indexI n xs = lookup n $ zip [0..] xs

main = quickCheck $ \n -> forAll (sized genJoinList) $ \js -> prop_index n js


An Arbitrary instance would need FlexibleInstances by the way.

Code Snippets

genJoinList :: Arbitrary a => Int -> Gen (JoinList Size a)
genJoinList 0 = pure Empty
genJoinList 1 = Single (Size 1) <$> arbitrary
genJoinList n = do
  left <- choose (0, n)
  Append (Size n) <$> (genJoinList left) <*> (genJoinList (n - left))

toList :: JoinList b a -> [a]
toList Empty          = []
toList (Single _ x)   = [x]
toList (Append _ l r) = toList l ++ toList r
prop_index :: (Eq a, Sized m, Monoid m) => Int -> JoinList m a -> Bool
prop_index n js = indexJ n js == indexI n (toList js)
  where
    indexI n xs = lookup n $ zip [0..] xs

main = quickCheck $ \n -> forAll (sized genJoinList) $ \js -> prop_index n js

Context

StackExchange Code Review Q#69347, answer score: 2

Revisions (0)

No revisions yet.