开发者

Creating convenient type

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 sti开发者_StackOverflowll being synonyms for Int would be perfect but I can not figure out how.


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.


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.


You can have both:

type Adult = Int
type Youth = Int

data Person = Adult Adult | Youth Youth

Data constructors are in a separate namespace from types so there is no conflict here.


I would suggest to just add the type synonym

type Person = Int

and you are able to give types to functions that work both, for Adults abd Youth, like

doSomething :: Person -> ...

(and you keep the possibility to use Adult and Youth in other type signatures)


I suggest to make Person polymorphic:

data Person a = Person a Int

With this definition you can write general functions on Person level that don't care about the concrete value of a:

getInt :: Person a -> Int
getInt (Person _ i) = i 

incInt :: Person a -> Person a
incInt (Person p i) = Person p (inc i) 

Then you can define "tags" to substantiate a Person:

data Adult = Adult
data Youth = Youth

Now you can write functions for a specific type of Person

rock :: Person Youth -> String
rock (Person Youth k) = "I rock until " ++ show k ++ " in the morning!!!"
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