To level set, here's a simple functor:
data Box a = Box a deriving (Show)
instance Functor Box where
fmap f (Box x) = Box (f x)
This allows us to operate "inside the box":
> fmap succ (Box 1)
Box 2
How do I achieve this same syntactic convenience with a newtype? Let's say I have the following:
newtype Width = Width { unWidth :: Int } deriving (Show)
newtype Height = Height { unHeight :: Int } deriving (Show)
This is a bit clunky:
> Width $ succ $ unWidth (Width 100)
Width {unWidth = 101}
This would be nice:
> fmap succ (Width 100) -- impossible?
Width {unWidth = 101}
Of course, I can't make Width or Height an instance of a Functor since neither has kind * -> *
. Although, syntactically they feel no different than Box, and so it seems like it should be possible to operate on the underlying value without all of the manual wrapping and unwrapping.
Also, it isn't satisfying to create n functions like this because of the repetition with every new newtype:
fmapWidth :: (Int -> Int) -> Width -> Width
fmapHeight :: (Int -> Int) -> Height -> Height
How do I lift a function on Ints to be a function on Widths?
over
from lens (or similar packages): given a lens for your field calledunWidth
,over unWidth
does what you want (i.e. it lets you work with a monomorphic functor). – duplodedata Width
ornewtype Box a
and nothing changes (except laziness which is not important here). – n. 1.8e9-where's-my-share m.