I'm trying to derive a Typeable instance for tupled constraints. See the following code:
{-# LANGUAGE ConstraintKinds, GADTs #-}
{-# LANGUAGE DataKinds, PolyKinds, AutoDeriveTypeable #-}
{-# LANGUAGE StandaloneDeriving, DeriveDataTypeable #-}
import Data.Proxy
import Data.Typeable
data Foo (p :: (*, *))
data Dict ctx where
Dict :: ctx => Dict ctx
deriving (Typeable)
deriving instance Typeable '(,)
deriving instance Typeable Typeable
deriving instance Typeable Show
works :: IO ()
works = print (typeRep (Proxy :: Proxy (Foo '(Bool, Char))))
alsoWorks :: IO ()
alsoWorks = print (typeRep (Dict :: Dict (Show Bool)))
fails :: IO ()
fails = print (typeRep (Dict :: Dict (Show Bool, Typeable Bool)))
main :: IO ()
main = works >> alsoWorks >> fails
If you compile this with -fprint-explicit-kinds, the following error is given:
No instance for (Typeable
(Constraint -> Constraint -> Constraint) (,))
Is there a way to derive such an instance? Everything I try refuses to disambiguate from the ★ -> ★ -> ★ constructor.
GHC can not currently make a Typeable instance, or any other instance, for (,) :: Constraint -> Constraint -> Constraint. The type constructor (,) only has kind * -> * -> *. There is no type constructor for products of the kind Constraint -> Constraint -> Constraint. The constructor (,) is overloaded to construct both tuples and products of Constraints, but has no corresponding type constructor when used to make a product of Constraints.
If we did have a type constructor for products of Constraints we should be able to define an instance as follows. For this, we'll pretend (,) is also a type constructor with kind (,) :: Constraint -> Constraint -> Constraint. To define an instance for it, we'd use KindSignatures and import GHC.Exts.Constraint to be able to talk about the kind of constraints explicitly
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE KindSignatures #-}
import GHC.Exts (Constraint)
import Data.Typeable
deriving instance Typeable ((,) :: Constraint -> Constraint -> Constraint)
If we do this now, it results in the following error, due to the kind of the (,) type constructor.
The signature specified kind `Constraint
-> Constraint -> Constraint',
but `(,)' has kind `* -> * -> *'
In the stand-alone deriving instance for
`Typeable ((,) :: Constraint -> Constraint -> Constraint)'
The constraints package also works with products of constraints, and includes the following note.
due to the hack for the kind of (,) in the current version of GHC we can't actually make instances for (,) :: Constraint -> Constraint -> Constraint
I presume the hack Edward Kmett is referring to is the overloading of the (,) constructor for Constraints without a corresponding type constructor.
It seems that it is not currently possible. There's a revealing comment in the latest version of constraint:
due to the hack for the kind of (,) in the current version of GHC we can't actually make instances for (,) :: Constraint -> Constraint -> Constraint
Related
What is the most direct way to bind a type variable when pattern matching in a Gadt ?
#!/usr/bin/env stack
-- stack script --resolver lts-13.1
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GADTs, ScopedTypeVariables #-}
{-# LANGUAGE DataKinds #-}
module Main where
import Data.Proxy
import GHC.TypeLits
main :: IO ()
main = undefined
data Kind where
Index :: Symbol -> Kind
data Gadt (f::Kind) where
Lit :: KnownSymbol s => Gadt ('Index s)
Binding s directly would fail
format :: Gadt f -> String
format (Lit :: Gadt ('Index s)) = undefined -- KO
with error
• Couldn't match type ‘f’ with ‘'Index s’
‘f’ is a rigid type variable bound by
the type signature for:
format :: forall (f :: Kind). Gadt f -> String
Expected type: Gadt f
Actual type: Gadt ('Index s)
A type function can extract the type, but aren't there more direct way to do this ?
format (Lit :: Gadt i) = symbolVal (Proxy :: TLabel i)
type family TLabel (a::Kind)
type instance TLabel ('Index s ) = Proxy s
The only way I see is to add a Proxy to bind the type variable with ScopedTypeVariables.
data Gadt a where
Lit :: KnownNat s => Proxy s -> Gadt ('Index s)
format :: Gadt a -> String
format (Lit (Proxy :: Proxy s)) = undefined
If you are worried about the extra allocation, the field can be unpacked. (EDIT: removed previous mention of Proxy# because that doesn't seem necessary).
import Data.Proxy
-- This should be as efficient as the original Gadt with a nullary Lit
data Gadt a where
Lit :: {-# UNPACK #-} !(Proxy r) -> Gadt ('Index r)
format :: Gadt a -> String
format (Lit (_ :: Proxy r)) = undefined
On the longer term, the following GHC proposal will address this issue: Type Applications in Patterns.
-- The original type
data Gadt a where
Lit :: forall s. Gadt ('Index s)
format :: Gadt a -> String
format (Lit #s) = ...
I want to convert any type to type-level string using some type families.
Of course, I can write something like this:
type family ShowType (t :: Type) :: Symbol where
ShowType Int = "Int"
ShowType String = "String"
...
But I wonder is there some existing mechanism for this? I can do this in runtime using Typeable techniques. But how can I automatically convert any type to Symbol?
There isn't a general solution for all types. But maybe you'll find the following interesting.
You can get the name of a type constructor with an instance of Generic, although that excludes primitive types like Int and Float. Two different ways are given below:
{-# LANGUAGE AllowAmbiguousTypes#-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeApplications #-}
import Data.Proxy
import GHC.Generics
import GHC.TypeLits
-- Solution 1: Defines a type family that extracts the type
-- constructor name as a Symbol from a generic Rep.
-- Then it can be reified via GHC.TypeLits.symbolVal.
type family TyConName (f :: * -> *) :: Symbol where
TyConName (M1 D ('MetaData name _mdl _pkg _nt) _f) = name
tyConName
:: forall a s
. (Generic a, s ~ TyConName (Rep a), KnownSymbol s) => String
tyConName = symbolVal (Proxy #s)
-- Solution 2: Uses the GHC.Generics.datatypeName helper
-- (value-level string only).
tyConName'
:: forall a d f p
. (Generic a, Rep a ~ D1 d f, Datatype d) => String
tyConName' = datatypeName (from #a undefined)
main = do
print (tyConName #(Maybe Int)) -- "Maybe"
print (tyConName' #(Maybe Int)) -- "Maybe"
We can get a value level proof that [Int] has a Show instance using a Dict
{-# LANGUAGE ConstraintKinds, GADTs #-}
data Dict (p :: Constraint) where
Dict :: p => Dict p
and
proof = Dict :: Dict (Show [Int])
Is there a way to get a value level derivation, that is, the entire proof tree ?
derivation = Apply#Int(Lam a.(Show a) :=> Show [a])) (Apply(() :=> Show Int)())
There isn't a way to get the derivation of an arbitrary constraint as a Haskell value.
The closest thing I can think of, if you want to check whether the derivation is what you think it is, is to look at the desugarer output.
ghc -ddump-ds -ddump-to-file A.hs
The relevant part looks like this:
-- RHS size: {terms: 2, types: 1, coercions: 0, joins: 0/0}
irred :: Show [Int]
[LclId]
irred = GHC.Show.$fShow[] # Int GHC.Show.$fShowInt
-- RHS size: {terms: 2, types: 3, coercions: 0, joins: 0/0}
proof :: Dict (Show [Int])
[LclIdX]
proof = Cns.Dict # (Show [Int]) irred
Another one is to write custom typeclasses instrumented to reflect the derivation, either in types or in values, but of course this doesn't apply to preexisting type classes.
{-# LANGUAGE AllowAmbiguousTypes, ConstraintKinds, GADTs, DataKinds,
FlexibleInstances, KindSignatures, MultiParamTypeClasses, RankNTypes,
ScopedTypeVariables, TypeApplications, TypeOperators,
UndecidableInstances #-}
import Data.Typeable
import Data.Kind
data (c :: [Type]) :=> (d :: Type -> Constraint)
class MyShow a d where
myshow :: a -> String
instance (d ~ ('[] :=> MyShow Int)) => MyShow Int d where
instance (MyShow a da, d ~ ('[da] :=> MyShow [a])) => MyShow [a] d where
myshowInstance :: forall a d. (Typeable d, MyShow a d) => TypeRep
myshowInstance = typeRep #_ #d Proxy
main = print (myshowInstance #[Int])
The output could be made to look better, e.g., via a singleton with a proper rendering method instead of TypeRep, but I hope you get the main idea.
:=> (': * (:=> ('[] *) (MyShow Int)) ('[] *)) (MyShow [Int])
This may be what you're after, or at least enough to give you a general idea. I can't think of a way to have GHC provide this automatically, but you can manually construct the chain of entailments that proves the constraint using the constraints package.
For whatever reason, there is no instance () :=> Show Int, so I've used Char instead. This is likely an oversight, I've opened a pull request to add the missing instances.
{-# LANGUAGE ConstraintKinds #-}
import Data.Constraints
derivation :: () :- Show [Char]
derivation = trans showList showChar
where showList :: Show a :- Show [a]
showList = ins
showChar :: () :- Show Char
showChar = ins
Unfortunately printing this value doesn't show the inner derivations, just "Sub Dict".
A fun exercise could be to try to write derivation with explicit TypeApplications using Data.Constraint.Forall. You'll need a couple extra steps to prove Show a :- Forall Show and ForallF Show [] :- Show [a].
I'm new to Haskell, so I'm probably missing something obvious, but what seems to be the problem here?
The singletons library provides a Sing instance for the kind * in import Data.Singletons.TypeRepStar.
The Sing data family is defined as follows..
data family Sing (a :: k)
and the * instance is defined as..
data instance Sing (a :: *) where
STypeRep :: Typeable a => Sing a
I'm trying to reproduce a minimal version of this using the following ...
{-# LANGUAGE GADTs
, TypeFamilies
, PolyKinds
#-}
module Main where
import Data.Typeable
data family Bloop (a :: k)
data instance Bloop (a :: *) where
Blop :: Typeable a => Bloop a
main :: IO ()
main = putStrLn "Hello, Haskell!"
But I'm getting the following error...
Main.hs:12:3: error:
• Data constructor ‘Blop’ returns type ‘Bloop a’
instead of an instance of its parent type ‘Bloop a’
• In the definition of data constructor ‘Blop’
In the data instance declaration for ‘Bloop’
|
12 | Blop :: Typeable a => Bloop a
| ^
The compiler insists that the a in Bloop (a :: *) and the a in Typeable a => Bloop a are not the same a. It produces exactly the same error if you replace one of them with b:
data instance Bloop (b :: *) where
Blop :: Typeable a => Bloop a
* Data constructor `Blop' returns type `Bloop a'
instead of an instance of its parent type `Bloop b'
* In the definition of data constructor `Blop'
In the data instance declaration for `Bloop'
This can be made more visible with -fprint-explicit-kinds:
* Data constructor `Blop' returns type `Bloop k a'
instead of an instance of its parent type `Bloop * a'
* In the definition of data constructor `Blop'
In the data instance declaration for `Bloop'
Now we can clearly see right in the error message that one a has kind k and the other has kind *. From this, a solution is obvious - explicitly declare the kind of the second a :
data instance Bloop (a :: *) where
Blop :: Typeable (a :: *) => Bloop (a :: *) -- Works now
It appears that this happens because of the PolyKinds extension. Without it, the second a is assumed to have kind *, and thus the original definition works.
It appears as though the PolyKinds extension is causing the error. The singletons library splits the data family declaration and the data instance definitions into different files. The data family requires the PolyKinds extension to work, but if the instance will fail if the extension is on. It seems you must use the KindSignatures extension instead.
Def.hs
{-# LANGUAGE PolyKinds, TypeFamilies #-}
module Def (Bloop) where
data family Bloop (a :: k)
Main.hs
{-# LANGUAGE GADTs
, TypeFamilies
, KindSignatures
#-}
module Main where
import Def
import Data.Typeable
data instance Bloop (a :: *) where
Blop :: Typeable a => Bloop a
main :: IO ()
main = putStrLn "Hello, Haskell!"
Using the singletons library, this simple function compiles and works. But, ghci and ghc disagree about the type signature of it, and if either of their suggestions is pasted into the code, it will fail to compile.
What type signature will GHC accept? ghc-7.10.3, singletons-2.0.1
{-# LANGUAGE DataKinds, PolyKinds, TypeOperators, TypeFamilies, GADTs, UndecidableInstances, FlexibleContexts #-}
import Data.Proxy (KProxy(..))
import Data.Singletons
import Data.Singletons.Prelude
-- ghc rejects this type signature, but if I leave it off, ghci :t shows exactly this.
matches :: (Eq (DemoteRep 'KProxy), SingKind 'KProxy) => DemoteRep 'KProxy -> Sing a -> Bool
matches m s = m == fromSing s
t :: Sing True
t = sing
demo :: Bool
demo = matches True t
GHC's error with above type signature:
Couldn't match type ‘DemoteRep 'KProxy’ with ‘DemoteRep 'KProxy’
NB: ‘DemoteRep’ is a type function, and may not be injective
The kind variable ‘k2’ is ambiguous
Use -fprint-explicit-kinds to see the kind arguments
Expected type: DemoteRep 'KProxy -> Sing a -> Bool
Actual type: DemoteRep 'KProxy -> Sing a -> Bool
In the ambiguity check for the type signature for ‘matches’:
matches :: forall (k :: BOX)
(k1 :: BOX)
(k2 :: BOX)
(k3 :: BOX)
(a :: k3).
(Eq (DemoteRep 'KProxy), SingKind 'KProxy) =>
DemoteRep 'KProxy -> Sing a -> Bool
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature for ‘matches’:
matches :: (Eq (DemoteRep KProxy), SingKind KProxy) =>
DemoteRep KProxy -> Sing a -> Bool
ghc -Wall suggests a different type signature, but the BOX stuff won't be accepted either:
Top-level binding with no type signature:
matches :: forall (k :: BOX) (a :: k).
(Eq (DemoteRep 'KProxy), SingKind 'KProxy) =>
DemoteRep 'KProxy -> Sing a -> Bool
'KProxy at the type level is like Proxy at the value level: it has a phantom. Just as we write Proxy :: Proxy a with the phantom type a at the value level, we have to turn on kind signatures and write 'KProxy :: KProxy k with a phantom kind k at the type level. Hopefully that analogy makes a kind of sense. Here's what it looks like:
{-# LANGUAGE DataKinds, PolyKinds, TypeOperators, TypeFamilies, GADTs, UndecidableInstances, FlexibleContexts, KindSignatures #-}
import Data.Proxy (KProxy(..))
import Data.Singletons
import Data.Singletons.Prelude
matches ::
( Eq (DemoteRep ('KProxy :: KProxy k))
, SingKind ('KProxy :: KProxy k)
) => DemoteRep ('KProxy :: KProxy k) -> Sing (a :: k) -> Bool
matches m s = m == fromSing s
This type variable k will occur in both DemoteRep ... and Sing ..., which is what lets us type-check m == fromSing s.
GHCi, though sweet and usually smart, has no idea that the type signature needs "another level of indirection" and needs an introduced kind variable.
Aside
I would caution aginst the majority opinion here that -fprint-explicit-kinds is helpful:
λ> :t matches
matches
:: (Eq (DemoteRep * ('KProxy *)), SingKind * ('KProxy *)) =>
DemoteRep * ('KProxy *) -> Sing * a -> Bool
That, to me, doesn't really point a finger at what's happening here. I was only able to piece together everything by looking up the signatures for DemoteRep, 'KProxy, and Sing with the handy-dandy :info command.
The trouble is that you're using (essentially) a kind class, but you're not pinning down kinds properly. In particular, the three occurrences of 'KProxy could all refer to different kinds. A common approach would be to name the proxy using an equality constraint, and use that name repeatedly. This saves a bit of typing compared to giving every proxy a signature:
matches :: (kproxy ~ ('KProxy :: KProxy k),
Eq (DemoteRep kproxy),
SingKind kproxy)
=> DemoteRep kproxy
-> Sing (a :: k) -> Bool
This makes it clear that the proxies should all be the same, and in particular should have the same kind as the type passed to Sing.