Home > database >  Algebraic Data Types in Haskell
Algebraic Data Types in Haskell

Time:10-29

Hello I have only worked with imperative programming so far and I am learning Haskell :)

I have the following algebraic data types:

data Day   = I | ... | XXXI deriving(Ord,Eq)    (Days in roman numerals)
data Month = Jan | ... | Dec deriving(Ord,Eq)   (Months abbreviated to 3 letters)
data Year  = 0 | ... | 2021                     (actually Ints)

and I need to do some calculations with those. My first thought was mapping the Days and Months to Ints and do the calculations from there. For example:

dayConversionMap   = [(I,1), (II,2), (III,3), (IV,4), ... , (XXXI,31)]
monthConversionMap = [(Jan,1), (Feb,2), (Mar,3), ... , (Dec,12)]

My question is:

  1. Is this a good solution for my problem?
  2. How could i convert the Days/Months into Ints in a function given I have those maps.

Thanks in advance! :)

CodePudding user response:

Don't, and I repeat don't do date and time calculations yourself. Ship out to a good library. See also Falsehoods programmers believe about time for an incomplete list of reasons to do this.

CodePudding user response:

Answering your questions:

There are many ways of doing what you are looking for, and a practical way would be to use a library, as already pointed out. Even better, find a library and read the source code. Hoogle is your friend.


But For learning Haskell purposes:

Instead of mapping them manually you could try provide a function. And because this is a behaviour you want more types to share you could create a Type Class. One naive (maybe didactic, less so practical, maybe fun to play with) way would be:

  1. Define a Class that provides a way to convert to and from Int, let's call it ToInt. Now you have a common interface of getting that behaviour out of all your Types
class ToInt a where
  toInt   :: a -> Int
  fromInt :: Int -> Maybe a

Now you can implement your to and from for your types and use them to convert.

instance ToInt Day where
  toInt x =  
    case x of
      I -> 1
      II -> 2 
--    ...

  fromInt x = 
    case x of 
      1 -> I
--    ...

instance ToInt Month where 
-- ...
calculation :: Day -> Month -> Year -> Int
calculation d m y = doSomething (toInt d) 
  where 
    doSomething :: Int -> Int 
    doSomething = ...

Note that this is a simple but bad example.

You can see the tedious nature of both implementation, and the limited help you get from the type checker. But once you start implementing something, you get a feel for what works and what not. Then you can search for how others deal with these issues in the actual libraries, for example.

  • Related