2

I want pass a sub data type into function.

An example:

data Car a = Ford | Opel | BMW | Mercedes a deriving (Show)

data Mercedes a = SClass a| CClass a| MClass a


myfunc::Car->String
myfunc a = show a ++ " works correctly"

but I do:

myfunc CClass "x"

it says

not in scope: constructor CClass

4
  • 4
    This has multiple errors. "deriving (Show)" should have the "show" capitalised. Your second line seems to be trying to be a data type, but lacks the "data" keyword (probably the cause of your error message). If you did it that way then your types are going to be problematic because you will have "Ford" being of type "Car (Mercedes String)". Tell us what you are trying to achieve. Commented Sep 9, 2012 at 14:56
  • Also, you need to use show in myfunc, i.e. myfunc a = show a ++ " works correctly". Commented Sep 9, 2012 at 14:59
  • I want to be able to pass in any car model into one function and the function be able to pattern-match the car model and treat each one differently. Commented Sep 9, 2012 at 15:00
  • 4
    Looks like you're thinking too "object-oriented", or rather too much in the style of what Java & co. call object-oriented. Examples like this may give a reasonably good insight into the way you're dealing with objects in those languages, but they don't really make much sense as they are. And Haskell has other (and more powerful) ways of doing stuff, you might want to rather write some interesting programs rather than trying to apply OO language example structures to Haskell. Commented Sep 9, 2012 at 16:04

2 Answers 2

12

To achieve "sub"-types, one has a few options. The first is just to use more data types, as you are attempting:

data Car a = Ford (Ford a) | Mercedes (Mercedes a) deriving (Show)

data Ford a = ModelT a | Falcon a deriving (Show) -- different Fords models
data Mercedes a = CClass a | SClass a deriving (Show) -- different Mercedes models

Note that being a type constructor is different to being a data constructor, so one can't just use data Car = .. | Mercedes a: this is saying that one of the ways to make a Car String is just by saying Mercedes "a", it has no correlation with the type called Mercedes. Now one can just use a function like:

horsepower :: Car a -> Float
horsepower (Ford (ModelT _)) = 1
horsepower (Ford (Falcon _)) = 500
horsepower (Mercedes (CClass _)) = 300
horsepower (Mercedes (SClass _)) = 400

And your example would be:

myfunc :: Show a => Car a -> String
myfunc a = show a ++ " works correctly"

-- myfunc (Ford (ModelT "A")) => Ford (ModelT "A") works correctly
-- myfunc (Mercedes (CClass "b")) => Mercedes (CClass "b") works correctly

Another way to allow "subtyping" like this is to use a type class (depending on the specifics, this might be a better option). E.g.

class (Show c) => Car c where
    make :: String
    model :: c -> String
    horsepower :: c -> Float
    number_of_seats :: c -> Int
    -- etc.

data Ford a = ModelT a | Falcon a deriving (Show)
instance (Show a) => Car (Ford a) where
    make = "Ford"
    horsepower (ModelT _) = 1
    horsepower (Falcon _) = 500
    -- etc.


data Mercedes a = CClass a | SClass a deriving (Show)
instance (Show a) => Car (Mercedes a) where
    make = "Mercedes"
    horsepower (CClass _) = 300
    horsepower (SClass _) = 400
    -- etc.

Your example of myfunc might be:

myfunc :: (Car c) => c -> String
myfunc c = (make `asTypeOf` c) ++ " " ++ show c ++ " works correctly"

-- myfunc (ModelT "A") => Ford ModelT "A" works correctly
-- myfunc (CClass "b") => Mercedes CClass "b" works correctly

Also note that one must call functions like function (Ford (Ford "a")) (or function (CClass "a")) with parenthesis.

Sign up to request clarification or add additional context in comments.

Comments

5

First off, you need to define your car type as follows:

data Car a = ... | Mercedes (MercedesClass a) | ...

data MercedesClass a = CClass a | ...

... and then you can write:

myFunc (Mercedes (CClass "x"))

3 Comments

In myFunc I try to pattern match on (CClass a) but it says couldnt match expected type Car a with actual type MercedesClass a
@peroni_santo You have to pattern match on Mercedes (CClass a)
@peroni_santo in let v = CClass "x" a value v has type MercedesClass String. Then, in let c = Mercedes v, a value c has type Car String.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.