On Oct 12, 2010, at 4:24 AM, Jacek Generowicz wrote:

I can't see a Haskell solution which combines both of these orthogonal
features without losing the benefits of the type system. (For example,
I could create my own, weak, type system with tags to identify the
type and maps to do the dispatch.)

Is there any particular reason why you want to actually to mirror Python code? I think that letting the programmer design domain specific control structures is rather the point of Haskell. Instead of relying on a one-sized fits all solution (which only really fits one kind of problem), you write your own. And it is typically easier to write the control structure than it is to implement it using the OO patterns, because of the notion of irreducible complexity. For example, the Factory pattern constructs a functor. You can write the essential semantics of doing this with a single Functor instance, instead of writing multiple classes which implement the semantics, while relying on implicit, and possibly ill-fitting semantics of method dispatch. The other OO patterns make this objection stronger. If you can write a UML diagram, you can turn it into a commutative diagram, and write less code by implementing its arrows.

An OO class hierarchy is a very specific functor over objects (which attaches methods to objects). Haskell provides the Functor type class. Write your generic functions for specific functors:


-- The varying "input" types. Will be attached to arbitrary values by the Functor instance.

data A = A      -- Variant 1
data B = B      -- Variant 2

-- Some normalized Output type.
data Output = Output

-- The new control structure. data Attaches a = AttachesA A a
                | AttachesB B a

-- Stick your conditional (varying) semantics in here. Corresponds to heterogeneousProcessor. -- The output presumably depends on whether A or B is attached, so this function is not equivalent -- to something of the form fmap (f :: a -> Output) (attaches :: Attaches a)
runAttaches :: Attaches a -> Attaches Output
runAttaches = undefined

-- This corresponds roughly to heterogeneousProcessor(heterogeneousContainer):
processedOutputs :: [Attaches a] -> [(Attaches Output)]
processedOutputs as = fmap runAttaches as


-- Functor instance. Now you have a way to treat an (Attaches a) value just like you would an a. (modulo calling fmap)
instance Functor Attaches where
         fmap f (AttachesA A a) = (AttachesA A (f a))
         fmap f (AttachesB B a) = (AttachesB B (f a))



_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to