Question

Suppose I have some ADT, like

data Foo = Foo !Int
         | Bar (Int->Int) Foo

Now say I want to impose some kind of extra type safety, getting rid of the "magic number type":

{-# LANGUAGE GADTs #-}

newtype Intey a = Intey { getIntey :: Int }

data Foo' a where
   Foo :: !(Intey a) -> Foo' a
   Bar :: (Intey a -> Intey b) -> Foo' a -> Foo' b

Since b is just a phantom argument within the constructor, has no constraints or anything else, it is basically meaningless – except for the type checker. Can it therefore compile down to the same as Foo, without any performance etc. cost?

Was it helpful?

Solution

You'd need to look at the Core to be absolutely sure, but in general:

  • newtype has no runtime cost compared to the underlying type. However something like map getIntey will still traverse the list doing nothing.

  • Types and type parameters themselves are erased during compilation so should also have no runtime cost - this is one of the advantages of static typing. It's only if you use a type class that a runtime value might be passed around.

So in most cases you can expect the same performance, but you may need to be a little careful about operations on containers like lists.

If you restrict yourself to GHC 7.8, then the new coerce function can help with that too.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top