[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