[Haskell-cafe] Re: [Haskell] Why functional programming matters

apfelmus apfelmus at quantentunnel.de
Thu Jan 31 05:05:09 EST 2008


Stephan Friedrichs wrote:
> I just uploaded a generalised heap (min-, max- and custom-heaps) 
> implementation:
> 
> http://hackage.haskell.org/cgi-bin/hackage-scripts/package/heap-0.1
> 
> Feedback would be appreciated :)

Feedback: I think the HeapPolicy thing is too non-standard. The 
canonical way would be to use a MinHeap and let the Ord instance handle 
everything. A MaxHeap can then be obtained via a different Ord instance

    newtype Ord a => Reverse a = Reverse { unReverse :: a }

    instance Ord a => Ord (Reverse a) where
      compare = comparing unReverse

This newtype should be in Data.Ord, of course. Being 
minimum/maximum-agnostic seems like a noble goal but turns out not to be 
that good. To see why, I'd like to report the first documentation bug: 
will a custom heap's  head  be the minimum or the maximum with respect 
to a custom  heapCompare  ? (ok, the docs for  head  indicate  minimum, 
but the docs for  HeapPolicy  should say so, too.)


Simply setting

   type MaxHeap a = MinHeap (Reverse a)

is inferior to a "native" MaxHeap since we'd have to pack/unpack the 
Reverse  all the time. But a type class for heaps - which should be 
present anyway - can solve that problem:

   class Heap h where
      empty    :: h a
      insert   :: Ord a => a -> h a -> h a
      viewHead :: Ord a => h a -> Maybe (a, h a)

      fromAscList :: Ord a => [a] -> h a
      toAscList   :: Ord a => h a -> [a]


      null    :: Ord a => h a -> Bool
      null = isNothing . viewHead

      singleton :: Ord a => a -> h a
      singleton = flip insert empty

      head      :: Ord a => h a -> a
      head = fst . fromJust . viewHead

      deleteHead :: Ord a => h a -> h a
      deleteHead = maybe empty snd . viewHead

      ... etc.

   instance Heap MinHeap where ...

   newtype MaxHeap a = M (MinHeap (Reverse a))
   instance Heap MaxHeap where ...

The  union  and  unions  functions are probably best not put in this 
class but implemented via separate  Monoid  instances.


In conclusion: the ordering policy stuff should not be part of 
Data.Heap, this is a job for Data.Ord.


In particular, Data.Ord might contain something like

    newtype OrdBy p a = OrdBy { unOrdBy :: a }

    class OrdPolicy p a where ...

    instance OrdPolicy p a => Ord (OrdBy p a) where ...

which can then be used to implement heaps with such different orderings 
in one go:

    newtype OrdPolicy p a => HeapP p a = HeapP (MinHeap (OrdBy p a))

    instance Heap (HeapP p) where ...


Regards,
apfelmus



More information about the Haskell-Cafe mailing list