Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Program design concerning ADTs

Tags:

haskell

I have a type

data Phase = PhaseOne
           | PhaseTwo
           | PhaseThree deriving Enum

and five operations to do on each Phase

  • read
  • write
  • validate
  • evalStatus
  • update

I began trying to create a type class. The problem is, they are all the same type. I'd like to be able to do something like

instance MyClass PhaseThree where
  read a = ...

Also, I need to overload the return type.

I know type classes aren't what I want. But I'm not sure how to do what I want. I thought of a GADT but that's not quite right as I need to be able to have each instance in a separate file.

I'd like some advice on which mechanisms I need to investigate? Have I given enough information?


2 Answers

I recommend inverting things a bit.

data Phase = Phase {
    read :: String -> Foo,
    write :: Foo -> IO (),
    validate :: Foo -> Bool,
    evalStatus :: IO (),
    update :: Foo -> Foo
}

phaseOne, phaseTwo, phaseThree :: Phase

(or some similar rejiggering of classes into explicit records).

like image 72
Daniel Wagner Avatar answered May 22 '26 09:05

Daniel Wagner


Elaborating on my comment above, if you wanted to use three different types with a class supporting your operations, you can sort of build in an Enum-like functionality with a succ class method.

You also have to provide a Done type as a placeholder for succ PhaseThree

{-# LANGUAGE MultiParamTypeClasses , FunctionalDependencies #-}
data PhaseOne = PhaseOne
data PhaseTwo = PhaseTwo
data PhaseThree = PhaseThree

data Done = Done

class YourClass p0 p1 | p0 -> p1 where
    succ :: p0 -> p1
    -- read :: ...
    -- write :: ...etc

instance YourClass PhaseOne PhaseTwo where
    succ PhaseOne = PhaseTwo
    -- read = ...

instance YourClass PhaseTwo PhaseThree where
    succ PhaseTwo = PhaseThree

instance YourClass PhaseThree Done where
    succ PhaseThree = Done

You might separate the Succ functionality from your read, write, etc. methods and create two classes as well. Return values can be polymorphic.

succ on your original posted formulation is horrible since succ PhaseThree just throws an error. If you can get the type system working for your application, that's the ideal.

like image 41
jberryman Avatar answered May 22 '26 08:05

jberryman