Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding maybeness to a Haskell data type (with record syntax)

Tags:

haskell

maybe

Looking at an answer to this question:

https://stackoverflow.com/a/34164251/1052117

I see that it defines a data type that is used to parse a JSON object.

data Address = Address
    { house  :: Integer
    , street :: String
    , city   :: String
    , state  :: Maybe String
    , zip    :: String -- here I change the original, zip codes are strings, they have leading zeros.
    } deriving (Show, Eq)

$(deriveJSON defaultOptions ''Address)

This is helpful, but I wonder: How could I change the Address data type to have all json fields be nullable? Specifically I see a Maybe before the state field, but I'm imagining a larger data structure where it would be tedious to modify all of the fields to Maybe fields. For example, while I /could/ re-write above as:

data Address = Address
    { house  :: Maybe Integer
    , street :: Maybe String
    , city   :: Maybe String
    , state  :: Maybe String
    , zip    :: Maybe String
    } deriving (Show, Eq)

What function could I apply to the Address data type /in code/ to achieve this same result without rewriting all the code and manually inserting the Maybes?

like image 803
Mittenchops Avatar asked Dec 27 '18 09:12

Mittenchops


People also ask

What are the benefits of Record Syntax in Haskell?

The main benefit of this is that it creates functions that lookup fields in the data type. By using record syntax to create this data type, Haskell automatically made these functions: firstName, lastName, age, height, phoneNumber and flavor. There's another benefit to using record syntax.

Can you have multiple constructors in Haskell?

In Haskell, you can have many constructors for your data type, separated by a vertical bar |. Each of your constructors then has its own list of data types! So different constructors of the same type can have different underlying data! We refer to a type with multiple constructors as a “sum” type.

Why build your own types in Haskell?

So it’s not surprising that Haskell has some nifty constructs for building our own types. Constructors and sum types give us the flexibility to choose what kind of data we want to store. We can even change the data stored for different elements of the same type!

Why never add typeclass constraints in data declarations in Haskell?

However, it's a very strong convention in Haskell to never add typeclass constraints in data declarations. Why? Well, because we don't benefit a lot, but we end up writing more class constraints, even when we don't need them.


1 Answers

As is discussed in the comments, using a functor-functor would work for this with just very small changes to the original data type.

If you start out with

data Address = Address
    { house  :: Integer
    , street :: String
    , city   :: String
    , state  :: Maybe String
    , zip    :: String
    } deriving (Show, Eq)

then it is equivalent to

import Data.Functor.Identity

data AddressF f = Address
  { house  :: f Integer 
  , street :: f String
  , city   :: f String
  , state  :: Maybe String
  , zip    :: f String 
  } deriving (Show, Eq)

type Address = AddressF Identity

and then you can get the second one by writing

type Address' = AddressF Maybe

To get back to the original definition, you can write

toOriginal (AddressF (Identity house) (Identity street) (Identity city) mbState (Identity zip)) = Address house street city mbState zip
like image 101
Eliza Brandt Avatar answered Nov 15 '22 06:11

Eliza Brandt