Deriving extensions with multiparameter types - haskell

I have an Ast type constructor, parameterized by the identifier type.
Using the DeriveFunctor, DeriveFoldable and DeriveTraversable extensions
it is possible to automatically create the appropriate instances.
Now I find it useful to introduce more type parameters but unfortunately
the above method doesn't scale. Ideally I would like to be able to
wrap my Ast type in selection types which would allow me to fmap to
the appropriate type parameters. Is there some way to achieve a similar
effect without having to define the instances myself?
edit:
Here is a small example of what the original Ast looked like:
Ast id = Ast (FuncDef id)
deriving (Show, Functor, Foldable, Traversable)
FuncDef id = FuncDef id [Fparam id] (Block id)
deriving (Show, Functor, Foldable, Traversable)
Block id = Block [Stmt id]
deriving (Show, Functor, Foldable, Traversable)
..

After fiddling around all day I came to the following conclusions:
The Ast presented in the question turned out not to be very flexible.
In later stages I want to annotate different nodes in a way that can't
be expressed by just parameterizing the original Ast.
So I changed the Ast in order to act as a base for writing new types:
Ast funcdef = Ast funcdef
deriving (Show)
Header id fpartype = Header id (Maybe Type) [fpartype]
deriving (Show)
FuncDef header block = FuncDef header block
deriving (Show)
Block stmt = Block [stmt]
deriving (Show)
Stmt lvalue expr funccall =
StmtAssign lvalue expr |
StmtFuncCall funccall |
..
Expr expr intConst lvalue funccall =
ExprIntConst intConst |
ExprLvalue lvalue |
ExprFuncCall funccall |
expr :+ expr |
expr :- expr |
..
Now I can simply define a chain of newtypes for each compiler stage.
The Ast at the stage of the renamer may be parameterized around the identifier type:
newtype RAst id = RAst { ast :: Ast (RFuncDef id) }
newtype RHeader id = RHeader { header :: Header id (RFparType id) }
newtype RFuncDef id = RFuncDef {
funcDef :: FuncDef (RHeader id) (RBlock id)
}
..
newtype RExpr id = RExpr {
expr :: Expr (RExpr id) RIntConst (RLvalue id) (RFuncCall id)
}
During the typechecking stage the Ast may be parameterized by
the different internal types used in the nodes.
This parameterization allows for constructing Asts with Maybe wrapped
parameters in the middle of each stage.
If everything is ok we can use fmap to remove the Maybes and prepare the tree for the next stage. There are other ways Functor, Foldable and Traversable are useful so these are a must to have.
At this point I figured that what I want is most likely not possible
without metaprogramming so I searched for a template haskell solution.
Sure enough there is the genifunctors library which implements generic
fmap, foldMap and traverse functions. Using these it's a simple matter
of writing a few newtype wrappers to make different instances of the required typeclasses around the appropriate parameters:
fmapGAst = $(genFmap Ast)
foldMapGAst = $(genFoldMap Ast)
traverseGast = $(genTraverse Ast)
newtype OverT1 t2 t3 t1 = OverT1 {unwrapT1 :: Ast t1 t2 t3 }
newtype OverT2 t1 t3 t2 = OverT2 {unwrapT2 :: Ast t1 t2 t3 }
newtype OverT3 t1 t2 t3 = OverT3 {unwrapT3 :: Ast t1 t2 t3 }
instance Functor (OverT1 a b) where
fmap f w = OverT1 $ fmapGAst f id id $ unwrapT1 w
instance Functor (OverT2 a b) where
fmap f w = OverT2 $ fmapGAst id f id $ unwrapT2 w
instance Functor (OverT3 a b) where
fmap f w = OverT3 $ fmapGAst id id f $ unwrapT3 w
..

Related

Error when making an instance of Eq typeclass in Haskell

