Haskell: How to make a type an instance of two typeclasses? - haskell

Is it possible to make Level an instance of Eq and Ord?
instance Eq Ord Level where
compare First Second = LT
...
I've tried this
instance (Ord, Eq) => Level where ...
But I've got an error
‘compare’ is not a (visible) method of class ‘Level’
I know I can use deriving (Eq) on my data Level. But I cannot change my data.

Use two instances
instance Eq Level where
x == y = ...
instance Ord Level where
compare x y = ...
Alternatively, use the standalone deriving extension:
{-# LANGUAGE StandaloneDeriving #-}
... -- ^^^^^^^^^^^^^^^^^^ must be at the top of the file
deriving instance (Eq Level)
deriving instance (Ord Level)

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.

How to constrain type family to Show

I'm currently working on an interpreter, which should be able to handle multiple variations of a language.
Therefore I'm designing my AST with type families (a simple example is given below).
How do I tell GHC that my type families need to have Show (and Eq) instances?
I have tried to use StandaloneDeriving, but can't find out how to define the dependency/ constraint.
-- Types.hs
{-# LANGUAGE TypeFamilies #-}
module Types where
data Statement v = CommonStatement (CommonStatement v)
| VariantStatement (VariantStatement v)
deriving (Show)
data CommonStatement v = Skip deriving (Show)
data family VariantStatement v
-- Coroutine.hs
{-# LANGUAGE TypeFamilies #-}
module Coroutine (module Coroutine, module Types) where
import Types
newtype Coroutine = Coroutine [Statement Coroutine]
data instance VariantStatement Coroutine = SomeStatement deriving (Show)
When trying to build this (with stack and resolver lts-16.16), it fails since it can't deduce an instance of Show for (VariantStatement v):
• No instance for (Show (VariantStatement v))
arising from the first field of ‘VariantStatement’
(type ‘VariantStatement v’)
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
• When deriving the instance for (Show (Statement v))
|
7 | deriving (Show)
| ^^^^
This is basically just a matter of chasing down and squashing the errors:
{-# LANGUAGE TypeFamilies, StandaloneDeriving, UndecidableInstances #-}
main= print SomeStatement
data Statement v
= CommonStatement (CommonStatement v)
| VariantStatement (VariantStatement v)
-- StandaloneDeriving and UndecidableInstances
-- are required for this one.
deriving instance Show (VariantStatement v) => Show (Statement v)
data CommonStatement v = Skip deriving (Show)
data family VariantStatement v
newtype Coroutine = Coroutine [Statement Coroutine]
data instance VariantStatement Coroutine = SomeStatement deriving Show

Derived instance in Haskell

I would like to use derived instance like this:
data Test3D = forall a. (Show a, Eq a, Typeable a, Generic a)
=> Test3D { testDt :: String
, testPrm :: a
}
deriving (Show, Eq, Typeable, Generic)
instance Binary (Test3D)
$(deriveJSON defaultOptions ''Test3D)
But I received from GHC:
• Can't make a derived instance of ‘Show Test3D’:
Constructor ‘Test3D’ has existentials or constraints in its type
Possible fix: use a standalone deriving declaration instead
• In the data declaration for ‘Test3D’
This way is very convenient for my project. I can not find the solution.
Is any way of using derived instance for such data?
Is any way of using derived instance for such data?
Yes. Do what GHC suggested, make a standalone deriving clause:
{-# LANGUAGE StandaloneDeriving, ExistentialQuantification #-}
data Test3D = forall a. (Show a)
=> Test3D { testDt :: String
, testPrm :: a
}
deriving instance Show Test3D
What you cannot do is derive an Eq instance, because different values may actually contain different types and it's only possible to compare these with a dynamic-cast hack through Typeable.

What is the difference between `DeriveAnyClass` and an empty instance?

Using the cassava package, the following compiles:
{-# LANGUAGE DeriveGeneric #-}
import Data.Csv
import GHC.Generics
data Foo = Foo { foo :: Int } deriving (Generic)
instance ToNamedRecord Foo
However, the following does not:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
import Data.Csv
import GHC.Generics
data Foo = Foo { foo :: Int } deriving (Generic, ToNamedRecord)
The compiler reports:
test.hs:7:50:
No instance for (ToNamedRecord Int)
arising from the first field of ‘Foo’ (type ‘Int’)
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
When deriving the instance for (ToNamedRecord Foo)
This leaves me with two questions: Why isn't the second version identical to the first? And why is the compiler hoping to find an instance for ToNamedRecord Int?
NB: As pointed out by David in the comments, GHC has been updated since I wrote this. The code as written in the question compiles and works correctly. So just imagine everything below is written in the past tense.
The GHC docs say:
The instance context will be generated according to the same rules
used when deriving Eq (if the kind of the type is *), or the rules for
Functor (if the kind of the type is (* -> *)). For example
instance C a => C (a,b) where ...
data T a b = MkT a (a,b) deriving( C )
The deriving clause will
generate
instance C a => C (T a b) where {}
The constraints C a and C (a,b) are generated from the data constructor arguments, but the
latter simplifies to C a.
So, according to the Eq rules, your deriving clause generates...
instance ToNamedRecord Int => ToNamedRecord Foo where
... which is not the same as...
instance ToNamedRecord Foo where
... in that the former is only valid if there's an instance ToNamedRecord Int in scope (which is appears there isn't in your case).
But I find the spec to be somewhat ambiguous. Should the example really generate that code, or should it generate instance (C a, C (a, b)) => instance C (T a b) and let the solver discharge the second constraint? It appears, in your example, that it's generating such constraints even for fields with fully-concrete types.
I hesitate to call this a bug, because it's how Eq works, but given that DeriveAnyClass is intended to make it quicker to write empty instances it does seem unintuitive.

Equal class misunderstanding

I have my own data type to represent nodes and edges of a graph as follows:
data Node a = Node a deriving (Show, Eq)
data Label a = Label a deriving (Show)
data Cost = CostI Int | CostF Float deriving (Show)
data Edge label node = Edge (Label label, (Node node,Node node), Cost) deriving (Show)
Now, I create a function to check whether an edge contains 2 nodes or not as follows:
isEdge:: (Eq n) => (Edge l n) -> (Node n, Node n) -> Bool
isEdge (Edge (_, (n1,n2), _)) (n3, n4) = result
where result = (n1 == n3) && (n2 == n4)
The function works well, the problem here is if I remove (Eq n) from the function, it fails. So, why is that, even though in the declaration above I declared Node as deriving from Eq class?
data Node a = Node a deriving (Show, Eq)
The Eq instance GHC derives for Node a is something like this:
instance Eq a => Eq (Node a) where
(Node x) == (Node y) = x == y
(Node x) /= (Node y) = x /= y
You can view the generated code by compiling with -ddump-deriv. The Eq a constraint is needed for obvious reasons. So, GHC couldn't infer an instance of Eq for, say, Node (a -> b) since functions can't be compared.
However, the fact that GHC can't infer an instance of Eq for Node a for some a doesn't mean it will stop you from constructing a values of type Node a where a isn't an equality type.
If you wanted to stop people from constructing non-comparable Nodes, you could try putting a constraint like this:
data Eq a => Node a = Node a deriving (Eq, Show)
But now GHC tells us we need a compiler pragma:
Illegal datatype context (use -XDatatypeContexts): Eq a =>
OK, let's add it to the top of our file:
{-# LANGUAGE DatatypeContexts #-}
Now compile:
/tmp/foo.hs:1:41: Warning: -XDatatypeContexts is deprecated: It was widely
considered a misfeature, and has been removed from the Haskell language.
The problem is that now every function using Nodes will need an Eq class constraint, which is annoying (your functions still need the constraint!). (Also, if your user wants to create Nodes using a non-equality type but never tests them for equality, what's the problem?)
There's actually a way to get GHC to do what you want, however: Generalized Algebraic Data Types (GADTs):
{-# LANGUAGE GADTs, StandaloneDeriving #-}
data Node a where
Node :: Eq a => a -> Node a
This looks just like your original definition, except that it emphasizes the Node value constructor (the one formerly on the right hand side of the data declaration) is just a function, which you can add constraints to. Now GHC knows that only equality types can be put into Nodes, and unlike our earlier attempted solution, we can make new functions that don't need a constraint:
fromNode :: Node a -> a
fromNode (Node x) = x
We can still derive Eq and Show instances, but with a slightly different syntax:
deriving instance Eq (Node a)
deriving instance Show (Node a)
(Hence the StandaloneDeriving pragma above.)
For this to work, GHC also requires us to add a Show constraint to our GADT (if you look at the generated code again, you'll see the constraints are now gone):
data Node a where
Node :: (Eq a, Show a) => a -> Node a
And now we can take the Eq constraint off isEdge, since GHC can infer it!
(This is definitely overkill for such a simple situation -- again, if people want to construct nodes with functions inside them, why shouldn't they? However, GADTs are extremely useful in pretty similar situations when you want to enforce certain properties of your data types. See a cool example).
EDIT (from the future): you can also write
data Node a = (Eq a, Show a) => Node a
but you still need to enable GADT extensions and derive instances separately. See this thread.
When you add a deriving clause to a data declaration, the derived clause will include any necessary constraints for the type variable in scope at the declaration. In this case, deriving Eq will create essentially the following instance:
instance Eq a => Eq (Node a) where
(Node a) == (Node b) = a == b
(Node a) /= (Node b) = a /= b
Any derived Eq instance will depend upon the Eq instance of types that appear to the right of the data constructor.
This is because there's really no other way to derive an Eq instance automatically. Two values are equal if they have the same type and all their components are equal. So you need to be able to test the components for equality. In order to generically test a polymorphic component for equality, you need an Eq instance.
This is true not just for Eq, but for all the derived classes. For example this code
toStr :: Edge l n -> String
toStr = show
won't work without adding the constraint (Show l, Show n). Without that constraint, the function to show an Edge doesn't know what to call to show its internal Labels and Nodes.

Resources