Binding types in signatures - haskell

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) = ...

Related

How to get rid of these apparently superfluous `undefined`s?

I'm using GHC 9.2.2 and playing with OverloadedRecordDot and generic-lens. As an experiment, I want to use the overloaded dot as a "frontend" to the generic-lens functionality (including type-changing update).
I have these auxiliary definitions:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverloadedRecordDot #-}
import Control.Lens ( (&), (.~), Lens )
import Data.Generics.Product.Fields qualified as G
import GHC.Records (HasField (..))
import GHC.TypeLits (Symbol)
import GHC.Generics (Generic)
-- Basically a 'Control.Lens.Reified.ReifiedLens'.
newtype Lensy s t a b = Lensy (Lens s t a b)
pry :: Lensy s t a b -> Lens s t a b
pry (Lensy l) = l
-- Just a dummy starting point for applying the overloaded dot.
data The s t = The
the :: s -> t -> The s t -- the parameters are just to guide type inference
the s t = The
-- This GHC.Records.HasField instance produces lenses, not values.
-- It piggybacks on Data.Generics.Product.Fields.HasField.
instance G.HasField (field :: Symbol) s t a b
=> HasField field (The s t) (Lensy s t a b) where
getField _ = Lensy (G.field #field)
And this example datatype taken from Data.Generics.Product.Fields:
data Human a
= Human
{ name :: String
, address :: String
, other :: a
}
| HumanNoAddress
{ name :: String
, other :: a
}
deriving (Generic, Show)
human :: Human Bool
human = Human { name = "Tunyasz", address = "London", other = False }
Putting my helpers to work, this compiles (don't mind the awful verbosity):
human' :: Human Int
human' = human & pry (the human human').other .~ (42 :: Int)
Passing undefineds as arguments to the the also compiles:
human' :: Human Int
human' = human & pry (the undefined undefined).other .~ (42 :: Int)
Ok, they seem to be unnecessary. Let's get rid of those parameters to the, then:
-- Just a dummy starting point for applying the overloaded dot.
data The s t = The
the :: The s t
the = The
human' :: Human Int
human' = human & pry the.other .~ (42 :: Int)
Alas, this doesn't compile:
* Ambiguous type variables `s0', `t0',
`a0' arising from selecting the field `other'
prevents the constraint `(HasField
"other"
(The s0 t0)
(Lensy (Human Bool) (Human Int) a0 Int))' from being solved.
How to make the parameterless version of the compile?
Unwitting kind polymorphism strikes again.
ghci> :t the
the :: forall {k1} {k2} (s :: k1) (t :: k2). The s t
It was sufficient to add a kind signature to The:
{-# LANGUAGE KindSignatures #-}
import Data.Kind ( Type )
type The :: Type -> Type -> Type
data The s t = The
And the signature of the becomes:
ghci> :t the
the :: forall s t. The s t

How can I derive typeclass instances from constraint families that are in scope?

edit: I have followed up with a more specific question. Thank you answerers here, and I think the followup question does a better job of explaining some confusion I introduced here.
TL;DR I'm struggling to get proofs of constraints into expressions, while using GADTs with existential constraints on the constructors. (that's a serious mouthful, sorry!)
I've distilled a problem down to the following. I have a simple GADT that represents points called X and function applications called F. The points X are constrained to be Objects.
data GADT ix a where
X :: Object ix a => a -> GADT ix a
F :: (a -> b) -> GADT ix a -> GADT ix b
Constrained refers to containers whose objects are constrained by something and Object is that something. (edit: my real problem involves Category and Cartesian classes from constrained-categories)
-- | I can constrain the values within containers of kind `* -> *`
class Constrained (ix :: * -> *) where
type Object ix a :: Constraint
-- | Here's a trivial constraint. A more interesting one might include `Typeable a`, for ex
instance Constrained (GADT ix) where
type Object (GADT ix) a = (Constrained ix, Object ix a)
I would like to write an expression:
-- error: Could not deduce: Object ix Int arising from a use of ‘X’
ex0 :: GADT ix String
ex0 = F show (X (3 :: Int))
And while the obvious solution works, it quickly becomes verbose when building larger expressions:
-- Typechecks, but eventually verbose
ex1 :: Object ix Int => GADT ix String
ex1 = F show (X (3 :: Int))
I think the correct solution should look something like this:
-- error: Could not deduce: Object ix Int arising from a use of ‘X’
ex2 :: Constrained ix => GADT ix String
ex2 = F show (X (3 :: Int))
But I still can't get that proof of Object ix Int.
I'm sure it's simpler than I'm thinking. I have tried adding constraints to the Object constraint family in the GADT class instance. I have tried offering constraints in the expression's signature. I have tried QuantifiedConstraints, although, I'm not sure I fully grasp it yet. Please help me wise ones!
Runnable:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE InstanceSigs #-}
module Test where
import Data.Kind
import Data.Functor.Identity
import Data.Functor.Const
-- | I can constrain the values within containers of kind `* -> *`
class Constrained (ix :: * -> *) where
type Object ix a :: Constraint
-- | Here's a trivial constraint. A more interesting one might include `Typeable a`, for instance
instance Constrained (GADT ix) where
type Object (GADT ix) a = (Constrained ix, Object ix a)
-- | A demo GADT that has function application ('F'), and points ('X'). The
-- points are constrained.
data GADT ix a where
X :: Object ix a => a -> GADT ix a
F :: (a -> b) -> GADT ix a -> GADT ix b
-- -- Broken
-- -- error: Could not deduce: Object ix Int arising from a use of ‘X’
-- ex0 :: GADT ix String
-- ex0 = F show (X (3 :: Int))
-- Typechecks
-- but for larger programs becomes verbose, requiring many explicit constraints
ex1 :: Object ix Int => GADT ix String
ex1 = F show (X (3 :: Int))
-- -- What I want, but, it's broken
-- ex2 :: Constrained ix => GADT ix String
-- ex2 = F show (X (3 :: Int))
Without more context it's hard to say what's the best solution, but here are a couple of possibilities:
Avoid constraining at all
As it stands, your GADT doesn't seem to have much reason for restricting X to Object. Maybe this is just not needed?
data GADT ix a where
X :: a -> GADT ix a
F :: (a -> b) -> GADT ix a -> GADT ix b
Instead, the constraint could come from the outside when it's needed.
Bite the bullet of constraint lists, but make them nicer
If you have many different types in your expression that all need to fulfill the same constraint, you can use a helper like All
ex2' :: All (Object ix) '[Int] => GADT ix String
ex2' = F show (X (3 :: Int))
where there can be more types in the list in addition to Int; and/or you can make synonym constraints such as
type StdObjs ix = (Object ix Int, Object x Bool, ...)
ex2'' :: StdObjs ix => GADT ix String
ex2'' = F show (X (3 :: Int))
Propagate the constraints backwards through the data structure itself
If you do need the constraint on the X values, it may nevertheless be possible to express this in another way in the GADT. For example, if the function is not a general function but something that is already constrained to only accept Objects, you could have it like this:
data YourFunc ix a b where
YourFunc :: Object ix a => (a->b) -> YourFunc ix a b
show' :: Object ix Int => YourFunc ix Int String
show' = YourFunc show
This doesn't directly help with the problem you were asking about, but maybe the function is shared or something. You could even have something like
class Object ix a => InferrenceChain ix a where
type PreElem ix a :: Type
propInferrence :: (InferrenceChain ix (PreElem a) => r) -> r
and then
data YourFunc ix a b where
YourFunc :: InferrenceChain ix a
=> (PreElem a -> a) -> YourFunc (PreElem a) a
Then in the end you could proof the X constraint from just putting in Object ix String on the outside and recursing over propInferrence. But this would probably get quite fiddly.
I think the correct solution should look something like this:
-- error: Could not deduce: Object ix Int >arising from a use of ‘X’
ex2 :: Constrained ix => GADT ix String
ex2 = F show (X 3)
Unfortunately, this solution doesn't make any sense. The compiler is justified in pointing out that it doesn't know that Object ix Int is satisfied at this point, since all it knows is that Constrained ix may impose some constraint through Object ix Int.
A solution through quantification
So perhaps what you want is a constraint which says: "at this point, all Object ix a constraints I use are satisfied" - which we can try and do through quantification:
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ConstraintKinds #-}
type Satisfied ix = forall a. Object ix a
ex2 :: Satisfied ix => GADT ix String
ex2 = F show (X 3)
Unfortunately, that gives us a GHC error:
• Quantified predicate must have a class or type variable head:
forall a. Object ix a
• In the quantified constraint ‘forall a. Object ix a’
In the type synonym declaration for ‘Satisfied’
Since Object is a type family and not a class or type variable.
Re-architecture
But... why is Object a type family? In fact, why does Constrained exist at all as a lawless class with no methods? If we want to exert constraints on combinations of containers and types, Haskell already gives us the means to do that - just use instance constraints!
{-# LANGUAGE MultiParamTypeClasses #-}
class Object ix a
type Constrained ix = forall a. Object ix a
Because if we have
instance (...<some stuff>...) => Constrained Foo where
type Object ix a = (...<some def>...)
we could translate that to
instance (...<some stuff>..., ...<some def>...)
=> Object ix a
Which makes this example compile.
ex2 :: Constrained ix => GADT ix String
ex2 :: F show (X 3)

What is the correct signature for this function?

This code fails to compile with this error
src/JsonParser.hs:33:37-62: error:
* Couldn't match type `b1' with `b'
`b1' is a rigid type variable bound by
the type signature for:
resultantRunParse :: forall b1. String -> Maybe (String, b1)
at src/JsonParser.hs:29:5-52
`b' is a rigid type variable bound by
the type signature for:
fmap :: forall a b. (a -> b) -> Parser a -> Parser b
at src/JsonParser.hs:27:11-42
Expected type: Maybe (String, b1)
Actual type: Maybe (String, b)
The code:
import Prelude
newtype Parser a = Parser
{ runParser :: String -> Maybe (String, a)
}
instance Functor Parser where
fmap :: (a -> b) -> Parser a -> Parser b
fmap f (Parser p) = Parser resultantRunParse where
-- THIS FUNCTION TYPE DECLARATION IS THE PROBLEM
-- IF I REMOVE THE TYPE DECLARATION, IT WORKS
resultantRunParse :: String -> Maybe (String, b)
resultantRunParse input =
case p input of
Nothing -> Nothing
Just (remaining, parsed) -> Just (remaining, f parsed)
I tried the signature resultantRunParse :: forall b1. String -> Maybe (String, b1) suggested in the error message and that also didnt work.
Also, making the resultantRunParse = undefined and keeping the type signature also worked. Very strange!
What is the correct signature for this function?
The type signature must contain b, but it must be the same one as the b used in the enclosing function. This is impossible without scoped type variables:
https://wiki.haskell.org/Scoped_type_variables
To us this, add a comment to the top of your file:
{-# LANGUAGE ScopedTypeVariables #-}
Then, use an explicit forall b. in the enclosing function’s type signature.
Without scoped type variables, there is no way to write b in the type signature and make it the same b as the one used in the enclosing function.
(My personal recommendation is to just not use a type signature here. It is not necessary.)
First get comfortable writing the instance by hand, then you can derive it. This type looks a lot like StateT, the state monad transformer where the order of the tuple is swapped.
type StateT :: Type -> MonadTransformer
newtype StateT s m a = StateT (s -> m (a, s))
Your Functor Parser instance can be derived via it if you are willing to swap the order
{-# Language DerivingVia #-}
{-# Language StandaloneKindSignatures #-}
import Control.Monad.State
import Data.Kind
type Parser :: Type -> Type
newtype Parser a = Parser
{ runParser :: String -> Maybe (a, String)
}
deriving Functor
via StateT String Maybe
You can derive more instances in this manner.
import Control.Applicative
import Control.Monad.Catch
import Control.Monad.Except
import Control.Monad.State
import Data.Kind
import Data.Monoid
newtype Parser a = Parser ..
deriving
( Functor, Applicative, Alternative
, Monad, MonadPlus, MonadFix, MonadThrow
, MonadFail, MonadError (), MonadState String )
via StateT String Maybe
-- pointwise lifting
-- (<>) = liftA2 (<>)
-- mempty = pure mempty
-- deriving (Semigroup, Monoid, Num, Bounded)
-- via Ap Parser a
-- or Alternative
-- (<>) = (<|>)
-- mempty = empty
deriving (Semigroup, Monoid)
via Ap Parser a
See the output of :instances command
:instances StateT String Maybe
:instances Ap Parser _
:instances Alt Parser _
The last two require partial type signatures :set -XPartialTypeSignatures -Wno-partial-type-signatures.

what is the type of: matches m s = m == fromSing s?

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.

Typeable instance for Constraint tupling

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

Resources