Reputation: 26122
Well, just simplified as possible:
There is a function that takes functor and does whatever
sToInt :: ∀ a s. Functor s => s a -> Int
sToInt val = unsafeCoerce val
Usage of this function with functor S
which param (v
) is functor too.
-- declare date type S that is functor
data S (v :: Type -> Type) a = S (v a)
instance functorS :: Functor v => Functor (S v) where
map f (S a) = S (map f a)
sV :: ∀ v a. S v a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV -- get the error here
No type class instance was found for
Data.Functor.Functor t2
The instance head contains unknown type variables. Consider adding a type annotation.
while applying a function sToInt
of type Functor t0 => t0 t1 -> Int
to argument sV
while checking that expression sToInt sV
has type Int
in value declaration sss
where t0 is an unknown type
t1 is an unknown type
t2 is an unknown type
So it doesn't like S Functor instance has v
param Functor constraint, I wonder why getting this error and how to fix it for this case.
Upvotes: 0
Views: 346
Reputation: 80734
This doesn't have to do with v
or with the specific shape of S
. Try this instead:
sV :: forall f a. Functor f => f a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV
You get a similar error.
Or here's an even more simplified version:
sV :: forall a. a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV
Again, same error.
The problem is that sToInt
must get a Functor
instance as a parameter (that's what the Functor s =>
bit in its type signature says), and in order to pick which Functor
instance to pass, the compiler needs to know the type of the value. Like, if it's Maybe a
, it will pass the Functor Maybe
instance, and if it's Array a
, it will pass the Functor Array
instance, and so on.
Usually the type can be inferred from the context. For example when you say map show [1,2,3]
, the compiler knows that map
should come from Functor Array
, because [1,2,3] :: Array Int
.
But in your case there is nowhere to get that information: sV
can return S v
for any v
, and sToInt
can also take any functor type. There is nothing to tell the compiler what the type should be.
And the way to fix this is obvious: if there is no context information for the compiler to get the type from, you have to tell it what the type is yourself:
sss :: Int
sss = sToInt (sV :: S Maybe _)
This will be enough for the compiler to know that v ~ Maybe
, and it will be able to construct a Functor (S Maybe)
instance and pass it to sToInt
.
Alternatively, if you want the consumer of sss
to decide what v
is, you can add an extra dummy parameter to capture the type, and require that the consumer pass in a Functor v
instance:
sss :: forall v. Functor v => FProxy v -> Int
sss _ = sToInt (sV :: S v _)
ddd :: Int
ddd = sss (FProxy :: FProxy Maybe)
In Haskell you can do this with visible type applications instead of FProxy
, but PureScript, sadly, doesn't support that yet.
Even more alternatively, if sToInt
doesn't actually care for a Functor
instance, you can remove that constraint from it, and everything will work as-is:
sToInt :: forall s a. s a -> Int
sToInt a = unsafeCoerce a
sV :: forall v a. S v a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV
This works because PureScript allows for ambiguous (aka "unknown") types to exist as long as they're not used for selecting instances.
Upvotes: 3