Is it possible to define your own Persistent / Esqueleto lens? - haskell

Given the following persistent type:
share
[mkPersist sqlSettings, mkMigrate "migrateAll"]
[persistLowerCase|
Account
email Text
passphrase Text
firstName Text
lastName Text
deriving Eq Show Generic
|]
What I think is a kind of lens is generated, ie AccountEmail, AccountPassphrase etc etc. Is it possible to combine these in such a way, not necessarily composition but say string concatenation, I often find myself writing these kinds of functions:
accountFullName :: SqlExpr (Entity Account) -> SqlExpr Text
accountFullName acc = acc ^. AccountFirstName ++. val " " ++. acc ^. AccountLastName
It would be good if I could define this in a similar way to Account* so I can call them using ^. rather than using raw functions, ie acc ^. AccountFullName. This may not be an appropriate way of using these accessors, but if it isn't I would be interested to know why as I feel it may help further my understanding of this part of the Persistent library, as I feel fairly lost when I look at the code around EntityField...

This isn't really possible.
(^.) :: (PersistEntity val, PersistField typ)
=> expr (Entity val)
-> EntityField val typ
-> expr (Value typ)
You'll see that the second argument is EntityField val typ, which is a type family defined in the PersistEntity val class. This is pre-defined for your table, and can't be changed, so this particular operator can't be used for custom accessors the way you want.
When you use persistLowerCase and friends, it uses Template Haskell to parse your definition and generate appropriate data definitions. As I understand it, something similar to the following is generated:
data Account = Account
{ accountEmail :: Text
, accountPassphrase :: Text
, accountFirstName :: Text
, accountLastName :: Text
}
data AccountField a where
AccountId :: AccountField Key
AccountEmail :: AccountField Text
AccountPassphrase :: AccountField Text
AccountFirstName :: AccountField Text
AccountLastName :: AccountField Text
instance PersistEntity Account where
data EntityField Account a = AccountField a
...
(This isn't syntactically accurate and is missing a lot of detail, but it provides enough context for this situation I think.)
So the "lens" you pass to (^.) is actually just a constructor for a type associated with your table type Account. You can't create new constructors or re-associate the type family dynamically, so you can't make something else that can be passed to (^.). These accessors are effectively set in stone.
I think it makes the most sense to just go with the raw function. accountFullName acc isn't bad to write, and it makes it clear that you're doing something a little more complex than just pulling a field value.

Related

QuickCheck Arbitrary instance for abstract data type with smart constructor

I am new to the language, trying to write my first non-trivial program. On the way, I am stuck creating an Arbitrary instance. Yet, I suppose my question to follow points at my general lack of understanding composing several applicative and monadic types. Hence, I hope to gain fundamental insight form the following. Thanks for your help!
I defined an Address type and a smart constructor with validation of the individual fields as follows:
data Address = Address
{ street :: StreetName
, streetExt :: Maybe StreetName
, city :: CityName
, zipCode :: ZipCode
, country :: CC.CountryCode
} deriving (Eq, Show)
mkAddress :: Text -> Maybe Text -> Text -> Text -> Text -> Maybe Address
mkAddress aStreet aStreetExt aCity aZipCode aCountry =
Address <$> mkStreetName aStreet
<*> Just (aStreetExt >>= mkStreetName)
<*> mkCityName aCity
<*> mkZipCode aZipCode
<*> CC.fromMText aCountry
StreetName, CityName and ZipCode are newtype wrappers for Text with a validating smart constructor that simply limits the maximum length of these fields. The streetExt field is optional. The country code uses Data.ContryCodes.CountryCode.
The overall type is abstract, the defining module only exports the smart constructor but not the data constructor.
I am now trying to create an Arbitrary instance for this type>
instance Arbitrary D.Address where
arbitrary = do
maybeAddress <- D.mkAddress <$> arbitrary -- streetName
<*> return Nothing -- streetExt
<*> arbitrary -- city
<*> arbitrary -- zipCode
<*> elements ["DE", "FR", "AG", "RW"] -- country
return fromJust maybeAddress
However, I am stuck with the following type checker error:
• Couldn't match type ‘Maybe a0 -> a0’ with ‘Gen D.Address’
Expected type: Maybe D.Address -> Gen D.Address
Actual type: Maybe D.Address -> Maybe a0 -> a0
• The function ‘return’ is applied to two arguments,
but its type ‘(Maybe a0 -> a0)
-> Maybe D.Address -> Maybe a0 -> a0’
has only three
From this error, I take that there is some issue wrapping the Generator inside the Maybe, or the other way around. But even after several experiments lift and join I can't get it to type check. Thus, I suspect that my mental model is flawed of how the types are wrapped and how the generator monads are returned.
It would be great if someone could point out my mistake.
In addition, I would highly appreciate a comment on this type of data modelling with abstract types and smart constructors - is this general recommended practice, or does it lead to problems like the one I am facing?
Thanks very much!
The error message says it (although the subsequent explanation is misleading):
The function ‘return’ is applied to two arguments
You have
return fromJust maybeAddress
You want
return (fromJust maybeAddress)

Code reuse in Haxl - avoiding GADT constructor-per-request-type

Haxl is an amazing library, but one of the major pain points I find is caused by the fact that each sort of request to the data source requires its own constructor in the Request GADT. For example, taking the example from the tutorial:
data BlogRequest a where
FetchPosts :: BlogRequest [PostId]
FetchPostContent :: PostId -> BlogRequest PostContent
Then each of these constructors are pattern matched on and processed separately in the match function of the DataSource instance. This style results in a lot of boilerplate for a non-trivial application. Take for example an application using a relational database, where each table has a primary key. There may be many hundreds of tables so I don't want to define a constructor for each table (let alone on all the possible joins across tables...). What I really want is something like:
data DBRequest a where
RequestById :: PersistEntity a => Key a -> DBRequest (Maybe a)
I'm using persistent to create types from my tables, but that isn't a critical detail -- I just want to use a single constructor for multiple possible return types.
The problem comes when trying to write the fetch function. The usual procedure with Haxl is to pattern match on the constructor to separate out the various types of BlockedFetch requests, which in the above example would correspond to something like this:
resVars :: [ResultVar (Maybe a)]
args :: [Key a]
(psArgs, psResVars) = unzip
[(key, r) | BlockedFetch (RequestById key) r <- blockedFetches]
...then I would (somehow) group the arguments by their key type, and dispatch a SQL query for each group. But that approach won't because here may be requests for multiple PersistentEntity types (i.e. database tables), each of which is a different type a, so building the list is impossible. I've thought of using an existentially quantified type to get around this issue (something like SomeSing in the singletons library), but then I see no way to group the requests as required without pattern matching on every possible table/type.
Is there any way to achieve this sort of code reuse?
I see two approaches:
Typeable:
data DBRequest a where
RequestById :: (Typeable a, PersistEntity a) => Key a -> DBRequest (Maybe a)
or GADT "tag" type:
data Tag a where
TagValue1 :: Tag Value1
TagValue2 :: Tag Value2
TagValue3 :: Tag Value3
TagValue4 :: Tag Value4
TagValue5 :: Tag Value5
data DBRequest a where
RequestById :: PersistEntity a => Tag a => Key a -> DBRequest (Maybe a)
These are very similar patterns, especially If you use GHC-8.2,
with https://hackage.haskell.org/package/base-4.10.1.0/docs/Type-Reflection.html
(replace Tag a with TypeRep a).
Either way, you can group Key a using the tag. I haven't tried, but
dependent-map might be handy: http://hackage.haskell.org/package/dependent-map

What's the difference between makeLenses and makeFields?

Pretty self-explanatory. I know that makeClassy should create typeclasses, but I see no difference between the two.
PS. Bonus points for explaining the default behaviour of both.
Note: This answer is based on lens 4.4 or newer. There were some changes to the TH in that version, so I don't know how much of it applies to older versions of lens.
Organization of the lens TH functions
The lens TH functions are all based on one function, makeLensesWith (also named makeFieldOptics inside lens). This function takes a LensRules argument, which describes exactly what is generated and how.
So to compare makeLenses and makeFields, we only need to compare the LensRules that they use. You can find them by looking at the source:
makeLenses
lensRules :: LensRules
lensRules = LensRules
{ _simpleLenses = False
, _generateSigs = True
, _generateClasses = False
, _allowIsos = True
, _classyLenses = const Nothing
, _fieldToDef = \_ n ->
case nameBase n of
'_':x:xs -> [TopName (mkName (toLower x:xs))]
_ -> []
}
makeFields
defaultFieldRules :: LensRules
defaultFieldRules = LensRules
{ _simpleLenses = True
, _generateSigs = True
, _generateClasses = True -- classes will still be skipped if they already exist
, _allowIsos = False -- generating Isos would hinder field class reuse
, _classyLenses = const Nothing
, _fieldToDef = camelCaseNamer
}
What do these mean?
Now we know that the differences are in the simpleLenses, generateClasses, allowIsos and fieldToDef options. But what do those options actually mean?
makeFields will never generate type-changing optics. This is controlled by the simpleLenses = True option. That option doesn't have haddocks in the current version of lens. However, lens HEAD added documentation for it:
-- | Generate "simple" optics even when type-changing optics are possible.
-- (e.g. 'Lens'' instead of 'Lens')
So makeFields will never generate type-changing optics, while makeLenses will if possible.
makeFields will generate classes for the fields. So for each field foo, we have a class:
class HasFoo t where
foo :: Lens' t <Type of foo field>
This is controlled by the generateClasses option.
makeFields will never generate Iso's, even if that would be possible (controlled by the allowIsos option, which doesn't seem to be exported from Control.Lens.TH)
While makeLenses simply generates a top-level lens for each field that starts with an underscore (lowercasing the first letter after the underscore), makeFields will instead generate instances for the HasFoo classes. It also uses a different naming scheme, explained in a comment in the source code:
-- | Field rules for fields in the form # prefixFieldname or _prefixFieldname #
-- If you want all fields to be lensed, then there is no reason to use an #_# before the prefix.
-- If any of the record fields leads with an #_# then it is assume a field without an #_# should not have a lens created.
camelCaseFields :: LensRules
camelCaseFields = defaultFieldRules
So makeFields also expect that all fields are not just prefixed with an underscore, but also include the data type name as a prefix (as in data Foo = { _fooBar :: Int, _fooBaz :: Bool }). If you want to generate lenses for all fields, you can leave out the underscore.
This is all controlled by the _fieldToDef (exported as lensField by Control.Lens.TH).
As you can see, the Control.Lens.TH module is very flexible. Using makeLensesWith, you can create your very own LensRules if you need a pattern not covered by the standard functions.
Disclaimer: this is based on experimenting with the working code; it gave me enough information to proceed with my project, but I'd still prefer a better-documented answer.
data Stuff = Stuff {
_foo
_FooBar
_stuffBaz
}
makeLenses
Will create foo as a lens accessor to Stuff
Will create fooBar (changing the capitalized name to lowercase);
makeFields
Will create baz and a class HasBaz; it will make Stuff an instance of that class.
Normal
makeLenses creates a single top-level optic for each field in the type. It looks for fields that start with an underscore (_) and it creates an optic that is as general as possible for that field.
If your type has one constructor and one field you'll get an Iso.
If your type has one constructor and multiple fields you'll get many Lens.
If your type has multiple constructors you'll get many Traversal.
Classy
makeClassy creates a single class containing all the optics for your type. This version is used to make it easy to embed your type in another larger type achieving a kind of subtyping. Lens and Traversal optics will be created according to the rules above (Iso is excluded because it hinders the subtyping behavior.)
In addition to one method in the class per field you'll get an extra method that makes it easy to derive instances of this class for other types. All of the other methods have default instances in terms of the top-level method.
data T = MkT { _field1 :: Int, _field2 :: Char }
class HasT a where
t :: Lens' a T
field1 :: Lens' a Int
field2 :: Lens' a Char
field1 = t . field1
field2 = t . field2
instance HasT T where
t = id
field1 f (MkT x y) = fmap (\x' -> MkT x' y) (f x)
field2 f (MkT x y) = fmap (\y' -> MkT x y') (f y)
data U = MkU { _subt :: T, _field3 :: Bool }
instance HasT U where
t f (MkU x y) = fmap (\x' -> MkU x' y) (f x)
-- field1 and field2 automatically defined
This has the additional benefit that it is easy to export/import all the lenses for a given type. import Module (HasT(..))
Fields
makeFields creates a single class per field which is intended to be reused between all types that have a field with the given name. This is more of a solution to record field names not being able to be shared between types.

Tagging a string with corresponding symbol

I would like an easy way to create a String tagged with itself. Right now I can
do something like:
data TagString :: Symbol -> * where
Tag :: String -> TagString s
deriving Show
tag :: KnownSymbol s => Proxy s -> TagString s
tag s = Tag (symbolVal s)
and use it like
tag (Proxy :: Proxy "blah")
But this is not nice because
The guarantee about the tag is only provided by tag not by the GADT.
Every time I want to create a value I have to provide a type signature, which
gets unwieldy if the value is part of some bigger expression.
Is there any way to improve this, preferably going in the opposite direction, i.e. from String to Symbol? I would like to write Tag "blah" and have ghc infer the type
TagString "blah".
GHC.TypeLits provides the someSymbolVal function which looks somewhat
related but it produces a SomeSymbol, not a Symbol and I can quite grasp how to use
it.
Is there any way to improve this, preferably going in the opposite direction, i.e. from String to Symbol?
There is no way to go directly from String to Symbol, because Haskell isn't dependently typed, unfortunately. You do have to write out a type annotation every time you want a new value and there isn't an existing tag with the desired symbol already around.
The guarantee about the tag is only provided by tag not by the GADT.
The following should work well (in fact, the same type can be found in the singletons package):
data SSym :: Symbol -> * where
SSym :: KnownSymbol s => SSym s
-- defining values
sym1 = SSym :: SSym "foo"
sym2 = SSym :: SSym "bar"
This type essentially differs from Proxy only by having the KnownSymbol dictionary in the constructor. The dictionary lets us recover the string contained within even if the symbol is not known statically:
extractString :: SSym s -> String
extractString s#SSym = symbolVal s
We pattern matched on SSym, thereby bringing into scope the implicit KnownSymbol dictionary. The same doesn't work with a mere Proxy:
extractString' :: forall (s :: Symbol). Proxy s -> String
extractString' p#Proxy = symbolVal p
-- type error, we can't recover the string from anywhere
... it produces a SomeSymbol, not a Symbol and I can quite grasp how to use it.
SomeSymbol is like SSym except it hides the string it carries around so that it doesn't appear in the type. The string can be recovered by pattern matching on the constructor.
extractString'' :: SomeSymbol -> String
extractString'' (SomeSymbol proxy) = symbolVal proxy
It can be useful when you want to manipulate different symbols in bulk, for example you can put them in a list (which you can't do with different SSym-s, because their types differ).

Haskell generic data structure

I want to create a type to store some generic information, as for me, this type is
Molecule, where i store chemical graph and molecular properties.
data Molecule = Molecule {
name :: Maybe String,
graph :: Gr Atom Bond,
property :: Maybe [Property] -- that's a question
} deriving(Show)
Properties I want to represent as tuple
type Property a = (String,a)
because a property may have any type: Float, Int, String e.t.c.
The question is how to form Molecule data structure, so I will be able to collect any numbers of any types of properties in Molecule. If I do
data Molecule a = Molecule {
name :: Maybe String,
graph :: Gr Atom Bond,
property :: Maybe [Property a]
} deriving(Show)
I have to diretly assign one type when I create a molecule.
If you know in advance the set of properties a molecule might have, you could define a sum type:
data Property = Mass Float | CatalogNum Int | Comment String
If you want this type to be extensible, you could use Data.Dynamic as another answer suggests. For instance:
data Molecule = Molecule { name :: Maybe String,
graph :: Gr Atom Bond,
property :: [(String,Dynamic)]
} deriving (Show)
mass :: Molecule -> Maybe Float
mass m = case lookup "mass" (property m) of
Nothing -> Nothing
Just i -> fromDynamic i
You could also get rid of the "stringly-typed" (String,a) pairs, say:
-- in Molecule:
-- property :: [Dynamic]
data Mass = Mass Float
mass :: Molecule -> Maybe Mass
mass m = ...
Neither of these attempts gives much type safety over just parsing out of (String,String) pairs since there is no way to enforce the invariant that the user creates well-formed properties (short of wrapping properties in a new type and hiding the constructors in another module, which again breaks extensibility).
What you might want are Ocaml-style polymorphic variants. You could look at Vinyl, which provides type-safe extensible records.
As an aside, you might want to get rid of the Maybe wrapper around the list of properties, since the empty list already encodes the case of no properties.
You might want to look at Data.Dynamic for a psudo-dynamic typing solution.

Resources