[Haskell-beginners] Generalised data constructor matching

Daniel Fischer daniel.is.fischer at web.de
Fri Sep 4 08:57:18 EDT 2009


Am Freitag 04 September 2009 14:01:47 schrieb Colin Campbell-McPherson:
> Hi Chaps,
>
> I've been trying to write a function that would get the name of most
> data that is an instance of class "Animal". This getName function
> could then be overwritten for data that doesn't follow the normal
> pattern for "Animal" data types. So the getName defined in the Animal
> class would be a generic, or default implementation.
>
> I've written a couple of  examples that don't use classes, but that I
> hope expresses what I'm trying to accomplish. In the first example
> getName needs to be defined for Dogs and Birds, even though they're
> essentially identical. The tries to define a more general function
> that works for both Birds and Dogs, and anything else that might come
> along.
>
> The first examples works, the second gives a "Parse error in pattern"
> error.
>
> EXAMPLE 1
>
> data Animal = Person String String | Dog String | Bird String deriving
> Show
> getName :: Animal -> String
> getName (Person firstName lastName) = firstName ++ " " ++ lastName
> getName (Dog name) = name
> getName (Bird name) = name
>
> logan = Person "Logan" "Campbell"
> ebony = Dog "Ebony"
> poly  = Bird "Poly"
>
> main = do
>   putStrLn $ show $ getName logan
>   putStrLn $ show $ getName ebony
>   putStrLn $ show $ getName poly
>

For such a datatype, named fields come in handy:

data Animal
    = Person { firstName, lastName :: String }
    | Dog { name :: String }
    | Bird { name :: String }

getName :: Animal -> String
getName (Person f l) = f ++ " " ++ l
-- other special cases if the datatype is extended
getName other = name other

>
> EXAMPLE 2
>
> data Animal = Person String String | Dog String | Bird String deriving
> Show
> getName :: Animal -> String
> getName (Person firstName lastName) = firstName ++ " " ++ lastName
> getName (_ name) = name
>
> logan = Person "Logan" "Campbell"
> ebony = Dog "Ebony"
> poly  = Bird "Poly"
>
> main = do
>   putStrLn $ show $ getName logan
>   putStrLn $ show $ getName ebony
>   putStrLn $ show $ getName poly
>
> I have a background with Ruby and Erlang, so if drawing from concepts
> in either of those languages would help explain please do so. I'm also
> quite new to haskell so if i've used the wrong terms, or I'm trying to
> apply concepts where they don't belong, sorry about that.
>
>
> TLDR: How can I write a generic function that will work on most
> instances of a class, but be over over-written for instances of that
> class that deviate from the normal structure (ie. a data constructor
> with two params, rather than one).

In general: not.
The problem is that potentially every datatype can be made an instance of the class, so in 
the default implementations, you can only[*] use functions which work on every datatype. 
There aren't many interesting functions that do.

[*]well, you can also use methods of the class and superclasses, so e.g.

class Eq a where
    (==) :: a -> a -> Bool
    (/=) :: a -> a -> Bool
    x == y = not (x /= y)
    x /= y = not (x == y)

class (Eq a) => Ord a where
    compare :: a -> a -> Ordering
    (<), (<=), (>), (>=) :: a -> a -> Bool
    min, max :: a -> a -> a
    x < y = x <= y && x /= y
    x <= y = x < y || x == y
    -- etc.

is possible. But you still have to write instances manually for every type (except 
instances you can let the compiler derive).

>
> Many thanks,
> Colin




More information about the Beginners mailing list