Reputation: 5243
I have a data type called Process
, which is a parameter to various functions. But not all Processes are alike. There are different types of Proccesses, which all have something in common, but differ in other aspects. My question is: what idioms do I have available to model this.
What I tried so far:
1st attempt
Capture the specifics of a Process in a run
function inside the Process datatype. The Type of the run function would be the same for all Processes, but its implementation may differ between Processes of different types. I abanoned this idea, because I cannot look inside the run
function from outside, i.e. I cannot modify it. I cannot alter specific aspects of it, I only can provide an entirely new run function. An operation like start 10 minutes later would be impossible to implement.
2nd attempt Use multiple constructors
type PlaceDep = Int
type PlaceArr = Int
type DepartureTime = Int
type Speed = Int
data Process = Train PlaceDep PlaceArr DepartureTime
| MovingBelt PlaceDep PlaceArr Speed
deriving (Eq, Show)
prc1 = Train 10 11 1
prc2 = MovingBelt 12 13 2
Here it bugs me that the fact that all Processes have PlaceDep and PlaceArr seems a bit coincidental and is not expressed celarly
3rd attempt Use one constructor but add ProcessParameters
having multiple constructors
type PlaceDep = Int
type PlaceArr = Int
data ProcessParams = DepartureTime Int | Speed Int
deriving (Eq, Show)
data Process = Process PlaceDep PlaceArr ProcessParams
deriving (Eq, Show)
prc1 = Process 10 11 (DepartureTime 1)
prc2 = Process 12 13 (Speed 2)
This looks promising so far. In any case I am interested to hear about other possible options.
Note
The question was edited multiple times. Some comments and answers may refer to older versions.
Upvotes: 2
Views: 171
Reputation: 43309
As, I'm sure, you know, there is no inheritance in Haskell. However it is not a problem at all. Cases like yours can easily be solved with a scalable approach called "Composition", which lately gets preferred over "Inheritance" even in OO languages.
What you need to do is implement each "Process" in isolation in separate modules and then in another module have a dome interface around a type, which is composed from all of them. That type is likely to be a union of those specific types of processes, while functions in it will mostly be about routing to functions of specific implementations. E.g.:
module MoreGeneralProcess where
import qualified SpecificProcess1
import qualified SpecificProcess2
data Process = SpecificProcess1 SpecificProcess1.Process |
SpecificProcess2 SpecificProcess2.Process
doOneGeneralThing :: Process -> IO ()
doOneGeneralThing process =
case process of
SpecificProcess1 x -> SpecificProcess1.doOneGeneralThing x
SpecificProcess2 x -> SpecificProcess2.doOneGeneralThing x
This is a common and infinitely scalable pattern. In some Haskell dialects it is even an idiom.
Upvotes: 3