Difference between revisions of "Non-trivial type synonyms"
Jump to navigation
Jump to search
BrettGiles (talk | contribs) (Convert from HaWiki) |
BrettGiles (talk | contribs) m (links, format) |
||
(3 intermediate revisions by the same user 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 19: | Line 19: | ||
− | What do you mean by "redefined to be 'id'"? (New to Haskell, though I like it a lot.) Instinctively I dislike the idea of changing things after the code is "stabilized", because code never stabilizes unless because people are afraid to touch it because it's too fragile. I really like the idea of making the type system track units like that... Has anybody worked out the details of a system that would use classes and inheritance to automate the tracking of complex units like Miles/Hour? If I do, I'll probably post it here. --[[User:DanielKnapp]] |
||
==Alternate Miles etc. definitions == |
==Alternate Miles etc. definitions == |
||
Line 25: | 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. |
− | One possibly valid reason for removing the constructors and selector may be |
||
− | that they clutters the code too much. |
||
− | (I think restricted type synonyms can sometimes fix this better) |
||
− | |||
− | -- StefanLjungstrand |
||
Structures might be a bit more convenient here. |
Structures might be a bit more convenient here. |
||
Line 50: | 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]] |
||
− | ---- |
||
− | CategoryIdiom |
Latest revision as of 16:35, 13 October 2006
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.
Alternate Miles etc. definitions
No need to change things : The functions toMiles and fromMiles is already effectively id !
A newtype
definition just generates a new type whose implementation is the same as the old one.
The constructor (and possibly selector) really does nothing except coerce between the new type and the old one.
So as undefined
is Haskell's notation for bottom
toMiles undefined === undefined
which isn't the case if we use a data
definition.
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.
See also
- For an example toy implementation using phantom types & functional dependencies, see dimensionalized numbers
- Wrapper types.