Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting from newtype to Int and from Int to newtype

Tags:

haskell

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

like image 261
cheshire Avatar asked Sep 20 '25 15:09

cheshire


2 Answers

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.

like image 154
Jon Purdy Avatar answered Sep 22 '25 23:09

Jon Purdy


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
like image 41
Li-yao Xia Avatar answered Sep 22 '25 23:09

Li-yao Xia