Same variable name in Data types - haskell

Why using data types I cannot give same inner attribute name for those Data attributes?
Here I cannot reuse the variable name val in several Data
Does not compile
data Product = Product {val::String}deriving (Show, Eq)
data Price = Price {val::Double}deriving (Show, Eq)
data Discount = Discount { val::Double }deriving (Show, Eq)
compile
data Product = Product {productVal::String}deriving (Show, Eq)
data Price = Price {priceVal::Double}deriving (Show, Eq)
data Discount = Discount { discountVal::Double }deriving (Show, Eq)

Why using data types I cannot give same inner attribute name for those Data attributes?
If you define a record type, you implicitly have constructed a "getter". If you define a record datatype like:
data Product = Product { val :: String } deriving (Show, Eq)
then Haskell will construct a function:
val :: Product -> String
that obtains the val of a given Product object.
If you then later define a new record datatype:
data Price = Price { val :: Double } deriving (Show, Eq)
then you thus define two versions of val, which thus results in name clashes.
The DuplicateRecordFields extension
The Glasgow Haskell Compiler (GHC) has, since 8.0.1, an extension DuplicateRecordFields that allows to specify two record datatypes with the same field name.
There is no problem to use the same record name for pattern matching, or when we construct records, for example:
productToPrice :: Product -> Price
productToPrice (Product {val = x}) = Price { val = 3 }
creates no problems, since val in Product { val = x } clearly refers to the val defined in the Product data constructor, and val in Price { val = 3 } refers to the val of the Price data constructor.
If we however use val as a function, it will create ambiguity:
Prelude> val (Product "foo")
<interactive>:15:1: error:
Ambiguous occurrence ‘val’
It could refer to either the field ‘val’,
defined at <interactive>:1:25
or the field ‘val’, defined at <interactive>:2:21
We can add the signature of the function to specify which val we want to use:
Prelude> (val :: Product -> String) (Product "foo")
"foo"
or by specifying the type of Product "foo", we obtain the same effect:
Prelude> val (Product "foo" :: Product)
"foo"
Given val however has the same type, or has some generic meaning, it might be better to introduce a typeclass, and thus define the val function there.

Related

How to Serialize a Type to specified database columns

I am using postgresql-simple in a haskell application, and i want to be able to serialize a data type to a row in my database that doesn't have a 1 to 1 mapping of the record fields used in the data type because i am using them in other data types. (I'm Fairly New to Haskell but I think this involves using the Identifier data constructor).
Example I have a database table Users with the following columns: user_id, email, name, password, address, phone_number
now I have a type with the following format:
data UserDetails = UserDetails {
user_id :: Int,
email :: Text,
phone_number :: Maybe (Text),
password :: Text,
name :: Maybe (Text),
address :: Maybe (Text),
} deriving (Show, Generic, FromRow)
And i can have a generic ToRow implemented for this type no problem since the record fields are the same as the column names, but I have another type that i want to generate a ToRow instance for which is:
data UserEditDetails = UserEditDetails {
ued_email :: Maybe (Email),
ued_phone_number :: Maybe (Text),
ued_address :: Maybe (Text),
ued_name :: Maybe (Text),
} deriving (Show, Generic)
how would i implement a ToRow instance of this type or more generally how can i write a ToRow instance like the following pseudo code
instance ToRow UserEditDetails where
toRow a = (columnname, ued_email a)... etc
hopefully it has a function similar to Aeson where you can easily write something like:
instance ToJSON Login where
toJSON = genericToJSON defaultOptions { fieldLabelModifier = drop 4 }
but i havent found this.
postgresql-simple doesn't pay any attention to database column names. It just expects the count and order of columns serialized or deserialized by the ToRow/FromRow instances will match the count and order of columns in the SQL query. You can use the generic instance for ToRow UserEditDetails as long as the query you're feeding it to matches the four columns in the right order. For example, if you have the following definition and generic ToRow instance:
data UserEditDetails = UserEditDetails
{ ued_email :: Maybe Text
, ued_phone_number :: Maybe Text
, ued_address :: Maybe Text
, ued_name :: Maybe Text
} deriving (Show, Generic, ToRow)
then I believe the following query will work fine:
do let q = "update user_table set email=?, phone_number=?, address=?, name=? "
++ "where user_id=?"
execute conn q $ (UserEditDetails
(Just "me#example.invalid")
(Just "555-1212")
(Just "123 Fake Street")
(Just "Bob Jones"))
:. Only (15 :: Int) -- user_id 15
Note that the generic instances from FromRow and ToRow are equivalent to:
instance ToRow UserEditDetails where
toRow (UserEditDetails a b c d) = [toField a, toField b, toField c, toField d]
instance FromRow UserEditDetails where
fromRow = UserEditDetails <$> field <*> field <*> field <*> field
The fields are anonymous and there's no place to give specific database columns anyway.

Haskell : recursive data type (Parameterized Types)

