I am struggling with understanding the newtype declaration. I am experimenting with the exercises in LYAH: http://learnyouahaskell.com/functors-applicative-functors-and-monoids#the-newtype-keyword
And wanted to use the newtype for the custom type instantiation Tofu Frank as seen below following LYAH's recipe: http://learnyouahaskell.com/making-our-own-types-and-typeclasses, but adding the newtype-part myself.
class Tofu t where
tofu :: j a -> t a j
instance Tofu Frank where
tofu x = Frank x
data Frank a b = Frank {frankField :: b a} deriving (Show)
newtype Frank a b = Frank{frankField :: (b a)} deriving Show
OUTPUT:
Multiple declarations of `Frank'
Declared at: tryouts.hs:563:1
tryouts.hs:572:1
In the description of newtype in LYAH:http://learnyouahaskell.com/functors-applicative-functors-and-monoids#the-newtype-keyword it is stated that:
Instead of the data keyword, the newtype keyword is used. Now why is that? Well for one, newtype is faster. If you use the data keyword to wrap a type, there's some overhead to all that wrapping and unwrapping when your program is running. But if you use newtype, Haskell knows that you're just using it to wrap an existing type into a new type (hence the name), because you want it to be the same internally but have a different type. With that in mind, Haskell can get rid of the wrapping and unwrapping once it resolves which value is of what type.
But do I misunderstand newtype here and will the newtype not overwrite the existing data type, as long as the former has a only one field in the constructor as is the case in my example? It does seem to work if I just leave out the data-declaration part.
Note that the description in LYAH says that
newtypeis used instead ofdata. That's the key. Bothdataandnewtypedeclare a new datatype (Frank, in your case), and you're supposed to only use only one or the other, not both for the same new datatype. So, you either write:if you want
Frankto be a regulardatatype, or else you write:if you want
Frankto be anewtypeinstead.In general, Haskell doesn't support "overwriting" (or redefining or redeclaraing) datatypes, whether you use
dataornewtypeor some mixture. Other languages might be more flexible in this regard. For example, Python will let you define aclass Frank, reference it in some code, and the redefineclass Frankand use the new class in some more code:However, Haskell requires that a new datatype is defined in exactly one place. It's similar to the way Haskell also requires a (global) function to be defined in only one place. Multiple definition lines that are consecutive are considered to be part of a single definition:
and multiple definitions that are non-consecutive are rejected: