Non-trivial type synonyms
From HaskellWiki
(Difference between revisions)
m (Adding Category) |
m (links, format) |
||
| (One intermediate revision not shown.) | |||
| Line 2: | Line 2: | ||
To avoid Miles/Km , feet/metres goofs: | To avoid Miles/Km , feet/metres goofs: | ||
| - | + | Rather than | |
<haskell> | <haskell> | ||
type Miles = Int | type Miles = Int | ||
| Line 24: | Line 24: | ||
The functions toMiles and fromMiles is already effectively id ! | The functions toMiles and fromMiles is already effectively id ! | ||
| - | A | + | A <hask>newtype</hask> definition just generates a new type whose implementation is the same as the old one. |
| - | same as the old one. | + | |
| - | The constructor (and possibly selector) really does nothing except coerce | + | The constructor (and possibly selector) really does nothing except coerce between the new type and the old one. |
| - | between the new type and the old one. | + | |
| - | So as <hask>undefined</hask> is | + | So as <hask>undefined</hask> is Haskell's notation for bottom |
<haskell> | <haskell> | ||
toMiles undefined === undefined | toMiles undefined === undefined | ||
</haskell> | </haskell> | ||
| - | which isn't the case if we use a | + | which isn't the case if we use a <hask>data</hask> definition. |
| Line 44: | Line 42: | ||
{- or just use Miles, though this is harder to excise later -} | {- or just use Miles, though this is harder to excise later -} | ||
</haskell> | </haskell> | ||
| - | For tracking more complex units, you may be able to get some of the way by using [[ | + | For tracking more complex units, you may be able to get some of the way by using [[phantom type]]s or creative use of [[functional dependencies]]. |
==See also== | ==See also== | ||
| - | * For an example toy implementation using [[ | + | * For an example toy implementation using [[phantom type]]s & [[functional dependencies]], see [[dimensionalized numbers]] |
* [[Wrapper types]]. | * [[Wrapper types]]. | ||
[[Category:Idioms]] | [[Category:Idioms]] | ||
Current revision
1 Make the type system work for you
To avoid Miles/Km , feet/metres goofs:
Rather than
type Miles = Int
use
newtype Miles = Miles Int
together with
toMiles :: Int -> Miles fromMiles :: Miles -> Int
these can be redefined to be "id" later, after the code is stablized.
2 Alternate Miles etc. definitions
No need to change things : The functions toMiles and fromMiles is already effectively id !
Anewtype
The constructor (and possibly selector) really does nothing except coerce between the new type and the old one.
So asundefined
toMiles undefined === undefined
data
Structures might be a bit more convenient here.
newtype Miles = Miles { fromMiles :: Int } toMiles = Miles {- or just use Miles, though this is harder to excise later -}
For tracking more complex units, you may be able to get some of the way by using phantom types or creative use of functional dependencies.
3 See also
- For an example toy implementation using phantom types & functional dependencies, see dimensionalized numbers
- Wrapper types.
