QSpider
QSpider

Reputation: 577

Ambiguous type in Haskell type class

I want to use parametrized type class. Below is my source code:

class (CContext3D c k v) => CBuilder3D c a k v where
    build3D :: c -> a -> String -> HSL HLangJS HLangJS

At compilation I receive the following error:

Could not deduce (CBuilder3D c a k0 v0)
from the context: CBuilder3D c a k v
bound by the type signature for:
   build3D :: CBuilder3D c a k v =>
                              c -> a -> String -> HSL HLangJS HLangJS

The following code works correctly:

class (CContext3D c KeyContext3D String) => CBuilder3D c a where
    build3D :: c -> a -> String -> HSL HLangJS HLangJS

How is it possibly to release instance of class depending from k and v types?

Upvotes: 0

Views: 280

Answers (1)

chi
chi

Reputation: 116174

Suppose there is a call to your build3D. From the context of that call, the compiler has to find a proper instance. This involves finding values for variables c a k v. However, the type of build3D do not mention k v, so it would be impossible to find those.

More concretely, if we had

instance CBuilder3D c a K1 V1 where ...
instance CBuilder3D c a K2 V2 where ...

their related build3D function would have exactly the same type, and the compiler has no way to choose one of those.

Possible solutions:

If possible, you should use functional dependencies or type families to state that the value of k and v are determined by the other parameters. This might be the case or not, depending on your specific class.

Otherwise, you could try enabling AllowAmbiguousTypes and TypeApplications, and keep the ambiguous type around. However, at every call, you now will have to specify those types explicitly as in build3D @t1 @t2 @t3 @t4 x1 x2 x3 where t1,... are the types for all the variables c a k v. Not terribly convenient.

Another option is to make k,v to appear in the type with a proxy:

import Data.Proxy

class (CContext3D c k v) => CBuilder3D c a k v where
    build3D :: proxy k -> proxy v -> c -> a -> String -> HSL HLangJS HLangJS

now each call should be something like build3D (Proxy :: Proxy K1) (Proxy :: Proxy V1) x1 x2 x3.

Upvotes: 3

Related Questions