The below instances for Vehicle are illegal due to overlapping instances:
data Ford = Ford
data Ferrari = Ferrari
class Car c where
accelerate :: c -> String
instance Car Ford where
accelerate _ = "Broom broom I'm a Ford"
instance Car Ferrari where
accelerate _ = "Rrrr I'm a fast red Ferrari!"
data Bowing747 = Bowing747
data JetFighter = JetFighter
class Plane p where
takeoff :: p -> String
instance Plane Bowing747 where
takeoff _ = "My passengers and I are taking off!"
instance Plane JetFighter where
takeoff _ = "RAWW I'm a loud jet fighter!"
class Vehicle v where
go :: v -> String
instance (Car c) => Vehicle c where
go = accelerate
instance (Plane p) => Vehicle p where
go = takeoff
main = return ()
I'm obviously approaching this in a very object orientated way, and perhaps this is where I'm going wrong.
So how in Haskell can I have a structure like below that allows me to call generic functions in a hierarchy without:
- Keeping in sync repeated sets of instances.
- Requiring extra "tag" arguments to be added at the call site.
That being said, I've got no need for Car, Plane or Vehicle to be clases, nor Ford, Ferrari etc to be defined how they are, as long as I can call go (some vehicle) and get the same result, and clients can add new cars, planes, and vehicle types without repeating myself.
The vehicles for each type need to be open to users to add their own. The vehicle types themselves could be closed, I'd prefer if they weren't though.
CarandPlaneare the same asVehicle(accelerate = goandtakeoff = go), then why even have theCarandPlanetype classes? If they aren't necessarily the same asVehicle, then e.g. trying to provide theVehicleinstance for allPlanes is misdirected and you'd be better off withclass Vehicle p => Plane p where takeoff :: p -> String; takeoff = go.