[Haskell-cafe] Creating a type for a subset of the integers

gwern0 at gmail.com gwern0 at gmail.com
Tue Dec 18 21:20:27 EST 2007


On 2007.12.18 21:07:25 -0500, Brad Larsen <brad.larsen at gmail.com> scribbled 0.6K characters:
> Hi there list,
>
> How would one go about creating a new type for a subset of the integers,
> for (contrived) example just the even integers?  I was thinking of making a
> new type
>
> newtype EvenInt = EvenInt Integer
>
> but the problem with this is that it accepts any integer, even odd ones.
> So to prevent this, the module does not export the constructor for
> it---rather, the module exports a function `mkEvenInt' that creates an
> EvenInt if the given value is acceptable or raises an error otherwise.
>
> What's the right way to do this?  Thanks!
>
> Brad Larsen

Well, I've had cause to do this in the past.

Before I paste the following code, I'd like to emphasize that I wrote it a while when I was even more new to Haskell; that it compiles but hasn't been tested very much; and that I'm sure there are better ways to do it.

What I wanted to do was to define a type for a subset of 'reals' (floats) which are either 0, or positive. The code looks like this:

> {- For many equations and results, it is nonsensical to have negative results, > but we don't want
> to use solely natural numbers because then we lose precision. So we define a
> PosReal type which tries
> to define the subset of real numbers which are 0 or positive; this way the type
> system checks for negative
> results instead of every other function having conditionals checking for
> negative input or output. -}
> newtype PosReal = MakePosReal Float deriving (Show, Eq, Ord)
>
> -- Basic numerical operations on positive reals
> instance Num PosReal where
>     fromInteger = toPosReal . fromInteger
>     x + y = MakePosReal (fromPosReal x + fromPosReal y)
>     x - y = toPosReal ((fromPosReal x) - (fromPosReal y))
>     x * y = MakePosReal (fromPosReal x * fromPosReal y)
>     abs x | x >= 0 = x
>           | otherwise = x * (-1)
>     signum x | x >= 0 = 1
>              | otherwise = (-1)
>
> -- Define division on PosReals
> instance Fractional PosReal where
>     x / y = toPosReal ((fromPosReal x) / (fromPosReal y))
>     fromRational x = MakePosReal (fromRational x)
>
> -- Positive reals are truncated at 0
> toPosReal :: Float -> PosReal
> toPosReal x
>     | x < 0     = MakePosReal 0
>     | otherwise = MakePosReal x
> fromPosReal :: PosReal -> Float
> fromPosReal (MakePosReal i) = i
>
> -- Define an instance to allow QuickCheck operations
> instance Arbitrary PosReal where
>     arbitrary = liftM3 fraction arbitrary arbitrary arbitrary
>         where fraction :: Integer -> Integer -> Integer -> PosReal
>               fraction a b c = fromInteger a + (fromInteger b / (abs (fromInteger c) + 1))


--
gwern
RFI el Audiotel muezzin E911 B61-11 Revolution 5.0i N5P6 espionage
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://www.haskell.org/pipermail/haskell-cafe/attachments/20071218/32cde187/attachment.bin


More information about the Haskell-Cafe mailing list