I am learning Haskell and writing a small decision diagrams library as a starting project. I have declared the data type as
data DD a = DDNode { var :: Int, vals :: [DD a]} | DDLeaf { val :: a} deriving (Show, Eq)
For testing for equality between 2 DDs, I am making an instance of Eq for DD. It basically does the same as testing for node and leaf equality in the case of tree structures.
instance (Eq a) => DD a where
(DDNode i vs) == (DDNode i' vs') = i == i' && vs == vs'
(DDLeaf v) == (DDLeaf v') = v == v'
_ == _ = False
When I load a file with the above code in GHCi, I get the following error,
Prelude> :load decisionDiagrams.hs
[1 of 1] Compiling DecisionDiagram ( decisionDiagrams.hs, interpreted )
decisionDiagrams.hs:9:19: error:
‘==’ is not a (visible) method of class ‘DD’
Failed, modules loaded: none.
What am I doing wrong?
You can not use Eq both in deriving and in an instance declaration, since then there are two implementations. The deriving (Eq) should thus be removed:
data DD a
= DDNode { var :: Int, vals :: [DD a]}
| DDLeaf { val :: a}
deriving (Show)
You need to specify that you are defining an instance of Eq, so the instance declaration should look like:
-- ↓ defining an instance for Eq
instance (Eq a) => Eq (DD a) where
-- …
The Eq instance you are implementing, is the one that Haskell can automatically derive. You thus do not need to construct such instance yourself: you can do this with a deriving clause. There is thus no reason to implement Eq manually.

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) ] ]

The limit set of types with new data like `Tree a`

