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

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

Related

Deriving Eq and Show for an ADT that contains fields that can't have Eq or Show

I'd like to be able to derive Eq and Show for an ADT that contains multiple fields. One of them is a function field. When doing Show, I'd like it to display something bogus, like e.g. "<function>"; when doing Eq, I'd like it to ignore that field. How can I best do this without hand-writing a full instance for Show and Eq?
I don't want to wrap the function field inside a newtype and write my own Eq and Show for that - it would be too bothersome to use like that.
One way you can get proper Eq and Show instances is to, instead of hard-coding that function field, make it a type parameter and provide a function that just “erases” that field. I.e., if you have
data Foo = Foo
{ fooI :: Int
, fooF :: Int -> Int }
you change it to
data Foo' f = Foo
{ _fooI :: Int
, _fooF :: f }
deriving (Eq, Show)
type Foo = Foo' (Int -> Int)
eraseFn :: Foo -> Foo' ()
eraseFn foo = foo{ fooF = () }
Then, Foo will still not be Eq- or Showable (which after all it shouldn't be), but to make a Foo value showable you can just wrap it in eraseFn.
Typically what I do in this circumstance is exactly what you say you don’t want to do, namely, wrap the function in a newtype and provide a Show for that:
data T1
{ f :: X -> Y
, xs :: [String]
, ys :: [Bool]
}
data T2
{ f :: OpaqueFunction X Y
, xs :: [String]
, ys :: [Bool]
}
deriving (Show)
newtype OpaqueFunction a b = OpaqueFunction (a -> b)
instance Show (OpaqueFunction a b) where
show = const "<function>"
If you don’t want to do that, you can instead make the function a type parameter, and substitute it out when Showing the type:
data T3' a
{ f :: a
, xs :: [String]
, ys :: [Bool]
}
deriving (Functor, Show)
newtype T3 = T3 (T3' (X -> Y))
data Opaque = Opaque
instance Show Opaque where
show = const "..."
instance Show T3 where
show (T3 t) = show (Opaque <$ t)
Or I’ll refactor my data type to derive Show only for the parts I want to be Showable by default, and override the other parts:
data T4 = T4
{ f :: X -> Y
, xys :: T4' -- Move the other fields into another type.
}
instance Show T4 where
show (T4 f xys) = "T4 <function> " <> show xys
data T4' = T4'
{ xs :: [String]
, ys :: [Bool]
}
deriving (Show) -- Derive ‘Show’ for the showable fields.
Or if my type is small, I’ll use a newtype instead of data, and derive Show via something like OpaqueFunction:
{-# LANGUAGE DerivingVia #-}
newtype T5 = T5 (X -> Y, [String], [Bool])
deriving (Show) via (OpaqueFunction X Y, [String], [Bool])
You can use the iso-deriving package to do this for data types using lenses if you care about keeping the field names / record accessors.
As for Eq (or Ord), it’s not a good idea to have an instance that equates values that can be observably distinguished in some way, since some code will treat them as identical and other code will not, and now you’re forced to care about stability: in some circumstance where I have a == b, should I pick a or b? This is why substitutability is a law for Eq: forall x y f. (x == y) ==> (f x == f y) if f is a “public” function that upholds the invariants of the type of x and y (although floating-point also violates this). A better choice is something like T4 above, having equality only for the parts of a type that can satisfy the laws, or explicitly using comparison modulo some function at use sites, e.g., comparing someField.
The module Text.Show.Functions in base provides a show instance for functions that displays <function>. To use it, just:
import Text.Show.Functions
It just defines an instance something like:
instance Show (a -> b) where
show _ = "<function>"
Similarly, you can define your own Eq instance:
import Text.Show.Functions
instance Eq (a -> b) where
-- all functions are equal...
-- ...though some are more equal than others
_ == _ = True
data Foo = Foo Int Double (Int -> Int) deriving (Show, Eq)
main = do
print $ Foo 1 2.0 (+1)
print $ Foo 1 2.0 (+1) == Foo 1 2.0 (+2) -- is True
This will be an orphan instance, so you'll get a warning with -Wall.
Obviously, these instances will apply to all functions. You can write instances for a more specialized function type (e.g., only for Int -> String, if that's the type of the function field in your data type), but there is no way to simultaneously (1) use the built-in Eq and Show deriving mechanisms to derive instances for your datatype, (2) not introduce a newtype wrapper for the function field (or some other type polymorphism as mentioned in the other answers), and (3) only have the function instances apply to the function field of your data type and not other function values of the same type.
If you really want to limit applicability of the custom function instances without a newtype wrapper, you'd probably need to build your own generics-based solution, which wouldn't make much sense unless you wanted to do this for a lot of data types. If you go this route, then the Generics.Deriving.Show and Generics.Deriving.Eq modules in generic-deriving provide templates for these instances which could be modified to treat functions specially, allowing you to derive per-datatype instances using some stub instances something like:
instance Show Foo where showsPrec = myGenericShowsPrec
instance Eq Foo where (==) = myGenericEquality
I proposed an idea for adding annotations to fields via fields, that allows operating on behaviour of individual fields.
data A = A
{ a :: Int
, b :: Int
, c :: Int -> Int via Ignore (Int->Int)
}
deriving
stock GHC.Generic
deriving (Eq, Show)
via Generically A -- assuming Eq (Generically A)
-- Show (Generically A)
But this is already possible with the "microsurgery" library, but you might have to write some boilerplate to get it going. Another solution is to write separate behaviour in "sums-of-products style"
data A = A Int Int (Int->Int)
deriving
stock GHC.Generic
deriving
anyclass SOP.Generic
deriving (Eq, Show)
via A <-𝈖-> '[ '[ Int, Int, Ignore (Int->Int) ] ]

I get an error when i try deriving eq. How can i fix this?

I am getting this error:
No instance for (Eq T1)
arising from the first field of TT' (typeMatrix T1')
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
When deriving the instance for (Eq TT)
|
20 | } deriving (Eq, Ord)
and I don't know why and how I can fix this ( error is the same for Ord)
Here's my code:
import Data.Matrix
data T1 = T1 { x :: Char
, y :: Int
, z :: Int
}
instance Show T1 where
show t1 = [(x t1)]
data TT = TT { myMap :: Matrix T1
, flag :: Int
} deriving (Eq, Ord)
Any idea?
In your example, a value of type TT contains a value of type T1; thus, to equate two values of type TT, you also need to know how to equate two values of type T1. But you haven't defined an Eq instance for T1! Add a deriving (Eq) clause to T1 and the error will go away. The same applies to Ord.
In general, if you have a type A, which contains a value of type B, in order to derive a typeclass on A, you need to derive that same typeclass on B. As described above, this occurs because in order to implement the methods of that typeclass on A, you need to already know how that typeclass behaves on B e.g. you can't equate A values unless you know how B values are equal (which is your example above). Another example: if you want to show values of type A as a String, you need to be able to convert B to a string.

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.

Specifying a constraint for a class

I have three data declarations in the different modules:
data Data1 = Data1
{ id :: UUID
, field2 :: String
, field3 :: Int
}
data Data2 = Data2
{ id :: UUID
, field1112 :: String
, field4433 :: String
}
data Data3 = Data3
{ id :: UUID
, field22 :: Double
, field344 :: Int
}
And a class declaration:
class MyClass1 a where
method1 ....
How can I specify a constraint for MyClass1 so that only Data1, Data2 and Data3 can be instantiated by MyClass1 because they all have the field id?
I tried the following, but it didn't seem right to me and I got errors:
-- in the different module
class MyDataBase a where
id :: a -> UUID
-- in the module Data1.hs
instance MyDataBase Data1 where
id d1 =
-- in the module Data2.hs
-- and so on....
class (MyDataBase a) => MyClass1 a where
method1 .... = -- calling
so that only Data1, Data2 and Data3 can be instantiated by MyClass1 because they all have the field id?
What about types you don't know about that also have that field?
In general, you can accomplish things like that with Lens (regular Haskell records are IMHO unusable); if you name your fields _Data1Id and _Data2Id (customizable), you'll get a HasId class with id lens and instances for that class for Data1 and Data2. Then you can use that class as a constraint further.
Of course you don't have to use makeFields and you can write the instances yourself. Not sure why you'd do that, though.
You didn't specify what errors you got, but I bumped off UndecidableInstances. Here's how to get around "Constraint is no smaller than the instance head" error:
class A a where aOp :: a -> Int
class B a where bOp :: a -> Int
data C = forall a. B a => C a
instance A C where aOp (C a) = bOp a
This will allow you to use any type that satisifies B in a A context (but as Carsten pointed out, it's also an antipattern of sorts).
You don't want to do that. The simplest way of achieving what you want is the following:
class HasId a where
getId :: a -> UUID
class HasId a => MyClass1 a where
method1 = -- NOTE: Use "getId" instead of plain "id".
when you define your data types you simply do:
data Data1 = Data1
{ id :: UUID
, field2 :: String
, field3 :: Int
}
instance HasId Data1 where
getId = id
If you want to add a new data type to the family you simply create a new instance of the HasId class.
You don't need no extensions, nothing fancy, no libraries. Sure you can probably shorten the code or do something more fancy, but I'd prefer to use simple code that works and I understand versus code that I don't understand.

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.

Resources