Home > Mobile >  Eq Ord Classes Haskell Data
Eq Ord Classes Haskell Data

Time:11-21

Now I have another problem:

Another subtask tells me to derive a Currency data type from the Eq and Ord classes.

The problem is again that I'm not allowed to use deriving (Ord, Eq).

I don't know how to compare each currency. Do you have an idea and could you explain it to me so that I can understand?

data Currency = Dollar Integer Integer | Yen Integer | Euro Integer Integer

instance Eq Currency where
...

instance Ord Currency where
...

CodePudding user response:

In general, the way to approach this kind of problem is to not get over-distracted by the type class machinery. I suggest you start by writing a function like eqCurrency:

eqCurrency :: Currency -> Currency -> Bool
eqCurrency ...

The obvious next step is to put in your arguments and do some pattern matching. For example, I'd probably write:

eqCurrency :: Currency -> Currency -> Bool
eqCurrency (Dollar d1 c1) (Dollar d2 c2) = ... 
eqCurrency (Yen y1) (Yen y2) = ...
eqCurrency (Euro d1 c1) (Euro d2 c2) = ...

Next, you have to decide how to check equality for different types of currency. So, ask yourself, is there ever a case where some dollar amount can equal some yen amount? If so, write cases for that. If not, perhaps you can just add a catch-all pattern match like

eqCurrency _c1 _c2 = False

Once you've written this function and are happy with its behavior, you can slot it in to the type class:

instance Eq Currency where
  (==) = eqCurrency

You'll need to do the same thing for the Ord type class. For Ord, the minimal complete definition is either defining <= or compare, so you should choose one of those. For instance, you could define:

leqCurrency :: Currency -> Currency -> Bool
leqCurrency ...

Once again, you'll ask yourself the same questions: If I have two Dollar amounts, when is one less than the other? If I have a Euro and a Yen, which one is less than the other? I can't answer these semantic questions for you, but you'll use your answers to encode the various cases, and when you're finished, you can fill in the type class:

instance Ord Currency where
  (<=) = leqCurrency

CodePudding user response:

I don't know how to compare each currency

Me neither. "How should currencies be compared" is more of a question of design than of implementation.

If you want to go for full correctness, you'd have to use the internet to download current exchange rates in order to do the comparison. But Eq and Ord instances simply don't allow internet connection, so that's not really possible.

It sounds like this is for an exercise, so perhaps it'd be fair to choose some fixed exchange rates for your program? Google tells me that, at the time of writing, one US cent is worth 1.4 Yen, so I'll go with that.

Then we know one case for ord:

instance Ord Currency where
  compare (Dollar dollars cents) (Yen yen) = compare ((dollars*100   cents) * 1.4) yen
  -- ...

The rest of the Ord instance could be filled in in a similar fashion, with cases for compare (Yen ...) (Dollar ...) and compare (Dollar ...) (Euro ...) etc, etc.

That implementation will work, and would be worth filling out completely.

There is a "cleaner" solution, though, if you're interested. We can choose some "anchor" currency, say Yen. Then we can write a so-called 'normalization' function which converts every currency to Yen:

normalize :: Currency -> Integer
normalize (Dollar dollars cents) = (dollars*100   cents) * 1.4
-- you fill in the rest

Using this, we can write Ord more simply as just

instance Ord Currency where
  compare c1 c2 = compare (normalize c1) (normalize c2)
  • Related