1

I'm just beginning to learn Haskell and I'm stuck at the following problem:

I want to create a type of the calendar weeks, i.e. the numbers from 1 to 52. That's why I tried this one:

data CalendarWeek = 1 | 2 | ... | 52 deriving (Eq, Order, Show)

So then it could be used right here:

data Offer = Offer CalendarWeek Day Offer String deriving (Eq, Order, Show)

However, GHC just prints out the following error:

parse error on input `1'

What am I doing wrong? Is there another way to build this type?

Thanks a lot for your answers!

1
  • I am fairly sure you can't use names that only consist of numbers. What you could do is data CalendarWeek = W1 | W2 | W3 and so on. However, I would actually recommend just doing newtype CalendarWeek = Week Int and then making sure, in all the other functions (and with tests!) that you don't actually have a week less than 0 and bigger than 53. (Some years have 53 weeks.) Commented Nov 26, 2013 at 10:25

1 Answer 1

5

Expanding on my comment:

I am fairly sure you can't have names that only consist of numbers. If you really want to do it your way, you could do

data CalendarWeek = W1 | W2 | W3 | … | W52 | W53 deriving (Eq, Order, Show)

(keeping in mind that some years have 53 weeks, last was 2009.)

However, I don't recommend this. For one, it's a lot of typing, and in any case it is hard to treat week numbers as numbers when doing things this way. What I recommend is doing

data CalendarWeek = Week Int

Then you can define a function like

mkWeek :: Int -> CalendarWeek
mkWeek number =
  if number >= 1 && number <= 53
     then Week number
     else error "Not a valid week number!"

This will result in mkWeek 47 returning the value Week 47, while mkWeek 112 will blow your program up. In a real program, you probably don't want to blow your program up here, but what you do is dependent on the situation.

In the same vein, any time you work with weeks, you will need to make sure that the value doesn't overflow, but this is trivial (and if you go through mkWeek, you get the check for free!)

Of course, for this to be as safe as the approach you suggest, you would need to write a bunch of tests. All the functions handling week numbers should be tested so they can't accidentally return Week 975. And, if you design this as a separate module, you should not export the Week constructor, because doing so would allow anyone to create any crazy week value. Instead, force everyone to use your mkWeek function that makes sure no weird week number can be made.

Sign up to request clarification or add additional context in comments.

8 Comments

As a convenience CalendarWeek could instance Num so that, for example, weeks could be manipulated like this: (12 :: CalendarWeek) + 1
Do not export Week constructor from module, export mkWeek only. This way no one could create unchecked weeks. Also, you may also find Enum and Bounded instances useful.
@PedroRodrigues I haven't yet been able to tell whether or not that's a good idea. Week numbers violate some of our assumptions of how (non-modular) numbers usually behave. Added to that is the complexity of whether or not 4*52+1 should be 53 or 1 – it depends on which years are in between the "starting week" and the final week.
@PedroRodrigues (couldn't edit my comment this late) I guess this depends on whether you're into ISO calendar weeks or just weeks as a unit of time delta. I assumed ISO weeks because of the type of the data in the question.
@kqr Those are questions that have to be dealt irrespective of the CalendarWeek being defined as instance of Num or not. For example, your mkWeek functions fails to convey that the week 53 is only valid for some years. Either the CalendarWeek is changed to also include the year, or the client of CalendarWeek is aware of its limitations and knows how to deal with them.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.