I'v seen a couple of posts with a similar subject but they don't really help me to solve my problem. So I dare to repeat.
Now I have a functions with signature:
run' :: Expr query => RethinkDBHandle -> query -> IO [JSON]
this is a database query run function.
I wrap this function in a pool (pool is already created and irrelevant to the question) to simplify connections.
rdb q = withResource pool (\h -> run' (use h $ db "test") q)
Essentially, this function has exact the same signature as the run above.
The problem is that if I use the function without a signature then all is good and GHC is happy figuring things out. As soon as I specify the signature it stops working on certain input complaining about not being able to deduce the type.
There are mainly two input types that are used as query input.
ReQL and Table
Both of those types are instances of Expr
so they both accepted by GHC.
As soon as I put the signature everything stops working and GHC coplains about not being able to deduce the type and gives me "rigid type variable bound by the type signature" error. If I make signature more specific like ReQL
instead of Expr a
, then obveously it stops accepting Table
input and visa versa. Specifying input as Expr a
, which both ReQL
and Table
are instances of, stops with the error above. Dropping the signature all together works fine.
So how do I solve this? Dropping the signature feels wrong.
I don't know if I should make the question more generic or more specific but if it helps this is the library with all the types and instances to help with an advice.
UPDATE
As requested, this is the full code listing producing the error.
main = do
pool <- createPool (connect "localhost" 28015 Nothing) close 1 300 5
let rdb q = withResource pool (\h -> run' (use h $ db "test") q)
scotty 3000 $ basal rdb
basal :: Expr q => (q -> IO [JSON]) -> ScottyM ()
basal r = get "/json" $ showJson r
showJson :: Expr q => (q -> IO [JSON]) -> ActionM ()
showJson r = do
j <- lift $ r $ table "mytable"
text $ T.pack $ show j
And this is the full error listing
Main.hs:19:17:
No instance for (Expr q0) arising from a use of `basal'
The type variable `q0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Expr () -- Defined in `Database.RethinkDB.ReQL'
instance (Expr a, Expr b) => Expr (a, b)
-- Defined in `Database.RethinkDB.ReQL'
instance (Expr a, Expr b, Expr c) => Expr (a, b, c)
-- Defined in `Database.RethinkDB.ReQL'
...plus 24 others
In the second argument of `($)', namely `basal rdb'
In a stmt of a 'do' block: scotty 3000 $ basal rdb
In the expression:
do { pool <- createPool
(connect "localhost" 28015 Nothing) close 1 300 5;
let rdb q = withResource pool (\ h -> ...);
scotty 3000 $ basal rdb }
Main.hs:26:19:
Could not deduce (q ~ Table)
from the context (Expr q)
bound by the type signature for
showJson :: Expr q => (q -> IO [JSON]) -> ActionM ()
at Main.hs:24:13-52
`q' is a rigid type variable bound by
the type signature for
showJson :: Expr q => (q -> IO [JSON]) -> ActionM ()
at Main.hs:24:13
In the return type of a call of `table'
In the second argument of `($)', namely `table "mytable"'
In the second argument of `($)', namely `r $ table "mytable"'
Thank you
Reading the error messages it seems the first problem is that the type you specify for
showJson
is wrong.As
r
is being applied directly totable
which istable :: String -> Table
its type is notbut instead either
or (using
RankNTypes
)The first is simpler and more direct while the second is probably closer to your intended meaning---it can be read as "
fromJson
takes an input which it demands uses only theExpr
interface on its argument" instead of "fromJson
takes any kind of input which happens to use anExpr
instantiated type as its argument". For instance, with the type you've givenwould unify as well... but clearly that's now how
r
is being used in the function body.(In particular, it has to do with the positivity of the parameter
q
. Due to the way this function is written,q
acts more like an output argument than an input argument. Indeed, the function creates aTable
(withtable
) instead of demanding one. The argument you've written thus implies that we have a functionExpr q => Table -> q
.)Now, this specificity of type transmits upward as well causing
basal
to have the typeor
and thus leading to your
Cannot deduce (q ~ Table)
error.At this point I can't be sure why stating an explicit type for
rdb
would lead to issues, but it may be that clearing this one will stop problems from occurring there. Usually once you've already broken the type system it's very hard to predict its behavior in other locations.