Martin Drautzburg
Martin Drautzburg

Reputation: 5243

"Subclassing" a type in Haskell

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

Answers (1)

Nikita Volkov
Nikita Volkov

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

Related Questions