Reputation: 1159
How do I convert newtype to Int and vice versa?
I tried:
newtype NT1 = NT1 Integer
fromNT1toInt :: NT1 -> Int
fromNT1toInt x = let y = x :: Int
in y
but I get could't match expected type error
I tried making NT1 instance of Enum class but I don't understand well how does toEnum work
newtype NT1 = NT1 Integer
instance Enum NT1 where
toEnum x = let x = x :: Integer
in if x >= 0
then x :: NT1
else x :: NT1
when I call toEnum 5 :: NT1 this should return 5 NT1 but I get StackOverflow error. Where am I making mistake?
Edited: newtype name
Upvotes: 4
Views: 1298
Reputation: 54971
e :: t
doesn’t mean “convert expression e
to type t
”, it’s just an annotation that says “e
has type t
(already)”. So this:
let y = x :: Int in y
Means: assert that x
has type Int
, set y
equal to x
, and return y
. That’s why you got a type mismatch: x
does not have type Int
as you are claiming to the compiler. And this:
let x = x :: Integer
in if x >= 0 then x :: NT1 else x :: NT1
Means: declare a new variable x
, set it equal to itself (an infinite loop), asserting that it has type Integer
, then test whether that infinite loop returns a nonnegative value; either way, return x
, asserting that it has type NT1
(this contradicts the Integer
from before).
To convert between Integer
and Int
, you can use fromIntegral :: (Integral a, Num b) => a -> b
, which converts any integral type (such as Int
or Integer
) into any numeric type (such as Int
, Integer
, Float
, Double
, or Ratio
).
For converting from newtype
s, you can use pattern-matching:
fromNT1ToInt :: NT1 -> Int
fromNT1ToInt (NT1 x) = fromIntegral x
Or add a record accessor function to the newtype
and use that:
newtype NT1 = NT1 { nt1Val :: Integer }
-- Note: nt1Val :: NT1 -> Integer
fromNT1ToInt :: NT1 -> Int
fromNT1ToInt nt = fromIntegral (nt1Val nt)
-- Or, with function composition (.):
fromNT1ToInt = fromIntegral . nt1Val
Or, finally, use coerce
from Data.Coerce
:
import Data.Coerce (coerce)
fromNT1ToInt :: NT1 -> Int
fromNT1ToInt nt = fromIntegral (coerce nt :: Integer)
And of course, to construct a newtype
you just use its constructor—in this case, NT1 :: Integer -> NT1
, e.g. NT1 5
.
Upvotes: 7
Reputation: 33389
Use fromIntegral
to convert between integral types, such as Int
and Integer
. Use NT1
to convert from Integer
to NT1
, and pattern-matching from NT1
to Integer
. Finally, you can compose functions to connect things.
toNT1 :: Int -> NT1
toNT1 = NT1 . fromIntegral
fromNT1 :: NT1 -> Int
fromNT1 (NT1 x) = fromIntegral x
Upvotes: 5