The composite design pattern implemented using record types, where the named elements are the interface to the object Overall, I think I agree with Tim that the record types are simpler to code. I'm not sure, though, what would happen if I tried to add state to the types. With the previous example, using existentials to create a reference type that holds elements of a type class that matches the interface, I think that it would be natural to hold state by having that element stored in a mutable state variable, and replacing the held values. In any case: Two methods, add and draw
data Component = Component { draw :: String, add :: Component -> Component }
A constructor for the leaf type, which holds a string
leaf :: String -> Component leaf s = Component draw1 add1 where draw1 = show s add1 _ = leaf s
the draw method for the composite type (because I was having trouble with layout and formating for 72 cols)
compositeDraw :: [Component] -> String compositeDraw [] = "()" compositeDraw leaves = "(" ++ (foldr1 (++) $ map draw leaves) ++ ")"
A constructor for the composite type, which holds a list of components and dispatches to the contained elements
composite :: [Component] -> Component composite cs = Component draw1 add1 where draw1 = compositeDraw cs add1 c = composite $ c:cs
On 2/27/07, Tim Docker <twd_gg@dockerz.net> wrote:
Steve Downey wrote:
interesting. it leads to something that feels much more like an object based, as opposed to a class based, system. as far as haskell is concerned, everything has the same type, even though different instances have very different behavior. .... the question is, which plays nicer with the rest of haskell? that is, if i'm not committing to a closed dsl, which style is more likely to be reusable against other libraries.
I suspect there's no right answer - it's a case of choosing the best approach for the problem. As an example, my charting library (http://dockerz.net/software/chart.html) uses the record of functions approach for composing drawings:
data Renderable = Renderable { minsize :: (Render RectSize) render :: (Rect -> Render ()) }
Tim