haskellsetpowerset

Power set using BST in haskell


I have implemented a Set datatype in Haskell using Binary search tree. I have not used any of the in-built functions nor imported any module.

My set datatype is as follows:

data Set a = Empty | Node a (Set a) (Set a) deriving(Show) 

I have written a toList function , and a fromList function using insert function . I have also written a setmap, and a setfoldr function on sets using bst.

I am stuck on just one problem now:

-- powerset of a set
-- powerset {1,2} => { {}, {1}, {2}, {1,2} }
powerSet :: Set a -> Set (Set a) 

I have no idea on how to implement a powerSet using this type signature. I don't have any clues on what kind of auxiliary functions I need to write for this. I have some clue on how to do this with Lists, but not using a binary search tree. If you could please share some hints on how to do this. Thanks in advance!


Solution

  • You've mentioned you've implemented toList. You can use it to go the lists route here.

    Just as in your previous question, this calls for implementing and using fromAscendingList, to construct a tree from a list in a purely structural manner, without any comparisons, under the assumption that the list is already ordered in an increasing order.

    This structural construction doesn't involve any knowledge of the elements; same should be true for the powerset function:

    powerSet :: Set a -> Set (Set a)
    powerSet = toList >>> powerList >>> map fromAscendingList
                      >>> fromAscendingList
    
    -- (foo >>> bar >>> baz) x = baz (bar (foo x))
    

    Of course we need to implement powerList in an order-preserving fashion, for this to work properly:

    powerList :: [a] -> [[a]]
    powerList  =  concat . powers
      where
        powers :: [a] -> [ [[a]]]
        powers []     =  [ [[]] ]
        powers (x:xs) =  [ [[]] ] ++
             [ map (x:) a ++ b 
               | (a:b:_) <- tails (powers xs ++ [[]]) ]
    
    -- > powerList [1,2,3]
    -- [[],  [1],[2],[3],  [1,2],[1,3],[2,3],  [1,2,3]]
    

    (a simpler alternative generates the sublists in a different order:

    powerList' :: [a] -> [[a]]
    powerList' (x:xs) = [ s | s <- powerList' xs, s <- [s, x:s]]
    powerList' []     = [[]]
    
    -- > powerList' [1,2,3]
    -- [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
    

    and if we'd followed the set-notation pseudocode in the other answer directly, the resulting code would produce the sublists even more out of order -- [3] would come out before [2], and that before [1]).

    You still need to implement fromsAcendingList. The simplest way is to just create the highly-unbalanced, list-like tree. You can start with that. Then perhaps devise a way to create the nearly-balanced tree, which is preferable.

    As an alternative, treat all of the above as an executable specification and re-implement it to work directly on your Set type values. mapTree is trivial (and already covered in your previous question); simultaneously accessing a node and its successor in the fringe is also doable.


    As a curiosity, I include also a version which generates the longest sublists first, for comparison:

    -- shortest first:
    powers :: [a] -> [ [[a]]]
    powers []     =  [ [[]] ]
    powers (x:xs) =  [ [[]] ] ++
         [ map (x:) a ++ b |  (a:b:_) <- tails (powers xs ++ [[]]) ]
    
    -- longest first:
    rpowers :: [a] -> [ [[a]]]
    rpowers []     =  [ [[]] ]
    rpowers (x:xs) = 
         [ map (x:) b ++ a |  (a:b:_) <- tails ([[]] ++ rpowers xs) ] 
          ++          [ [[]] ] 
    
    > powers [1,2,3]
    [[[]],  [[1],[2],[3]],  [[1,2],[1,3],[2,3]],  [[1,2,3]]]
    
    > rpowers [1,2,3]
    [[[1,2,3]],  [[1,2],[1,3],[2,3]],  [[1],[2],[3]],  [[]]]