Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mandatory Maybes in the type system

Tags:

haskell

I have something similar to the following

data A = A
  { id :: Integer
  , foo :: Maybe String
  , bar :: Maybe String
  , baz :: Maybe String
  }

This data is coming in to my service as JSON. This request is only considered valid when one or more of foo, bar, or baz are given. Is there a better way to express this within Haskell's type system?

Note: Unfortunately I am unable to make this separate requests. I'm just following a defined protocol.

like image 774
Justin Wood Avatar asked Aug 10 '15 13:08

Justin Wood


People also ask

How many types of Erlang are there?

7 Types and Function Specifications.

What is type assertions in TypeScript?

In Typescript, Type assertion is a technique that informs the compiler about the type of a variable. Type assertion is similar to typecasting but it doesn't reconstruct code. You can use type assertion to specify a value's type and tell the compiler not to deduce it.

Should you type everything in TypeScript?

Yes, you should make it a habit to explicitly set all types, it's will prevent having unexpected values and also good for readability.


3 Answers

Expanding on ʎǝɹɟɟɟǝſ's suggestion to use a map: there's also a type specifically for non-empty maps. (Note however that this sort of clashes with the more popular nonempty-list type from the semigroups library.)

import qualified Data.NonEmpty.Map as NEM

data Field = Foo | Bar | Baz
data A = A { id :: Integer
           , fields :: NEM.T Field String
           }
like image 167
leftaroundabout Avatar answered Oct 17 '22 04:10

leftaroundabout


If it is not mandatory to have three separate fields with foo,bar and baz, I'd go with this, NonEmpty guarantees that there is at least one element, though there can of course be more.

import Data.List.NonEmpty

data Impression = Banner String | Video String | Native String

data A = A
  { id :: Integer
  , fooBarBaz :: NonEmpty Impression
  }
like image 32
Markus1189 Avatar answered Oct 17 '22 03:10

Markus1189


I would use a Map Field String with data Field = Foo | Bar | Baz (this can easily be replaced with String if needed, and then have:

data A = A
    { id :: Integer
    , fields :: Map Field String
    }

Now checking for the validity condition is as simple as:

isValid :: A -> Bool
isValid = not . Map.null . fields
like image 4
Shoe Avatar answered Oct 17 '22 03:10

Shoe