Is it possible to define a instance constrain for "not a monad", in order to define two non-overlapping instances, one for monadic values, other for non-monadic values?
A simplified example:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverlappingInstances #-}
class WhatIs a b | a -> b where
whatIs :: a -> b
instance (Show a) => WhatIs a String where
whatIs = show
instance (Monad m, Functor m, Show a) => WhatIs (m a) (m String) where
whatIs x = fmap show x
main :: IO ()
main = do
let x = 1 :: Int
putStrLn "----------------"
{-print $ whatIs (1::Int)-}
print $ whatIs (Just x)
putStrLn "--- End --------"
So, I use the FunctionalDependencies to avoid type annotations, but of course, the compiler complains with
Functional dependencies conflict between instance declarations:
instance [overlap ok] Show a => WhatIs a String
-- Defined at test.hs:10:10
instance [overlap ok] (Monad m, Functor m, Show a) =>
WhatIs (m a) (m String)
-- Defined at test.hs:13:10
Because a can assume the value m a, and thus a conflict arises.
However, if I could replace the first instance with something like:
instance (NotAMonad a, Show a) => WhatIs a String where
whatIs = show
This problem would not present itself.
So far I've found this very old email that seems to propose a somewhat related solution, but I'm not sure if there are new techniques to address this...
I also found the constraints package, which I'm sure has useful functions for this case, but it is sorely lacking in (simple) examples.
Any clues?
Edit: after user2407038 correct answer.
So, I tried user2407038 answer below, and indeed I managed to compile the provided example. The conclusion? I should not have simplified the example so much. After some thinkering with my actual example, I was able to reduce it to this:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module IfThenElseStackExchange where
class IfThenElse a b c d | a b c -> d where
ifThenElse :: a -> b -> c -> d
instance (Monad m) => IfThenElse (m Bool) (m b) (m b) (m b) where
ifThenElse m t e = do
b <- m
if b then t else e
instance (Monad m) => IfThenElse (m Bool) b b (m b) where
ifThenElse ma t e = do
a <- ma
return $ if a then t else e
But I still getting the dreaded Functional dependencies conflict between instance declarations error. Why? The part after the => (the instance head, as user2407038 promptly noted) is in fact quite different, thus it does not even qualify for OverlappingInstances, as the compiler can choose the most specific one.
Then what?
The error is, as always, hinted by the error message. The a b c d | a b c -> d part is not being respected by the code above. So I finally tried this instead:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module IfThenElseStackExchange where
class IfThenElse a b c d | a b c -> d where
ifThenElse :: a -> b -> c -> d
instance (Monad m, c ~ b) => IfThenElse (m Bool) (m b) (m b) (m c) where
ifThenElse m t e = do
b <- m
if b then t else e
instance (Monad m, c ~ b) => IfThenElse (m Bool) b b (m c) where
ifThenElse ma t e = do
a <- ma
return $ if a then t else e
Et voilà!
By using (m b) in the last parameter, I was trying to indicate that the final result has the same type as the second and third parameter. But the problem seems to be that the FunctionalDependencies extension does not make the same kind of instance choosing on types as OverlappingInstances, and thus considers b and (m b) "the same" for its purposes. Is this interpretation correct, or am I still missing something?
I can still 'tell' the compiler that c is of the same type as b using the constrain c ~ b, and thus reaching the intended result.
After reading some more material about this, I highly recomend reading this article by Oleg where he generalizes his former solutions that both I and user2407038 linked. I found it quite accessible.
If my interpretation of the FunctionalDependencies above is correct, and TypeFamilies being presented as a more flexible solution for the same problem domain, I wonder if could use them to solve this in another way. Oleg solution mentioned above sure uses them, of course.
You don't need a NotAMonad class, or rather, WhatIs is exactly this class already.
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances,
TypeFamilies, UndecidableInstances, IncoherentInstances #-}
class WhatIs a b | a -> b where
whatIs :: a -> b
instance (Show a, b ~ String) => WhatIs a b where
whatIs = show
instance (Monad m, Functor m, Show a) => WhatIs (m a) (m String) where
whatIs x = fmap show x
You don't strictly need IncoherentInstances but if you want things like whatIs (1 :: Num a => a) to work you need it.
This probably isn't the best way of doing what you want but your use case isn't clear.
Edit: more explanation:
First of all: these instances are not overlapping! I included the full list of language pragmas. The error you got said that "Functional dependencies conflict between instance declarations". Say you have the following:
class C a b | a -> b
Supposed you have two instances of C: C a b, C c d (here a is not a rigid type variable; it is just any haskell type). If a is an instantiation of c (or vice versa) then b must be an instantiation of d. This general rule may be somewhat abstract so lets look at your code:
instance (Show a) => WhatIs a String where
instance (Monad m, Functor m, Show a) => WhatIs (m a) (m String) where
Since a is any type, you are declaring that 'for any type a, whatIs a == String'.
The second instance declares that 'for any type (m a), whatIs (m a) == (m String)'. Obviously m a is an instantiation of a (any type is an instantiation of a free type variable) but String is never an instantiation of m String.
Why does any of this matter? When the compiler checks to see if fundeps conflict, it only looks at the instance head; that is, the portion to the right of =>. Therefore,
instance (Show a, b ~ String) => WhatIs a b where
is saying 'for any types a,b, whatIs a == b'. Obviously, since a and b are both free variables, they can be instantiated with any other type. So if a == (m a0) you can freely say that b == (m String). The fact that b must be a string becomes known if and only if the first instance is the one that is matched.
Since any types match a and b, WhatIs (IO ()) b matches the first instance. The second instance is used because the compiler will try to match the instances in order of specificity. You can find the 'rules' for determining specificity here.. The simple explanation is that WhatIs a b matches more things so it is more general, and will be used later. (In fact, the instance C a0 a1 a2 .. an where a* is a distinct type variable, is the most general instance and will always be tried last)
Edit: Here is the general solution to your problem. With this code, whatIs = f_map show.
Related
I'm writing a distributed programming DSL and I'd like to allow implementations to choose their serialization method (if any, as it might not even be needed for a simulated execution).
Trying to solve this by adding a type family led to the problem below for a standard function I have. I imagine that it would work if I could require, and have the type checker understand, that if two values are serializable their pairing is also serializable. However, adding that as a quantified constraint doesn't seem to work. Can this be solved or is there a better solution for the problem?
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
import Data.Kind
class (Monad (DistrM t)) => Distributed (t :: *) where
type Sendable t :: * -> Constraint
type DistrM t :: * -> *
-- ...
data FromSendable t a where
FromSendable :: (Sendable t b)
=> (b -> DistrM t a)
-> b
-> FromSendable t a
pairWith :: ( Sendable t a
, Distributed t
, forall a b. (Sendable t a, Sendable t b) => Sendable t (a,b)
)
=> a
-> FromSendable t b
-> FromSendable t (a,b)
pairWith a (FromSendable f b) =
FromSendable (\(a,b) -> (a,) <$> f b) (a,b)
-- >>> Could not deduce: Sendable t (a1, b1) ...
Edit 1
It type checks if I do
pairWith :: ( Sendable t a
, Distributed t
, st ~ Sendable t
, forall a b. (st a, st b) => st (a,b)
)
=> ...
It would get cumbersome to have to repeat these types of constraints, so I tried a type synonym but that doesn't work:
type Cs t = forall (st :: * -> Constraint).
(Sendable t ~ st, forall a b. (st a, st b) => st (a,b))
-- >>> Expected a constraint, but ‘st (a, b)’ has kind ‘*’
This looks weird. I only have a partial answer, but I'll post it anyway.
I simplified your code to
class C t where -- (*)
data T t where
T :: C t => (a -> t) -> a -> T t
foo ::
( C u
, forall a b . (C a , C b) => C (a, b) )
=> u -> T t -> T (u, t)
foo i (T f x) = T (\(a,b) -> (a, f b)) (i, x)
and, in this version, it compiles fine. However, if we replace
class C t where
with
type instance C :: * -> Constraint
then we get an error telling us that C (a, b) can not be deduced.
I can't completely understand what's going on here, but it looks like quantified constraints do not mix well with type families.
It looks like the above type family is treated like it were
type instance C (t :: *) :: Constraint
and in such case, I can't understand what's wrong. Since C now does not refer to a single type class, it is impossible to implement a quantified constraint like forall a b . (C a , C b) => C (a, b) by (say) passing a pointer to a specific instance, since the three C constraints could be anything at all, in an open world.
I still do not understand why type family C :: * -> Constraint is handled in the same way.
Perhaps GHC should reject quantified constraints involving type families ... -> Constraint in such way? I not sure.
I think you've pushed your code to the edges of GHC's type system here. You can fix the kind error on Cs by writing:
type Cs t = (forall (st :: * -> Constraint).
(Sendable t ~ st, forall a b. (st a, st b) => st (a,b))) :: Constraint
but then you run up against "GHC doesn't yet support impredicative polymorphism". Until GHC adds support for class families as per issue 14860, you're maybe out of luck with this approach.
However, you did ask about alternative approaches. Doesn't making Sendable t a a multiparameter type class accomplish basically the same thing?
Certainly, the following type-checks:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
import Data.Kind
class (Monad (DistrM t)) => Distributed (t :: *) where
type DistrM t :: * -> *
-- ...
class Sendable t a where
data FromSendable t a where
FromSendable :: (Sendable t b)
=> (b -> DistrM t a)
-> b
-> FromSendable t a
type Cs t = forall a b. (Sendable t a, Sendable t b) => Sendable t (a,b) :: Constraint
pairWith :: ( Sendable t a
, Distributed t
, Cs t
)
=> a
-> FromSendable t b
-> FromSendable t (a,b)
pairWith a (FromSendable f b) =
FromSendable (\(a,b) -> (a,) <$> f b) (a,b)
Wondering is following code ever possible in Haskell?
equal :: a -> b -> Bool
equal a b = a == b
No, the type of (==) requires its arguments to be of the same type
(==) :: Eq a => a -> a -> Bool
You ask if it's possible (to test equality between different types), yes it is possible but not something you'd normally do. You can use Typeable to witness that a and b are the same type but you need a Typeable constraint on both of them (and Eq constraint on either)
{-# Language ScopedTypeVariables #-}
{-# Language TypeApplications #-}
{-# Language ConstraintKinds #-}
{-# Language GADTs #-}
import Type.Reflection
type Equal a b = (Eq a, Typeable a, Typeable b)
equal :: forall a b. Equal a b => a -> b -> Bool
equal x y =
case eqTypeRep (typeRep #a) (typeRep #b) of
-- In this branch, `a' and `b' are the SAME type
-- so `(==)' works
Just HRefl -> x == y
-- Values of different types are never equal
Nothing -> False
so the following works
>> equal 10 'a'
False
>> equal 'X' 'a'
False
>> equal 'X' 'X'
True
Make sure you understand why we only constrain one of Eq a/Eq b and it doesn't matter which one.
Despite the fact Eq won't allow you to define that function due to =='s signature, you can define your own typeclass:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
class Eqq a b where
eqq :: a -> b -> Bool
-- Just an example of a possible instance for general types
instance Eqq a b where
eqq a b = True
And then,
equal :: (Eqq a b) => a -> b -> Bool
equal a b = a `eqq` b
I am using makeFields from lens to generate fields overloaded for various structures. I would like to use these fields at one with multiple structures while having to state which field I want to use only once. It would look like this:
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
import Control.Lens
data A = A
{ _aX :: String
, _aY :: String
}
makeFields ''A
data B = B
{ _bX :: String -> Char
, _bY :: String -> Bool
}
makeFields ''B
-- x can get _aX from an A and _bX from a B
a :: A
a = undefined
b :: B
b = undefined
q :: (Getter A String) AND (Getter B (String -> a)) -> a
q lens = (b^.lens) (a^.lens)
Which type should I give q? I tried letting GHC infer the types, but that failed.
To decide what is to be done, we need to know what the types of your (makeField-generated) fields are:
GHCi> :t x
x :: (HasX s a, Functor f) => (a -> f a) -> s -> f s
So the abstraction covering all your x-bearing types (the abstraction I was whining about before noticing you were using makeFields) is a multi-parameter type class HasX, and similarly for the other fields. That gives us enough to use x with different types in a single implementation:
-- Additional extension required: FlexibleContexts
-- Note that GHC is able to infer this type.
qx :: (HasX t (a -> b), HasX s a) => t -> s -> b
qx t s = (t ^. x) (s ^. x)
GHCi> import Data.Maybe
GHCi> let testA = A "foo" "bar"
GHCi> let testB = B (fromMaybe 'ø' . listToMaybe) null
GHCi> qx testB testA
'f'
That, however, is not quite what you asked for. You wanted something like:
q xOrY b a = (b^.xOrY) (a^.xOrY)
Achieving that, however, requires abstracting over the classes HasX, HasY, etc. Doing so is, in fact, somewhat feasible thanks to the ConstraintKinds extension, as demonstrated in Could we abstract over type classes? Here it goes:
-- Additional extensions required: ConstraintKinds, ScopedTypeVariables
-- Additional import required: Data.Proxy
-- GHC cannot infer this type.
q :: forall h s t a b. (h t (a -> b), h s a) => Proxy a -> Proxy h
-> (forall u c. h u c => Getting c u c) -> t -> s -> b
q _ _ l t s =
(t ^. (l :: Getting (a -> b) t (a -> b))) (s ^. (l :: Getting a s a))
GHCi> q (Proxy :: Proxy String) (Proxy :: Proxy HasX) x testB testA
'f'
The first proxy, which determines the intermediate type, is necessary unless you give up this bit of generality and replace a by String. Additionally, you have to specify the field twice, both by passing the getter as an argument and through the second proxy. I am not at all convinced that this second solution is worth the trouble -- the extra boilerplate of having to define qx, qy, etc. looks quite a bit less painful than all the circuitousness involved here. Still, if any of you who are reading this would like to suggest an improvement, I'm all ears.
Given the following code, removing forall a r from the type of go fails with "Overlapping instances for Typeable (D r)". I wonder why?
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
module M where
import Data.Typeable (Proxy, Typeable, cast)
class C r where
data D r :: *
deriving instance Typeable D
data A = forall r . A (D r)
go :: forall r a . (Typeable a, Typeable (D r)) => a -> Proxy r -> A
go a _ = case cast a of
Just (b :: D r) -> A b
Nothing -> error "fail to cast"
The error also says "The choice depends on the instantiation of r" - but isn't that pinned by the supplied Proxy r?
This is how scoped type variables work in Haskell. Note that you are re-using r here:
go :: forall r a . (Typeable a, Typeable (D r)) => a -> Proxy r -> A
go a _ = case cast a of
Just (b :: D r) -> A b -- this r is the same as the r above
Without the explicit forall, type variables are interpreted to be local to the signature. That is, your code is read as:
go :: (Typeable a1, Typeable (D r1)) => a1 -> Proxy r1 -> A -- renaming local variables
go a _ = case cast a of
Just (b :: D r) -> A b -- r bears no relation to r1
Hence the type error.
(It is confusing to get an Overlapping instances error, though.)
I'm playing around with the ConstraintKinds extension of GHC.
I have the following data type, which is just a box for things fulfilling some one parameter constraint c:
data Some (c :: * -> Constraint) where
Some :: forall a. c a => a -> Some c
For example, I could construct a box with some kind of number (arguably not very useful).
x :: Some Num
x = Some (1 :: Int)
Now, as long as c includes the constraint Show, I could provide an instance of Show (Some c).
instance ??? => Show (Some c) where
show (Some x) = show x -- Show dictionary for type of x should be in scope here
But how do I express this requirement in the instance context (marked with ???)?
I cannot use an equality constraint (c ~ Show), because the two are not necessarily equal. c could be Num, which implies, but is not equal to, Show.
Edit
I realised that this cannot be possible in general.
If you have two values of type Some Eq, it is not possible to compare them for equality. They could be of different types that each have their own notion of equality.
What applies to Eq applies to any type class in which the type parameter appears on the right hand side of the first function arrow (like the second a in (==) :: a -> a -> Bool).
Considering that there is no way to create a constraint expressing "this type variable is not used beyond the first arrow", I don't think it is possible to write the instance I want to write.
The closest we are able to get is a Class1 class that reifys the relationship between a class and a single superclass constraint as a class. It's based on the Class from constraints.
First, we'll take a short tour of the constraints package. A Dict captures the dictionary for a Constraint
data Dict :: Constraint -> * where
Dict :: a => Dict a
:- captures that one constraint entails another. If we have a :- b, whenever we have the constraint a we can produce the dictionary for the constraint b.
newtype a :- b = Sub (a => Dict b)
We need a proof similar to :-, we need to know that forall a. h a :- b a, or h a => Dict (b a).
Single Inheritance
Actually implementing this for classes with just single inheritance requires the kitchen sink of language extensions, including OverlappingInstances.
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverlappingInstances #-}
import Data.Constraint
We'll define the class of constraints of kind k -> Constraint where the constraint has a single superclass.
class Class1 b h | h -> b where
cls1 :: h a :- b a
We're now equipped to tackle our example problem. We have a class A that requires a Show instance.
class Show a => A a
instance A Int
Show is a superclass of A
instance Class1 Show A where
cls1 = Sub Dict
We want to write Show instances for Some
data Some (c :: * -> Constraint) where
Some :: c a => a -> Some c
We can Show a Some Show.
instance Show (Some Show) where
showsPrec x (Some a) = showsPrec x a
We can Show a Some h whenever h has a single superclass b and we could show Some b.
instance (Show (Some b), Class1 b h) => Show (Some h) where
showsPrec x (Some (a :: a)) =
case cls1 :: h a :- b a of
Sub Dict -> showsPrec x ((Some a) :: Some b)
This lets us write
x :: Some A
x = Some (1 :: Int)
main = print x
The new QuantifiedConstraints extension allows this.
class (a => b) => Implies a b where
instance (a => b) => Implies a b where
instance (forall a. c a `Implies` Show a) => Show (Some c) where
show (Some x) = show x
Within the body of the Show instance, it is as if there is a
instance forall a. Implies (c a) (Show a)
in scope. If you then have T :: Type and know c T, then the superclass of c T => Show T of the specialized Implies (c T) (Show T) instance allows you to derive Show T. It is necessary to use Implies instead of a straight forall a. c a => Show a constraint. This incorrect constraint acts like
instance forall a. c a => Show a
which overlaps with every Show instance, causing weird breakage. Forcing an indirection through the superclass of an otherwise useless constraint fixes everything.
You cannot make Some c an instance of Show, except trivially.
You want to show the a inside Some, but that variable is existentially quantified, so we cannot depend on any knowledge of the type of a. In particular, we have no way of knowing that a is an instance of Show.
EDIT: I'll expand on my answer.
Even with more machinery, and giving up on a Show instance, I still don't think what you want is possible because of the existential quantification.
First I'll rewrite Some in a more familiar form
data Dict p where
Dict :: p a => a -> Dict p
The usual way to talk about "constraints implying constraints" is with the concept of constraint entailment.
data p :- q where
Sub :: p a => Dict q -> p :- q
We can think about a value of type p :- q as a proof that if the constraint forall a. p a holds, then forall a. q a follows.
Now we try to write a sensible show-ish function
showD :: p :- Show -> Dict p -> String
showD (Sub (Dict a)) (Dict b) = show b
At a glance, this might work. We have brought the following constraints into scope (forgive the pseudo-exists syntax)
(0) p :: * -> Constraint
(1) exists a. p a -- (Dict p)
(2) exists b. p b => Show b -- (p :- Show)
But now things fall apart, GHC rightfully complains:
main.hs:10:33:
Could not deduce (Show a2) arising from a use of `show'
from the context (p a)
bound by a pattern with constructor
Sub :: forall (p :: * -> Constraint) (q :: * -> Constraint) a.
(p a) =>
Dict q -> p :- q,
in an equation for `showD'
at main.hs:10:8-19
or from (Show a1)
bound by a pattern with constructor
Dict :: forall (p :: * -> Constraint) a. (p a) => a -> Dict p,
in an equation for `showD'
at main.hs:10:13-18
or from (p a2)
bound by a pattern with constructor
Dict :: forall (p :: * -> Constraint) a. (p a) => a -> Dict p,
in an equation for `showD'
at main.hs:10:23-28
because it is impossible to unify the a from (1) with the b from (2).
This is the same essential idea that is used throughout the constraints package mentioned in the comments.