I have this :
data Val s i a = S s | I i | A a deriving (Show)
To play with non-homogenous lists in Haskell. So I can do something like (just an example function ):
oneDown :: Val String Int [String]-> Either String String
But I would actually like this to be a list of Vals, i.e. something like :
oneDown :: Val String Int [Val]-> Either String String
What you're looking for would result in an infinite data type, which Haskell explicitly disallows. However, we can hide this infinity behind a newtype and the compiler won't complain.
data Val s i a = S s | I i | A a deriving (Show)
newtype Val' = Val' (Val String Int [Val']) deriving (Show)
It's still doing exactly what your example did (plus a few type constructors that will get optimized away at runtime), but now we can infinitely recurse because we've guarded the recursive type.
This is actually what the recursion-schemes library does to get inductively-defined data that we can define generic recursion techniques on. If you're interested in generalized data types like this, you may have a look at that library.
To construct this newly-made type, we have to use the Val' constructor.
let myVal = A [Val' (I 3), Val' (S "ABC"), Val' (A [])]

Ambiguous occurrence compilation error of custom data types in Haskell

I have a custom data type Person and Employee (DataTypesAPI.hs)
{-# LANGUAGE DuplicateRecordFields #-}
data Person = Person {fName :: String
, lName :: String
} deriving (Show, Generic, FromJSON, ToJSON, ToBSON, FromBSON)
data Employee = Employee {fName :: String
, lName :: String
, id :: String
} deriving (Show, Generic, FromJSON, ToJSON, ToBSON, FromBSON)
I have an instance of Employee (as e) and want to create Person instance from it so that fName and lName will be populated from Employee. Code snippet is (src/MyLib.hs)
import DataTypesAPI.hs (Employee(..), Person(..))
DataLink.map (\e -> Person (fName e) (lName e))
However, as both types have same attributes name ghc give compilation error
Ambiguous occurrence ‘last_commit_hash’
It could refer to either the field ‘fName’,
imported from ‘FirstHaskellAPI’ at src/MyLib.hs:68:101-115
or the field ‘fName’,
imported from ‘FirstHaskellAPI’ at src/MyLib.hs:68:53-98
In later part of my code I need both types. How to resolve such compilation error?
Try disambiguating it using e.g.
DataLink.map (\e -> Person (fName e) (lName (e :: Employee)))

Generic type for OO classes in Haskell

I want to have a generic type that can represent any class in a simple class diagram. In this case a class contains:
A name
Any number of arguments of any type
Any number of functions that takes any number of arguments of any type
I have only used simple ADT declarations which is not working in this case, for example this is what I have been stuck with but it gives me no where near the type of flexibility I'm after:
data Attr a = Attr { name :: String
, kind :: a}
deriving (Show)
data Action = Action { name1 :: String
, params :: [Attr Int]}
deriving (Show)
data Class a = NewC { name2 :: String
, attrs :: [Attr Int]
, actions :: [Action]}
deriving (Show)
So my question is now how would I go about representing any arbitrary class in Haskell?
I do not want to do OOP in haskell. Imaging that the class type I'm trying to make will be a node in a graph. However each node in the graph will be a different class.
I think you want to represent your class diagrams entirely as values rather than a mix of values and types. Instead of Attr Int, for example, you might use something like Attr { name="Int", kind=PrimitiveInt }. I've introduced an OopType type below.
data Attr = Attr { name :: String
, kind :: OopType}
deriving (Show)
data Action = Action { name1 :: String
, params :: [Attr]}
deriving (Show)
data Class = NewC { name2 :: String
, attrs :: [Attr]
, actions :: [Action]}
deriving (Show)
data OopType = ClassType Class
| InterfaceType Class -- TODO make a dedicated interface type
| Enum -- TODO make a dedicated enum type
| PrimitiveString
| PrimitiveInt
Note that this representation doesn't model 'generics' (that is, classes that are parameterised by types). To do that, you'd add another field to the Class type.

Convert Lens' a b into Lens' a (Maybe b)

I have several data structures like
data Data1 = Data1
{ _data1Field :: Int
-- More fields
} deriving (Eq, Show)
makeLenses ''Data1
data Data2 = Data2
{ _data2Field :: Int
-- More fields
} deriving (Eq, Show)
makeLenses ''Data2
-- More similar data types
So I decided to write a simple type class to make it easier to compose
class HasField a where
field :: Lens' a Int
instance HasField Data1 where
field = data1Field
instance HasField Data2 where
field = data2Field
But then I ran into the problem that some of these structures have the corresponding field as optional
data Data3 = Data3
{ _data3Field :: Maybe Int
-- More fields
} deriving (Eq, Show)
makeLenses ''Data3
And now I can no longer use the type class. Since there are about the same number of data types that have that field optional as not, I decided that it'd be better to change the typeclass:
class HasField a where
field :: Lens' a (Maybe Int)
instance HasField Data3 where
field = data3Field
But since I'm not very experienced with the lens library, I'm stuck figuring out how to make this new lens work with the types for Data1 and Data2. Ideally, I'd like to be able to view it and get a Maybe Int value for any type, and when setting I'd like Just x to set the field to x for Data1 and Data2 and be a no-op for those two types when passed Nothing.
Is this possible using existing combinators or am I going to have to write the lens myself? I'm fine doing so, but the majority of existing tutorials use TH and gloss over the details of writing one by hand.
I'm using GHC 7.6.3 and lens 3.10.
As a follow up to shachaf
class HasFieldA d where
field :: Traversal' d Int
instance HasFieldA Data1 where
field = data1Field -- Lens's are Traversals
instance HasFieldA Data3 where
field = data3Field . _Just
And then the ^? operator or the ^.. operator
getField :: HasFieldA d => d -> Maybe Int
getField = d ^? field -- or preview field d
to get it.
To set optional fields, you'd need another function
class SetFieldA d where
setField :: Setter' d Int
instance SetFieldA Data3 where
setField = set data3Field . Just

Resources