Reputation: 441
Say I have the following datatype:
data MyType = Element1 (Maybe Int) | Element2 (Maybe Int)
instance1 = Element1 (Just 1)
instance2 = function(instance1)
What can I use in place of function
with so that instance2 = Element1 (Just 2)
?
Upvotes: 1
Views: 99
Reputation: 5459
You could define your data type using record syntax:
data MyType = Element1 { x :: (Maybe Int) } | Element2 { x :: (Maybe Int)}
instance1 = Element1 (Just 1)
instance2 = instance1 { x = Just 2 }
Upvotes: 1
Reputation: 153162
You give three equations:
instance1 = Element1 (Just 1)
instance2 = function(instance1)
instance2 = Element1 (Just 2)
Let's use these equations to solve for function
.
function (instance1) = instance2
function (Element1 (Just 1)) = instance2
function (Element1 (Just 1)) = Element1 (Just 2)
This final line:
function (Element1 (Just 1)) = Element1 (Just 2)
is a perfectly good chunk of Haskell code that defines a function named function
. Of course, it doesn't say what to do with things that are actually Element2
s, or that are Element1
s containing Nothing
s, or that are Element1
s containing Just
s containing things that aren't 1
! But it does meet the specification given by the three original equations, and I think is an excellent demonstration of the concept of "equational reasoning" that Haskell shares with mathematics.
Upvotes: 4
Reputation: 532053
If you generlize your type slightly, you can make it a functor:
{-# LANGUAGE DeriveFunctor #-}
data MyType a = Element1 (Maybe a) | Element2 (Maybe a) deriving (Functor, Show)
Then the function you are looking for is (<$)
, from the Functor
typeclass.
> i1 = Element1 (Just 1)
> i1
Element1 (Just 1)
> 2 <$ i1
Element1 (Just 2)
If you don't want to use the DeriveFunctor
extension, the instance is trivial to define manually.
instance Functor MyType where
fmap f (Element1 x) = Element1 (fmap f x)
fmap f (Element2 x) = Element2 (fmap f x)
A specialized version of (<$)
for a monomorphic type might look like
data MyType = Element1 (Maybe Int) | Element2 (Maybe Int)
change :: Int -> MyType -> MyType
change new (Element1 old) = Element1 (new <$ old)
change new (Element2 old) = Element2 (new <$ old)
Or, you might define your type as a product, to generalize the function over the data constructors.
data MyTypeTags = Element1 | Element2
data MyType = MyType MyTypeTags (Maybe Int)
change :: Int -> MyType -> MyType
change new (MyType tag old) = MyType tag (new <$ old)
Upvotes: 3