Static Guarantee on Key/Value Relationships in Data.Map - haskell

I want to make a special smart constructor for Data.Map with a certain constraint on the types of key/value pair relationships. This is the constraint I tried to express:
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, DataKinds #-}
data Field = Speed | Name | ID
data Value = VFloat Float | VString ByteString | VInt Int
class Pair f b | f -> b where
toPair :: f -> b -> (f, b)
toPair = (,)
instance Pair Speed (VFloat f)
instance Pair ID (VInt i)
for each field, there is only one type of value that it should be associated with. In my case, it does not make sense for a Speed field to map to a ByteString. A Speed field should uniquely map to a Float
But I get the following type error:
Kind mis-match
The first argument of `Pair' should have kind `*',
but `VInt' has kind `Value'
In the instance declaration for `Pair Speed (VFloat f)'
using -XKindSignatures:
class Pair (f :: Field) (b :: Value) | f -> b where
toPair :: f -> b -> (f, b)
toPair = (,)
Kind mis-match
Expected kind `OpenKind', but `f' has kind `Field'
In the type `f -> b -> (f, b)'
In the class declaration for `Pair'
I understand why I get the Kind mis-match, but how can I express this constraint so that it is a compile time type-checker error to use toPair on an non-matching Field and Value.
It was suggested to me by #haskell to use a GADT, but I havent been able to figure it out yet.
The goal of this is to be able to write
type Record = Map Field Value
mkRecord :: [Field] -> [Value] -> Record
mkRecord = (fromList .) . zipWith toPair
so that I can make safe Maps where the key/value invariants are respected.
So this should type-check
test1 = mkRecord [Speed, ID] [VFloat 1.0, VInt 2]
but this should be a compile time error
test2 = mkRecord [Speed] [VInt 1]
EDIT:
I'm beginning to think that my specific requirements aren't possible. Using my original example
data Foo = FooInt | FooFloat
data Bar = BarInt Int | BarFloat Float
In order to enforce the constraint on Foo and Bar, there must be some way to differentiate between a FooInt and FooFloat at the type level and similarly for Bar. Thus I instead need two GADTs
data Foo :: * -> * where
FooInt :: Foo Int
FooFloat :: Foo Float
data Bar :: * -> * where
BarInt :: Int -> Bar Int
BarFloat :: Float -> Bar Float
now I can write an instance for Pair that only holds when the Foo and Bar are both tagged with the same type
instance Pair (Foo a) (Bar a)
and I have the properties I want
test1 = toPair FooInt (BarInt 1) -- type-checks
test2 = toPair FooInt (BarFloat 1) -- no instance for Pair (Foo Int) (Bar Float)
but I lose the ability to write xs = [FooInt, FooFloat] because that would require a heterogeneous list. Furthermore if I try to make the Map synonym type FooBar = Map (Foo ?) (Bar ?) I'm stuck with a Map of either only Int types or only Float types, which isnt what I want. It's looking rather hopeless, unless theres some powerful type class wizardry I'm not aware of.

You could use a GADT like so,
data Bar :: * -> * where
BarInt :: Int -> Bar Int
BarFloat :: Float -> Bar Float
now you have 2 distinct types of Bar available (Bar Int) and (Bar Float).You could then just split Foo into 2 types unless there is a reason not to.
data FooInt
data FooFloat
class Pair f b c| f b -> c where
toPair :: f -> b -> c
instance Pair FooInt (Bar Int) (FooInt,Int) where
toPair a (BarInt b)= (a,b)
This is sort of a clumsy example but it shows how you can specialize the type using a GADT. The idea is that they carry a "phantom type" along. It is described pretty well on this page and with DataKinds on this page.
EDIT:
If we make both Foo and Bar GADT's we can use a type or data family as described here. So, this combination allows us to set the type of Map based on the key type. Still feels like there are other possibly simpler ways to accomplish this, but it does showcase 2 great GHC extensions!
data Foo :: * -> * where
FooInt :: Int -> Foo Int
FooFloat :: Float -> Foo Float
data Bar :: * -> * where
BarInt :: Int -> Bar Int
BarFloat :: Float -> Bar Float
class Pair f b c| f b -> c where
toPair :: f -> b -> c
instance Pair (Foo Int) (Bar Int) ((Foo Int),Int) where
toPair a (BarInt b)= (a,b)
type family FooMap k :: *
type instance FooMap (Foo Int) = Map (Foo Int) (Bar Int)

An oldschool version using Dynamic and Typeable and FunDeps. To keep it safe, you just need to not export the abstraction-breaking things like the SM constructor and the SMKey typeclass.
{-# LANGUAGE DeriveDataTypeable, MultiParamTypeClasses, FunctionalDependencies, TypeSynonymInstances, FlexibleInstances #-}
module Main where
import qualified Data.Map as M
import Data.Dynamic
import Data.Typeable
data SpecialMap = SM (M.Map String Dynamic)
emptySM = SM (M.empty)
class (Typeable a, Typeable b) => SMKey a b | a -> b
data Speed = Speed deriving Typeable
data Name = Name deriving Typeable
data ID = ID deriving Typeable
instance SMKey Speed Float
instance SMKey Name String
instance SMKey ID Int
insertSM :: SMKey k v => k -> v -> SpecialMap -> SpecialMap
insertSM k v (SM m) = SM (M.insert (show $ typeOf k) (toDyn v) m)
lookupSM :: SMKey k v => k -> SpecialMap -> Maybe v
lookupSM k (SM m) = fromDynamic =<< M.lookup (show $ typeOf k) m
-- and now lists
newtype SMPair = SMPair {unSMPair :: (String, Dynamic)}
toSMPair :: SMKey k v => k -> v -> SMPair
toSMPair k v = SMPair (show $ typeOf k, toDyn v)
fromPairList :: [SMPair] -> SpecialMap
fromPairList = SM . M.fromList . map unSMPair
{-
*Main> let x = fromPairList [toSMPair Speed 1.2, toSMPair ID 34]
*Main> lookupSM Speed x
Just 1.2
-}

When I first read this I attempted to solve the problem of forcing compile errors in the required cases, but something seemed wrong. I then tried an approach with multiple maps and a lifting function, but something was still nagging me. However, when I realised that essentially what you are trying to do is create some form of extensible record, it reminded me of a very cool package I had become aware of a few months ago: the Vinyl package (available on Hackage). This may or may not be exactly the effects you were after, and it does require GHC 7.6, but here is an example adapted from the readme:
{-# LANGUAGE DataKinds, TypeOperators #-}
{-# LANGUAGE FlexibleContexts, NoMonomorphismRestriction #-}
import Data.Vinyl
speed = Field :: "speed" ::: Float
name = Field :: "name" ::: String
iD = Field :: "id" ::: Int
Now a record can be made containing any number of these fields:
test1 = speed =: 0.2
test2 = speed =: 0.2
<+> name =: "Ted"
<+> iD =: 1
These are of different types, so an attempt to pass the wrong amount of information in a given function will cause a compile error. A type synonym can make this easier to use, but type annotations are not required.
type Entity = Rec ["speed" ::: Float, "name" ::: String, "id" ::: Int]
test2 :: Entity
The library provides automatic lenses on these types without the need for Template Haskell, and a casting function that allows for subtypes to be handled with ease. For example:
test2Casted :: Rec '["speed" ::: Float]
test2Casted = cast test2
(The extra tick is required to get the kind right for the single field record).
This doesn't allow the exact type for mkRecord you were after, but it does seem to capture the requirements of static checking of extensible records. If this doesn't work for you, you might nevertheless be able to use of the clever type techniques found in the Vinyl source to get where you want to go.

I would make an opaque datatype with some getters and setters.
module Rec (Rec, getSpeed, getName, getID, setSpeed, setName, setID, blank) where
data Rec = R { speed :: Maybe Double; name :: Maybe String; id :: Maybe Int }
getSpeed :: Rec -> Maybe Double
getSpeed = speed
setSpeed :: Double -> Rec -> Rec
setSpeed s r = r { speed = s }
blank = R { speed = Nothing, name = Nothing, id = Nothing }

Related

Deriving Show when a type family is present (without writing manual constraints)

I want to create an ADT that is parameterized on a certain type family, which can be used to change the type of the fields. I'd like to derive Show/Eq/etc. for this type without lots of boilerplate.
Standalone deriving works, if you manually write out the constraints. I understand from questions like this one why a normal deriving Show statement doesn't work.
But, writing out the constraints is cumbersome if you have lots of fields like this. My question is, given all the new deriving features in GHC lately (strategies, via, etc.) is there some way to do this concisely?
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
module Test where
import Data.Kind
import Prelude
type family Switchable (f :: Type -> Type) x where
Switchable TextName x = String
Switchable Same x = x
data TextName x
data Same x
data Foo f = Foo {
fooField :: Switchable f Int
}
-- The constraint here is required, which gets cumbersome when many fields are present
deriving instance (Show (Switchable f Int)) => Show (Foo f)
At first I thought you might be able to get away with a quantified constraint like this:
deriving instance (forall a. Show a => Show (Switchable f a)) => Show (Foo f)
But sadly, type families cannot appear in a quantified constraint, for the same reason they can't appear in instance heads.
So I came up with a slightly worse, but still less cumbersome solution: extract all the constraint boilerplate as yet another type family returning a constraint.
type family ShowAll f (xs :: [Type]) :: Constraint where
ShowAll f '[] = ()
ShowAll f (x:xs) = (Show (Switchable f x), ShowAll f xs)
Now you can use this to assert Show (Switchable f a) for all interesting a:
data Foo f = Foo {
fooField1 :: Switchable f Int,
fooField2 :: Switchable f String,
fooField3 :: Switchable f Bool
}
deriving instance ShowAll f '[Int, String, Bool] => Show (Foo f)
You still have to enumerate all the a explicitly, but at least now it's cleaner without all the noise.
I hope this is helpful.
There are a few different methods for this.
Make an alias for applying a constraint to all the field types, to abbreviate constraints on all of them. (Some will be redundant.)
{-# Language ConstraintKinds #-}
data Foo f = Foo
{ fooField1 :: Switchable f Int
, fooField2 :: Switchable f String
, fooField3 :: Switchable f Bool
}
type Fields (c :: Type -> Constraint) (f :: Type -> Type) =
( c (Switchable f Int)
, c (Switchable f String)
, c (Switchable f Bool)
)
deriving instance (Fields Show f) => Show (Foo f)
Replace the type family with a GADT.
data Foo f = Foo
{ fooField1 :: Field f Int
, fooField2 :: Field f String
, fooField3 :: Field f Bool
}
deriving instance Show (Foo f)
data Field (f :: Type -> Type) x where
Field :: Switch f x r -> Field f x
deriving instance (Show x) => Show (Field f x)
data Switch (f :: Type -> Type) x r where
SwitchTextName :: String -> Switch TextName x String
SwitchSame :: x -> Switch Same x x
deriving instance (Show x) => Show (Switch f x r)
This is a 1-for-1 translation, but it can be simplified depending on the specifics, such as using only one type parameter, instead of having both x for the provided type and r for the resulting representation type.
Since constraints are only necessary to talk about types generically, avoid constraints by deriving instances for concrete combinations of types whenever possible.
deriving instance Show (Foo TextName)
deriving instance Show (Foo Same)
Make each field type that may vary into a type parameter, then write convenience aliases for combinations of parameters.
data Foo i s b = Foo
{ fooField1 :: i
, fooField2 :: s
, fooField3 :: b
}
type FooByName = Foo String String String
type FooByNumbers = Foo Int String Bool
#4 can be a little unwieldy with a large number of parameters, but it has the distinct advantage that you can easily write polymorphic functions to update only one parameter and ignore the others. When all the field types are indexed by a single type parameter, like in the type-family version, you may need to traverse the whole data structure to update any of them.

Is there a way to apply Maybe constructor to each field of record with generics?

I have two data types and the second one is the copy of first, but with Maybe on each field.
data A = {a :: Int, b :: String}
data B = {c :: Maybe Int, d :: Maybe String}
Is there a way to make a functions
f :: A -> B
g :: B -> A -> A
without any knowledge about fields itself? (if value of first argument is nothing g will take default value from second argument)
This can be done with generics-sop, a library that extends the default Generics machinery of GHC.
"generics-sop" can take a regular record and deduce a generic representation for it. This representation has a type parameter that wraps every field, and the library allows Applicative sequence-like operations across the record fields.
{-# language TypeOperators #-}
{-# language DeriveGeneric #-}
{-# language TypeFamilies #-}
{-# language DataKinds #-}
import qualified GHC.Generics as GHC
import Generics.SOP
data A = A {a :: Int, b :: String} deriving (Show,GHC.Generic)
instance Generic A -- this Generic is from generics-sop
defaulty :: (Generic a, Code a ~ '[ xs ]) => NP Maybe xs -> a -> a
defaulty maybes r = case (from r) of
SOP (Z np) -> let result = hliftA2 (\m i -> maybe i I m) maybes np
in to (SOP (Z result))
main :: IO ()
main = do
print $ defaulty (Nothing :* Just "bar" :* Nil) (A 99 "foo")
Nothing :* Just "bar" :* Nil is a generic representation that matches the list of fields in the original record definition. Notice that each field in the representation is wrapped in Maybe.
See here for another example of generics-sop.
How about:
{-# LANGUAGE RankNTypes #-}
data R f = R { a :: f Int, b :: f String, c :: f Char }
newtype I a = I { unI :: a }
fromMaybeI :: I a -> Maybe a -> I a
fromMaybeI a Nothing = a
fromMaybeI _ (Just a) = I a
fromMaybeR :: R I -> R Maybe -> R I
fromMaybeR ri rm =
R (go a) (go b) (go c)
where
go :: (forall f. R f -> f a) -> I a
go x = fromMaybeI (x ri) (x rm)
R Maybe is the record with Maybe values, R I is the record with concrete values.
Using RankNTypes reduces the amount of boilerplate code in fromMaybeR.
One downside is that you have use I and unI to construct and
access the field values.

Existentials and reusing witness

Let's imagine I have an existential type T
T = ∃X { a :: X, f :: X -> Int}
Of which I produce a value
v :: T
v = pack {Int, { a = 0, f x = 0 } } as T
So :
users of this value are forbidden to know which type X is actually used in the implementation. In order to consume this value, their code has to be polymorphic in X
the implementor, on the other hand, is in full knowledge that X is actually an Int and can use the capacities of the underlying type as he wishes
I would like to know if there are variant of this mechanism which do not destroy evidence :
w, v = pack {Int, { a = 0, f x = 0 } } as T
s = unpack w v -- recovers type information
where w would be a value level proof of the type equation tying X to int. the idea would be to selectively reuse the implementation in another part of the code, and have non polymorphic code. to have the usual existential behaviour, we can just ignore the w returned.
I guess one could cast X to Int and abandon type safety, but that's another story: If I know the secret about v, wouldn't it make sense for me to be able to tell the secret to someone else and have the compiler verify that the secret only get used by code it has been given to.
Has it been tried / what's the most wrong part of this?
Use singletons
-- singleton for some types we are interested in
data S a where
Sint :: S Int
Sbool :: S Bool
-- existential type, with a singleton inside
data T where
T :: S a -> a -> (a -> Int) -> T
-- producer
t :: T
t = T Sint 3 succ
-- consumer
foo :: T -> Int
foo (T Sint n f) = f (n + 10)
foo (T Sbool True f) = 23
foo (T Sbool False f) = f 3
If you need to go full monty, use Typeable.
data T where
T :: Typeable a => a -> (a -> Int) -> T
-- consumer
foo :: T -> Int
foo (T x f) = case cast x of
Just n -> f ((n :: Int) + 10)
Nothing -> 12 -- more casts can be attempted here
Pack up a GADT which gives you a way to learn by pattern-matching what the existentially quantified type was. This is a way to emulate a dependent pair type.
data Ty a where
IntTy :: Ty Int
CharTy :: Ty Char
data T = forall a. T {
ty :: Ty a,
x :: a,
f :: a -> Int
}
consumeT :: T -> Int
consumeT (T IntTy x _) = {-# GHC knows (x :: Int) in this branch #-} x + 3
consumeT (T CharTy x f) = {-# GHC knows (x :: Char) in this branch #-} f x + 3

How can I abstract a common Haskell recursive applicative functor pattern

While using applicative functors in Haskell I've often run into situations where I end up with repetitive code like this:
instance Arbitrary MyType where
arbitrary = MyType <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
In this example I'd like to say:
instance Arbitrary MyType where
arbitrary = applyMany MyType 4 arbitrary
but I can't figure out how to make applyMany (or something similar to it). I can't even figure out what the type would be but it would take a data constructor, an Int (n), and a function to apply n times. This happens when creating instances for QuickCheck, SmallCheck, Data.Binary, Xml serialization, and other recursive situations.
So how could I define applyMany?
Check out derive. Any other good generics library should be able to do this as well; derive is just the one I am familiar with. For example:
{-# LANGUAGE TemplateHaskell #-}
import Data.DeriveTH
import Test.QuickCheck
$( derive makeArbitrary ''MyType )
To address the question you actually asked, FUZxxl is right, this is not possible in plain vanilla Haskell. As you point out, it is not clear what its type should even be. It is possible with Template Haskell metaprogramming (not too pleasant). If you go that route, you should probably just use a generics library which has already done the hard research for you. I believe it is also possible using type-level naturals and typeclasses, but unfortunately such type-level solutions are usually difficult to abstract over. Conor McBride is working on that problem.
I think you can do it with OverlappingInstances hack:
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeFamilies, OverlappingInstances #-}
import Test.QuickCheck
import Control.Applicative
class Arbitrable a b where
convert :: Gen a -> Gen b
instance (Arbitrary a, Arbitrable b c) => Arbitrable (a->b) c where
convert a = convert (a <*> arbitrary)
instance (a ~ b) => Arbitrable a b where
convert = id
-- Should work for any type with Arbitrary parameters
data MyType a b c d = MyType a b c d deriving (Show, Eq)
instance Arbitrary (MyType Char Int Double Bool) where
arbitrary = convert (pure MyType)
check = quickCheck ((\s -> s == s) :: (MyType Char Int Double Bool -> Bool))
Not satisfied with my other answer, I have come up with an awesomer one.
-- arb.hs
import Test.QuickCheck
import Control.Monad (liftM)
data SimpleType = SimpleType Int Char Bool String deriving(Show, Eq)
uncurry4 f (a,b,c,d) = f a b c d
instance Arbitrary SimpleType where
arbitrary = uncurry4 SimpleType `liftM` arbitrary
-- ^ this line is teh pwnzors.
-- Note how easily it can be adapted to other "simple" data types
ghci> :l arb.hs
[1 of 1] Compiling Main ( arb.hs, interpreted )
Ok, modules loaded: Main.
ghci> sample (arbitrary :: Gen SimpleType)
>>>a bunch of "Loading package" statements<<<
SimpleType 1 'B' False ""
SimpleType 0 '\n' True ""
SimpleType 0 '\186' False "\208! \227"
...
Lengthy explanation of how I figured this out
So here's how I got it. I was wondering, "well how is there already an Arbitrary instance for (Int, Int, Int, Int)? I'm sure no one wrote it, so it must be derived somehow. Sure enough, I found the following in the docs for instances of Arbitrary:
(Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d) => Arbitrary (a, b, c, d)
Well, if they already have that defined, then why not abuse it? Simple types that are merely composed of smaller Arbitrary data types are not much different than just a tuple.
So now I need to somehow transform the "arbitrary" method for the 4-tuple so that it works for my type. Uncurrying is probably involved.
Stop. Hoogle time!
(We can easily define our own uncurry4, so assume we already have this to operate with.)
I have a generator, arbitrary :: Gen (q,r,s,t) (where q,r,s,t are all instances of Arbitrary). But let's just say it's arbitrary :: Gen a. In other words, a represents (q,r,s,t). I have a function, uncurry4, which has type (q -> r -> s -> t -> b) -> (q,r,s,t) -> b. We are obviously going to apply uncurry4 to our SimpleType constructor. So uncurry4 SimpleType has type (q,r,s,t) -> SimpleType. Let's keep the return value generic, though, because Hoogle doesn't know about our SimpleType. So remembering our definition of a, we have essentially uncurry4 SimpleType :: a -> b.
So I've got a Gen a and a function a -> b. And I want a Gen b result. (Remember, for our situation, a is (q,r,s,t) and b is SimpleType). So I am looking for a function with this type signature: Gen a -> (a -> b) -> Gen b. Hoogling that, and knowing that Gen is an instance of Monad, I immediately recognize liftM as the monadical-magical solution to my problems.
Hoogle saves the day again. I knew there was probably some "lifting" combinator to get the desired result, but I honestly didn't think to use liftM (durrr!) until I hoogled the type signature.
Here is what I'v got at least:
{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
module ApplyMany where
import Control.Applicative
import TypeLevel.NaturalNumber -- from type-level-natural-number package
class GetVal a where
getVal :: a
class Applicative f => ApplyMany n f g where
type Res n g
app :: n -> f g -> f (Res n g)
instance Applicative f => ApplyMany Zero f g where
type Res Zero g = g
app _ fg = fg
instance
(Applicative f, GetVal (f a), ApplyMany n f g)
=> ApplyMany (SuccessorTo n) f (a -> g)
where
type Res (SuccessorTo n) (a -> g) = Res n g
app n fg = app (predecessorOf n) (fg<*>getVal)
Usage example:
import Test.QuickCheck
data MyType = MyType Char Int Bool deriving Show
instance Arbitrary a => GetVal (Gen a) where getVal = arbitrary
test3 = app n3 (pure MyType) :: Gen MyType
test2 = app n2 (pure MyType) :: Gen (Bool -> MyType)
test1 = app n1 (pure MyType) :: Gen (Int -> Bool -> MyType)
test0 = app n0 (pure MyType) :: Gen (Char -> Int -> Bool -> MyType)
Btw, I think this solution is not very useful in real world. Especially without local type-classes.
Check out liftA2 and liftA3. Also, you can easily write your own applyTwice or applyThrice methods like so:
applyTwice :: (a -> a -> b) -> a -> b
applyTwice f x = f x x
applyThrice :: (a -> a -> a -> b) -> a -> b
applyThrice f x = f x x x
There's no easy way I can see to get the generic applyMany you're asking for, but writing trivial helpers such as these is neither difficult nor uncommon.
[edit] So it turns out, you'd think something like this would work
liftA4 f a b c d = f <$> a <*> b <*> c <*> d
quadraApply f x = f x x x x
data MyType = MyType Int String Double Char
instance Arbitrary MyType where
arbitrary = (liftA4 MyType) `quadraApply` arbitrary
But it doesn't. (liftA4 MyType) has a type signature of (Applicative f) => f Int -> f String -> f Double -> f Char -> f MyType. This is incompatible with the first parameter of quadraApply, which has a type signature of (a -> a -> a -> a -> b) -> a -> b. It would only work for data structures that hold multiple values of the same Arbitrary type.
data FourOf a = FourOf a a a a
instance (Arbitrary a) => Arbitrary (FourOf a) where
arbitrary = (liftA4 FourOf) `quadraApply` arbitrary
ghci> sample (arbitrary :: Gen (FourOf Int))
Of course you could just do this if you had that situation
ghci> :l +Control.Monad
ghci> let uncurry4 f (a, b, c, d) = f a b c d
ghci> samples <- sample (arbitrary :: Gen (Int, Int, Int, Int))
ghci> forM_ samples (print . uncurry4 FourOf)
There might be some language pragma that can shoehorn the "arbitrary" function into the more diverse data types. But that's currently beyond my level of Haskell-fu.
This is not possible with Haskell. The problem is, that your function will have a type, that depends on the numeric argument. With a type system that allows dependent types, that should be possible, but I guess not in Haskell.
What you can try is using polymorphism and tyeclasses to archieve this, but it could become hacky and you need a big bunch of extensions to satisfy the compiler.

Binding type variables that only occur in assertions

I find it extremely difficult to describe my problem, so here goes nothing:
I have a bunch of assertions on the type of a function. These assertions rely on a type variable that is not used for any parameter of the function, but is only used for internal bindings. Whenever I use this function it does not compile because, of course, the compiler has no information from which to guess what type to bind my type variable. Here is the code:
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances,
UndecidableInstances, FlexibleContexts, EmptyDataDecls, ScopedTypeVariables,
TypeOperators, TypeSynonymInstances #-}
class C a a' where convert :: a -> a'
class F a b where apply :: a -> b
class S s a where select :: s -> a
data CInt = CInt Int
instance S (Int,String) Int where select (i,_) = i
instance F Int CInt where apply = CInt
f :: forall s a b . (S s a, F a b) => s -> b
f s =
let v = select s :: a
y = apply v :: b
in y
x :: Int
x = f (10,"Pippo")
And here is the generated error:
FunctorsProblems.hs:21:4:
No instances for (F a Int, S (t, [Char]) a)
arising from a use of `f' at FunctorsProblems.hs:21:4-17
Possible fix:
add an instance declaration for (F a Int, S (t, [Char]) a)
In the expression: f (10, "Pippo")
In the definition of `x': x = f (10, "Pippo")
Failed, modules loaded: none.
Prelude>
You are trying to intersect some set of instances of classes and for compiler there is no way to say that this intersection will be empty or single entry.
You want to force compiler to choose the right type for you without knowing which problems (information loss or complexity of calculations) that decision can bring in your program. If you want to do that you should give a hint to compiler what is the best type "a" for specific pair "s" and "b" (with us of that FunctionalDependencies you specified).
class E x a | x -> a
instance (S s Int, F Int CInt) => E (s, CInt) Int
f :: forall s a b . (E (s,b) a) => s -> b
Probably there is the way to specify order of preferred types of "a" for pair of "s" and "b" with further deduce of best "a" (i.e. use of type-level or something like that to attach that information).

Resources