How to create many restricted types without duplicating code in Haskell?

For the project, Ive created an Int-based type that throws an error whenever the program tries to use the value outside the limits ([0..127] in my case). The code below does this and it works for me.

Is it possible in Haskell to create a second restricted type (say, [0..255], for example) without duplicating this code?

thank you for your responses

{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Minitel.Type.MNatural (MNat, mnat, fromMNat) where -- | The MNat type. The constructor is hidden. newtype MNat = MakeMNat Int deriving (Real, Eq, Ord, Show) -- | MNat is a bounded type instance Bounded MNat where minBound = MakeMNat 0 maxBound = MakeMNat 127 -- | Converts an Int into an MNat mnat :: Int -> MNat mnat x | loLimit <= x && x <= hiLimit = MakeMNat x | otherwise = error "Number out of bounds" where loLimit = fromIntegral (minBound :: MNat) hiLimit = fromIntegral (maxBound :: MNat) -- | Converts an MNat into an Int fromMNat :: MNat -> Int fromMNat (MakeMNat i) = i -- | Converts an Int binary function returning Int to a MNat binary function -- returning an MNat mfnat :: (Int -> Int) -> (MNat -> MNat) mfnat f = mnat . f . fromMNat mfnat2 :: (Int -> Int -> Int) -> (MNat -> MNat -> MNat) mfnat2 fxy = mnat $ f (fromMNat x) (fromMNat y) -- | You can do additions, substractions and multiplication with MNat instance Num MNat where fromInteger = mnat . fromIntegral (+) = mfnat2 (+) (-) = mfnat2 (-) (*) = mfnat2 (*) abs = mfnat abs signum = mfnat signum -- | Allows to use toInteger with MNat instance Integral MNat where quotRem xy = (fromInteger $ quot x' y', fromInteger $ rem x' y') where (x', y') = (toInteger x, toInteger y) toInteger = toInteger . fromMNat -- | Allows to generate lists instance Enum MNat where toEnum = mnat fromEnum = fromMNat 

Note:

  • performance is not here.
+1
haskell bounded-types
source share
1 answer

You can do this in GHC 7.8 using level literals:

 {-# LANGUAGE DataKinds, PolyKinds, ScopedTypeVariables #-} module SO26723035 where import GHC.TypeLits import Data.Proxy newtype MNat (n :: Nat) = MakeMNat Int deriving (Eq, Ord, Show) instance KnownNat n => Bounded (MNat n) where minBound = MakeMNat 0 maxBound = MakeMNat . fromInteger $ natVal (Proxy :: Proxy n) 

 ghci> maxBound :: MNat 5 MakeMNat 5 

You can use type synonyms to correct individual types. The rest of your code compiles fine with this polymorphic MNat with mechanical changes. You must add the KnownNat context everywhere and use ScopedTypeVariables in MNat .

+7
source share

All Articles