Mandatory Maybes in the type system - 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.

http://hackage.haskell.org/package/these-0.4.2/docs/Data-These.html
import Data.These
data A = A
{ id :: Integer
, fooBarBaz :: These Foo (These Bar Baz)
}
type Foo = String
type Bar = String
type Baz = String

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
}

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

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
}

Consider giving one branch for each possible required field:
data A
= Foo
{ foo :: String
, barM, bazM :: Maybe String
}
| Bar
{ bar :: String
, fooM, barM :: Maybe String
}
| Baz
{ baz :: String
, fooM, barM :: Maybe String
}
It's a fair bit of boilerplate, but it's very direct and quite clear about what's required.

Related

Safe Record field query

Is there a clean way to avoid the following boilerplate:
Given a Record data type definition....
data Value = A{ name::String } | B{ name::String } | C{}
write a function that safely returns name
getName :: Value -> Maybe String
getName A{ name=x } = Just x
getName B{ name=x } = Just x
getName C{} = Nothing
I know you can do this with Template Haskell, I am looking for a cleaner soln than that, perhaps a GHC extension or something else I've overlooked.
lens's Template Haskell helpers do the right thing when they encounter partial record fields.
{-# LANGUAGE TemplateHaskell #-}
import Control.Applicative
import Control.Lens
data T = A { _name :: String }
| B { _name :: String }
| C
makeLenses ''T
This'll generate a Traversal' called name that selects the String inside the A and B constructors and does nothing in the C case.
ghci> :i name
name :: Traversal' T String -- Defined at test.hs:11:1
So we can use the ^? operator (which is a flipped synonym for preview) from Control.Lens.Fold to pull out Maybe the name.
getName :: T -> Maybe String
getName = (^? name)
You can also make Prism's for the constructors of your datatype, and choose the first one of those which matches using <|>. This version is useful when the fields of your constructors have different names, but you do have to remember to update your extractor function when you add constructors.
makePrisms ''T
getName' :: T -> Maybe String
getName' t = t^?_A <|> t^?_B
lens is pretty useful!
Why don't you use a GADT? I do not know if you are interested in using only records. But, I fell that GADTs provide a clean solution to your problem, since you can restrict what constructors are valid by refining types.
{-# LANGUAGE GADTs #-}
module Teste where
data Value a where
A :: String -> Value String
B :: String -> Value String
C :: Value ()
name :: Value String -> String
name (A s) = s
name (B s) = s
Notice that both A and B produce Value String values while C produces Value (). When you define function
name :: Value String -> String
it specifically says that you can only pass a value that has a string in it. So, you can only pattern match on A or B values. This is useful to avoid the need of Maybe in code.

What is the right way to declare data that is an extension of another data

I am modelling a set of "things". For the most part all the things have the same characteristics.
data Thing = Thing { chOne :: Int, chTwo :: Int }
There is a small subset of things that can be considered to have an "extended" set of characteristics in addition to the base set shared by all members.
chThree :: String
I'd like to have functions that can operate on both kinds of things (these functions only care about properties chOne and chTwo):
foo :: Thing -> Int
I'd also like to have functions that operate on the kind of things with the chThree characteristic.
bar :: ThingLike -> String
I could do
data ThingBase = Thing { chOne :: Int, chTwo :: Int }
data ThingExt = Thing { chOne :: Int, chTwo :: Int, chThree :: Int }
fooBase :: ThingBase -> Int
fooExt :: ThingExt -> Int
bar :: ThingExt -> String
But this is hideous.
I guess I could use type classes, but all the boilerplate suggests this is wrong:
class ThingBaseClass a of
chOne' :: Int
chTwo' :: Int
instance ThingBaseClass ThingBase where
chOne' = chOne
chTwo' = chTwo
instance ThingBaseClass ThingExt where
chOne' = chOne
chTwo' = chTwo
class ThingExtClass a of
chThree' :: String
instance ThingExtClass ThingExt where
chThree' = chThree
foo :: ThingBaseClass a => a -> Int
bar :: ThingExtClass a => a -> String
What is the right way to do this?
One way to do so, is the equivalent of OO aggregation :
data ThingExt = ThingExt { thing :: Thing, chTree :: Int }
You can then create a class as in your post
instance ThingLike ThingExt where
chOne' = chOne . thing
chTwo' = chTwo . thing
If you are using the lens library you can use makeClassy which will generate all this boiler plate for you.
You can make a data type that is a type union of the two distinct types of things:
data ThingBase = ThingBase { chBaseOne :: Int, chBaseTwo :: Int }
data ThingExt = ThingExt { chExtOne :: Int, chExtTwo :: Int, chExtThree :: Int }
data ThingLike = CreatedWithBase ThingBase |
CreatedWithExt ThingExt
Then for any function which should take either a ThingBase or a ThingExt, and do different things depending, you can do pattern matching on the type constructor:
foo :: ThingLike -> Int
foo (CreatedWithBase (ThingBase c1 c2)) = c1 + c2
foo (CreatedWithExt (ThingExt c1 c2 c3)) = c3
-- Or another way:
bar :: ThingLike -> Int
bar (CreatedWithBase v) = (chBaseOne v) + (chBaseTwo v)
bar (CreatedWithExt v) = chExtThree v
This has the benefit that it forces you to pedantically specify exactly what happens to ThingBases or ThingExts wherever they appear to be processed as part of handling a ThingLike, by creating the extra wrapping layer of constructors (the CreatedWithBase and CreatedWithExt constructors I used, whose sole purpose is to indicate which type of thing you expect at a certain point of code).
But it has the disadvantage that it doesn't allow for overloaded names for the field accessor functions. Personally I don't see this as too big of a loss, since the extra verbosity required to reference attributes acts like a natural complexity penalty and helps motivate the programmer to keep the code sparse and use fewer bad accessor/getter/setter anti-patterns. However, if you want to go far with overloaded accessor names, you should look into lenses.
This is just one idea and it's not right for every problem. The example you already give with type classes is also perfectly fine and I don't see any good reason to call it hideous.
Just about the only "bad" thing would be wanting to somehow implicitly process ThingBases differently from ThingExts without needing anything in the type signature or the pattern matching sections of a function body to explicitly tell people reading your code precisely when and where the two different types are differentiated, which would be more like a duck typing approach which is not really what you should do in Haskell.
This seems to be what you're trying to get at by trying to force both ThingBase and ThingExt to have a value constructor with the same name of just Thing -- it seems artificially nice that the same word can construct values of either type, but my feeling is it's not actually nice. I might be misunderstanding though.
A very simple solution is to introduce a type parameter:
data ThingLike a = ThingLike { chOne, chTwo :: Int, chThree :: a }
deriving Show
Then, a ThingBase is just a ThingLike with no third element, so
type ThingBase = ThingLike ()
ThingExt contains an additional Int, so
type ThingExt = ThingLike Int
This has the advantage of using only a single constructor and only three record accessors. There is minimal duplication, and writing your desired functions is simple:
foo :: ThingLike a -> Int
foo (ThingLike x y _) = x+y
bar :: ThingExt -> String
bar (ThingLike x y z) = show $ x+y+z
One option is:
data Thing = Thing { chOne :: Int, chTwo :: Int }
| OtherThing { chOne :: Int, chTwo :: Int, chThree :: String }
Another is
data Thing = Thing { chOne :: Int, chTwo :: Int, chThree :: Maybe String }
If you want to distinguish the two Things at the type level and have overloaded accessors then you need to make use of a type class.
You could use a Maybe ThingExt field on ThingBase I guess, at least if you only have one extension type.
If you have several extensions like this, you can use a combination of embedding and matching on various constructors of the embedded data type, where each constructor represents one way to extend the base structure.
Once that becomes unmanageable, classes might become unevitable, but some kind of data type composition would still be useful to avoid duplication.

Haskell type with derived value

Is it possible to have a type preform a function one of its value to generate another one of it's values? For instance:
data Foo=Foo {valueOne::Int, valueTwo=valueOne*2} deriving (Bar)
Or am I thinking about this in the wrong way? Any help is appreciated!
If you always want the second field to depend on the first, just write a plain function:
data Foo = Foo { valueOne :: Int } deriving (Bar)
valueTwo :: Foo -> Int
valueTwo x = valueOne x * 2
The only difference is that the Bar instance, which is automatically generated, won't notice the second field.
If, instead, you want to generate values with such constraint, but still be able to sometimes disregard that, use a smart constructor:
data Foo = Foo { valueOne :: Int, valueTwo :: Int } deriving (Bar)
foo :: Int -> Foo
foo x = Foo x (2 * x)
If you use foo instead of Foo to construct new values, you will not need to pass the second argument, which will be derived from the first one.
Usually this is used in a module which does not export the constructor Foo, but exports the smart constructor foo. In this way the users of the module are constrained to build values satisfying the invariant, while the functions in the module can ignore it, when needed.

How to ignore a polymorph readable type, while reading?

I have a problem similar to:
data Foo a = Foo { myInt :: Integer, myValue :: a } deriving Read
bar :: String -> Integer
bar = myInt . read
main = print $ bar stringWithFooOfa
i don't want to use something like read . (!!1) . words, if i don't need to.
Add a type annotation to read. As commenters suggested, Haskell has no way of knowing what you're trying to read since you immediately turn it into an Int. To be more clear, consider this example:
data Foo a = Foo { myInt :: Integer, myValue :: a } deriving Read
data Foo2 a = Foo { myInt2 :: Integer } deriving Read
bar :: String -> Integer
bar = myInt . read
Now there are two very different behaviors for bar possible and it's hard to know which is correct.
To tell Haskell which one you want, use an inline annotation around read:
bar :: String -> Integer
bar = myInt . (read :: String -> Foo ())
Notice that I pick an a, too. Otherwise, we'll be in the same boat as above but just with a instead of Foo.

haskell variant of records with different field names

Given this:
data Foo = Bar { name :: String } | Baz { nickname :: String }
Both the functions name and nickname seem to be of type Foo -> String:
:t name
name :: Foo -> String
:t nickname
nickname :: Foo -> String
However, the definitions are incomplete since both of the following expressions will raise pattern match errors:
name $ Baz { nickname = "Bob" }
nickname $ Bar { name = "Fred" }
Is it possible to complete the definitions of name and nickname, i.e. something like:
name Baz { nickname = n } = ...
nickname Bar { name = n } = ...
Trying this in hugs yields errors like "Multiple declarations for variable name".
No, it's not possible. The field names are top-level functions with respect to scope and thus cannot be redefined or extended. It's as impossible to make them total functions as it is to make head one.
Try the -XDataKinds extension, it allows you to promote data constructors to be kinds.
Note that you'll need GHC 7.4.1, which was released just 12 days ago. This is a good time to be asking this question!

Resources