I declare the following newtypes:
newtype Code = Code String deriving (Show)
newtype Name = Name String deriving (Show)
newtype Account = Account (Code, Name) deriving (Show)
So:
*Main Lib> :t Code
Code :: String -> Code
*Main Lib> :t Name
Name :: String -> Name
*Main Lib> :t Account
Account :: (Code, Name) -> Account
and then I create some instances:
cn = Code "1.1.1"
nn = Name "Land And Buildings"
an = Account (cn, nn)
*Main Lib> an
Account (Code "1.1.1",Name "Land And Buildings")
Now I need to access for example just the Code
field from the variable an
, something like an.Code
How can I do that?
Is it better to use Data
instead of a newtype
? If Haskell lets me create a newtype named tuple, then I guess there should be an easy way to access the elements inside.
Is it better to use
data
instead of anewtype
?
Um, yes... the whole point of newtype
is to give a single type a new name. It's not supposed to be used for building composite types. So, like user2407038 suggested, make it
data Account = Account
{ accCode :: Code
, accName :: Name
} deriving (Show)
and then you can simply use
*Main Lib> let an = Account (Code "1.1.1") (Name "Land And Buildings")
*Main Lib> accCode an
Code "1.1.1"
That said, it's also not difficult to access fields in a tuple buried in a newtype, provided you give the newtype an unwrapper:
newtype Account = Account {getAccount :: (Code, Name)}
deriving (Show)
then
*Main Lib> let an = Account (Code "1.1.1", Name "Land And Buildings")
*Main Lib> fst $ getAccount an
Code "1.1.1"
If you want to be fancy, you can also use the “20.2nd century record accessors”, lenses:
{-# LANGUAGE TemplateHaskell, FunctionalDependencies #-}
import Lens.Micro
import Lens.Micro.TH
data Account = Account
{ accountCode :: Code
, accountName :: Name
} deriving (Show)
makeFields ''Account
then
*Main Lib> let an = Account (Code "1.1.1") (Name "Land And Buildings")
*Main Lib> an^.code
Code "1.1.1"
You can use pattern matching. E.g.
case an of
Account (Code c, Name n) -> "Code " ++ c ++ ", Name " ++ n
or, in a function definition you can directly write
foo :: Account -> String
foo (Account (Code c, Name n)) = "Code " ++ c ++ ", Name " ++ n
Using a data
is usually better.
data Account = Account Code Name
-- ...
case an of
Account (Code c) (Name n) -> "Code " ++ c ++ ", Name " ++ n
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With