Exploring and studing type system in Haskell I've found some problems.
1) Let's consider polymorphic type as Binary Tree:
data Tree a = Leaf a | Branch (Tree a) (Tree a) deriving Show
And, for example, I want to limit my considerations only with Tree Int, Tree Bool and Tree Char. Of course, I can make a such new type:
data TreeIWant = T1 (Tree Int) | T2 (Tree Bool) | T3 (Tree Char) deriving Show
But could it possible to make new restricted type (for homogeneous trees) in more elegant (and without new tags like T1,T2,T3) way (perhaps with some advanced type extensions)?
2) Second question is about trees with heterogeneous values. I can do them with usual Haskell, i.e. I can do the new helping type, contained tagged heterogeneous values:
data HeteroValues = H1 Int | H2 Bool | H3 Char deriving Show
and then make tree with values of this type:
type TreeH = Tree HeteroValues
But could it possible to make new type (for heterogeneous trees) in more elegant (and without new tags like H1,H2,H3) way (perhaps with some advanced type extensions)?
I know about heterogeneous list, perhaps it is the same question?
For question #2, it's easy to construct a "restricted" heterogeneous type without explicit tags using a GADT and a type class:
{-# LANGUAGE GADTs #-}
data Thing where
T :: THING a => a -> Thing
class THING a
Now, declare THING instances for the the things you want to allow:
instance THING Int
instance THING Bool
instance THING Char
and you can create Things and lists (or trees) of Things:
> t1 = T 'a' -- Char is okay
> t2 = T "hello" -- but String is not
... type error ...
> tl = [T (42 :: Int), T True, T 'x']
> tt = Branch (Leaf (T 'x')) (Leaf (T False))
>
In terms of the type names in your question, you have:
type HeteroValues = Thing
type TreeH = Tree Thing
You can use the same type class with a new GADT for question #1:
data ThingTree where
TT :: THING a => Tree a -> ThingTree
and you have:
type TreeIWant = ThingTree
and you can do:
> tt1 = TT $ Branch (Leaf 'x') (Leaf 'y')
> tt2 = TT $ Branch (Leaf 'x') (Leaf False)
... type error ...
>
That's all well and good, until you try to use any of the values you've constructed. For example, if you wanted to write a function to extract a Bool from a possibly boolish Thing:
maybeBool :: Thing -> Maybe Bool
maybeBool (T x) = ...
you'd find yourself stuck here. Without a "tag" of some kind, there's no way of determining if x is a Bool, Int, or Char.
Actually, though, you do have an implicit tag available, namely the THING type class dictionary for x. So, you can write:
maybeBool :: Thing -> Maybe Bool
maybeBool (T x) = maybeBool' x
and then implement maybeBool' in your type class:
class THING a where
maybeBool' :: a -> Maybe Bool
instance THING Int where
maybeBool' _ = Nothing
instance THING Bool where
maybeBool' = Just
instance THING Char where
maybeBool' _ = Nothing
and you're golden!
Of course, if you'd used explicit tags:
data Thing = T_Int Int | T_Bool Bool | T_Char Char
then you could skip the type class and write:
maybeBool :: Thing -> Maybe Bool
maybeBool (T_Bool x) = Just x
maybeBool _ = Nothing
In the end, it turns out that the best Haskell representation of an algebraic sum of three types is just an algebraic sum of three types:
data Thing = T_Int Int | T_Bool Bool | T_Char Char
Trying to avoid the need for explicit tags will probably lead to a lot of inelegant boilerplate elsewhere.
Update: As #DanielWagner pointed out in a comment, you can use Data.Typeable in place of this boilerplate (effectively, have GHC generate a lot of boilerplate for you), so you can write:
import Data.Typeable
data Thing where
T :: THING a => a -> Thing
class Typeable a => THING a
instance THING Int
instance THING Bool
instance THING Char
maybeBool :: Thing -> Maybe Bool
maybeBool = cast
This perhaps seems "elegant" at first, but if you try this approach in real code, I think you'll regret losing the ability to pattern match on Thing constructors at usage sites (and so having to substitute chains of casts and/or comparisons of TypeReps).

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.

Deriving functor instance, not on last type argument

Related to this question I asked earlier today.
I have an AST data type with a large number of cases, which is parameterized by an "annotation" type
data Expr ann def var = Plus a Int Int
| ...
| Times a Int Int
deriving (Data, Typeable, Functor)
I've got concrete instances for def and var, say Def and Var.
What I want is to automatically derive fmap which operates as a functor on the first argument. I want to derive a function that looks like this:
fmap :: (a -> b) -> (Expr a Def Var) -> (Expr b Def Var)
When I use normal fmap, I get a compiler message that indicates fmap is trying to apply its function to the last type argument, not the first.
Is there a way I can derive the function as described, without writing a bunch of boilerplate? I tried doing this:
newtype Expr' a = E (Expr a Def Var)
deriving (Data, Typeable, Functor)
But I get the following error:
Constructor `E' must use the type variable only as the last argument of a data type
I'm working with someone else's code base, so it would be ideal if I don't have to switch the order of the type arguments everywhere.
The short answer is, this isn't possible, because Functor requires that the changing type variable be in the last position. Only type constructors of kind * -> * can have Functor instances, and your Expr doesn't have that kind.
Do you really need a Functor instance? If you just want to avoid the boilerplate of writing an fmap-like function, something like SYB is a better solution (but really the boilerplate isn't that bad, and you'd only write it once).
If you need Functor for some other reason (perhaps you want to use this data structure in some function with a Functor constraint), you'll have to choose whether you want the instance or the type variables in the current order.
You can exploit a type synonym for minimizing the changes to the original code:
data Expr' def var ann = Plus a Int Int -- change this to Expr', correct order
| ...
| Something (Expr ann def var) -- leave this as it is, with the original order
deriving (Data, Typeable, Functor)
type Expr ann def var = Expr' def var ann
The rest of the code can continue using Expr, unchanged. The only exceptions are class instances such as Functor, which as you noticed require a certain order in the parameters. Hopefully Functor is the only such class you need.
The auto-derived fmap function has type
fmap :: (a -> b) -> Expr' def var a -> Expr' def var b
which can be written as
fmap :: (a -> b) -> Expr a def var -> Expr b def var

Resources