deriving clause with arbitrary "Constraint aliases"? - haskell

For example, this declaration with deriving:
{-# LANGUAGE DeriveDataTypeable, ConstraintKinds #-}
import Data.Data (Data)
import Data.Typeable (Typeable)
type Constraints a = (Show a, Eq a, Ord a, Data a, Typeable a)
data A = A deriving (Constraints)
errors with:
Illegal deriving item ‘Constraints’
Which makes sense given http://downloads.haskell.org/~ghc/7.8.3/docs/html/users_guide/deriving.html
I write deriving (Show, Eq, Ord, Data, Typeable) for most of my types. It might be nice to export standard "constraint aliases", i.e. any type of kind * -> Constraint. Given, of course, that the constraints in the constraint tuple are all the right arity, have an empty "minimal complete definition", etc.
Is there any proposal for this? How hard would it be? Are there alternatives?

There is no proposal for this. It wouldn't be too hard, but I suspect it wouldn't get a lot of traction. Not only could you use template haskell to generate standalone deriving declarations as a comment suggests, but you could macro-expand to your desired clause using CPP if you really want.

Related

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.

Is there a way to shorten this deriving clause?

Is there a way to write the following:
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveAnyClass #-}
data X = A | B | C
deriving (Eq, Ord, Show, Read, Data, SymWord, HasKind, SMTValue)
So that the deriving clause can be shortened somehow, to something like the following:
data X = A | B | C deriving MyOwnClass
I'd like to avoid TH if at all possible, and I'm happy to create a new class that has all those derived classes as its super-class as necessary (as in MyOwnClass above), but that doesn't really work with the deriving mechanism. With constraint kinds extension, I found that you can write this:
type MyOwnClass a = (Eq a, Ord a, Show a, Read a, Data a, SymWord a, HasKind a, SMTValue a)
Unfortunately, I cannot put that in the deriving clause. Is there some magic to make this happen?
EDIT From the comments, it appears TH might be the only viable choice here. (The CPP macro is really not OK!) If that's the case, the sketch of a TH solution will be nice to see.
There's bad and easy way to do it and good but hard way. As Silvio Mayolo said you can use TemplateHaskell to write such function. This way is hard and rather complex way. The easier way is to use C-preprocessor like this:
{-# LANGUAGE CPP #-}
#define MY_OWN_CLASS (Eq, Ord, Show, Read, Data, SymWord, HasKind, SMTValue)
data X = A | B | C
deriving MY_OWN_CLASS
UPDATE (17.07.2016): ideas & sketch of TH solution
Before introducing sketch of solution I will illustrate why this is harder to do with TH. deriving-clause is not some independent clause, it's a part of data declaration so you can't encode only part inside deriving unfortunately. The general approach of writing any TH code is to use runQ command on brackets to see what you should write in the end. Like this:
ghci> :set -XTemplateHaskell
ghci> :set -XQuasiQuotes
ghci> import Language.Haskell.TH
ghci> runQ [d|data A = B deriving (Eq, Show)|]
[ DataD
[]
A_0
[]
Nothing
[ NormalC B_1 [] ]
[ ConT GHC.Classes.Eq , ConT GHC.Show.Show ]
]
Now you see that type classes for deriving are specified as last argument of DataD — data declaration — constructor. The workaround for your problem is to use -XStadandaloneDeriving extension. It's like deriving but much powerful though also much verbose. Again, to see, what exactly you want to generate, just use runQ:
ghci> data D = T
ghci> :set -XStandaloneDeriving
ghci> runQ [d| deriving instance Show D |]
[ StandaloneDerivD [] (AppT (ConT GHC.Show.Show) (ConT Ghci5.D)) ]
You can use StandaloneDerivD and other constructors directly or just use [d|...|]-brackets though they have more magic but they give you list of Dec (declarations). If you want to generate several declarations then you should write you function like this:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE StandaloneDeriving #-}
module Deriving where
import Language.Haskell.TH
boilerplateAnnigilator :: Name -> Q [Dec]
boilerplateAnnigilator typeName = do
let typeCon = conT typeName
[d|deriving instance Show $(typeCon)
deriving instance Eq $(typeCon)
deriving instance Ord $(typeCon)
|]
Brief tutorial can be found here.
And then you can use it in another file (this is TH limitation called staged restriction: you should define macro in one file but you can't use it in the same file) like this:
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
import Deriving
data X = A | B | C
boilerplateAnnigilator ''X
You should put other type classes you want inside boilerplateAnnigilator function. But this approach only works for non-parametrized class. If you have data MyData a = ... then standalone deriving should look like:
deriving instance Eq a => MyData a
And if you want your TH macro work for parametrized classes as well, then you basically should implement whole logic of GHC compiler by deducing whether type have type variables or not and generate instances depending on that. But this is much harder. I think that the best solution is to just make ticket in GHC compiler and let authors implement such feature called deriving aliases :)

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.

Creating custom data types with constraints

I'm trying to create a custom data type. As an example
data Time = Second Int deriving (Show)
However, this is too limiting (we could say later need milliseconds). I would like to instead define something like this:
data Time = Second Num deriving (Show)
This doesn't compile because Num has kind * -> ghc-prim-0.4.0.0:GHC.Prim.Constraint
How do I setup Time such that Second may contain any Num?
One of the best examples of why this might not be so desirable is found here at the Wikibooks section on Classes and Types. They say:
Type constraints in data declarations are less useful than it might seem at first. Consider:
data (Num a) => Foo a = F1 a | F2 a String
Here, Foo is a type with two constructors, both taking an argument of a type a which must be in Num. However, the (Num a) => constraint is only effective for the F1 and F2 constructors, and not for other functions involving Foo. Therefore, in the following example...
fooSquared :: (Num a) => Foo a -> Foo a
fooSquared (F1 x) = F1 (x * x)
fooSquared (F2 x s) = F2 (x * x) s
... even though the constructors ensure a will be some type in Num we can't avoid duplicating the constraint in the signature of fooSquared
This suggests that a reasonable option for you is to just create Time with a generic parameter, and then later ensure that the module functions that operate on Time data always have the necessary constraint for Num.
It won't be so much of a worry that someone goes off and foolishly makes Time String or something -- if they do, then none of the provided module functions are going to be helpful for them, so it doesn't matter so much.
There are also options to look up with GADTs, the {-# LANGUAGE GeneralizedNewtypeDeriving #-} pragma, and the {-# LANGUAGE DatatypeContexts #-} pragma. But usually these start to rope in unnecessary degrees of extra complexity, especially if you're a Haskell novice like me.
There is a deprecated feature called Datatype Contexts that allows you to do that:
{-# LANGUAGE DatatypeContexts #-}
data Num a => Time a = Second a deriving (Show)
t = Second (5 :: Int)
main = print t
This executes on GHC 7.8.3 (sorry, don't have 7.10 to check), but warns you about the deprecation:
t.hs:1:14: Warning:
-XDatatypeContexts is deprecated: It was widely considered a
misfeature, and has been removed from the Haskell language.
Second 5
A non-deprecated way to do it is to use Generalized Algebraic Datatypes (GADTs) (and you'll need standalone deriving as well):
{-# LANGUAGE GADTs, StandaloneDeriving #-}
data Time a where
Second :: Num a => a -> Time a
deriving instance Show a => Show (Time a)
t = Second (5 :: Int)
main = print t
If you try to create a variable with something non-Num, you'll get a compilation error:
t = Second "a"
t.hs:12:5:
No instance for (Num [Char]) arising from a use of ‘Second’
In the expression: Second "a"
In an equation for ‘t’: t = Second "a"

Stackoverflow exception when comparing two dynamic types

I have defined a data type Loc which can accept Dynamics in the constructor. Moreover I need to compare Loc datatypes using == operator. So I came up with something like this:
data Loc = UnknownLoc | DynamicLoc Dynamic deriving (Eq,Show)
instance Eq Dynamic
data DynamicLocation = Loc_1 | Loc_2 deriving (Eq,Show)
instance Typeable DynamicLocation
But when attempting to run the following line I get stackoverflow exception.
DynamicLoc (toDyn Loc_1) == DynamicLoc (toDyn Loc_1)
any idea?
Please, read your compiler warnings :) You haven't provided a definition for the Typeable typeclass's typeOf method for DynamicLocation, and toDyn calls typeOf. So this definitely shouldn't work -- if you try just toDyn Loc_1, you'll get an exception.
But why an infinite loop? It's because you also haven't defined (==) for Dynamic, and (==) and (/=) are defined in terms of each other in GHC.Classes. GHC doesn't attempt to resolve such infinite recursion in default method declarations, so you unfortunately don't get a warning.
What to do? I suggest letting GHC derive the Typeable instance for you:
{-# LANGUAGE StandaloneDeriving, DeriveDataTypeable #-}
data DynamicLocation = Loc_1 | Loc_2 deriving (Eq,Show)
deriving instance Typeable DynamicLocation
or, more sensible:
{-# LANGUAGE DeriveDataTypeable #-}
data DynamicLocation = Loc_1 | Loc_2 deriving (Eq,Show,Typeable)
However, as a commenter has already pointed out, it's not immediately clear how to define (==) for Dynamic, or if this is even possible.

Resources