Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating convenient type

Tags:

haskell

I am beginning with Haskell. I have a situation where it is convenient to work the following type synonyms:

type Adult = Int
type Youth = Int

However I can not overload functions on Adult and Youth even if they had been synonyms for different types so have to have two seperate versions of functions eg. doSomethingForAdult and doSomethingForYouth , so next I tried

data Person = Adult Int | Youth Int

Then I can pattern match and use a single version of functions, but then I loose the option of using the Adult and Youth as types in functions declarations which is convenient. Is there a middle way ? I looked at Either, but from the description in tutorials it seems this would be misuse ? Something similar to a small type hierarchy with Person at the root and Youth and Adult derived and still being synonyms for Int would be perfect but I can not figure out how.

like image 966
ropps_nest Avatar asked Dec 16 '22 11:12

ropps_nest


2 Answers

I don't see how that would be a misuse of Either. Just as (,) is a generic product type, Either is perfectly acceptable as a generic sum type, i.e. anything of the form:

data T = T1 A | T2 B C

...can be thought of algebraically as A + (B * C), which is equivalent to Either A (B, C).

On the other hand, if you want to distinguish between Adult and Youth, using synonyms for the same actual type can be counterproductive; they're just transparent aliases. An alternate approach would be to use newtypes, like this:

newtype Adult = Adult Int deriving (Eq, Ord, Show, Read, Num) 
newtype Youth = Youth Int deriving (Eq, Ord, Show, Read, Num) 

Adjust the deriving clause to taste; I added Num here because the underlying type is numeric, but if all you want is a unique identifier then adding or multiplying them doesn't make sense. At this point you can then use a sum type for Person if you like, or define a type class to get proper overloading:

class Person a where 
    -- (etc...)

instance Person Adult where -- ...
instance Person Youth where -- ...

Any functions defined in Person are then effectively overloaded on Adult and Youth, letting you dispatch based on type the way "overloaded" functions in other languages do.

like image 77
C. A. McCann Avatar answered Jan 03 '23 04:01

C. A. McCann


Are you wanting a typeclass?

data Adult = Adult Int
data Youth = Youth Int

class Person a where
  doSomething :: a -> b

instance Person Adult where
  doSomething (Adult i) = ...

instance Person Youth where
  doSomething (Youth i) = ...

This is the typical manner of overloading function in Haskell. The typeclass, Person, has a single function, doSomething :: a -> b. Each data type you want to be an instance of Person can have its own, separate, implementation. If you want the underlying implementation to be the same then just use another function, doSomethingGlobal :: Int -> b and let each instance equal this new function.

like image 29
Thomas M. DuBuisson Avatar answered Jan 03 '23 03:01

Thomas M. DuBuisson