cheshire
cheshire

Reputation: 1159

Converting from newtype to Int and from Int to newtype

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

Answers (2)

Jon Purdy
Jon Purdy

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 newtypes, 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

Li-yao Xia
Li-yao Xia

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

Related Questions