[Takusen] working out how to use bind variables

Jason Dagit dagit at codersbase.com
Wed Aug 11 22:06:48 EDT 2010


I explained this in IRC but I'm also replying here so that the solution will
appear together with the question when other people search for it.

On Wed, Aug 11, 2010 at 11:45 AM, Michael Litchard <michael at schmong.org>wrote:

> Here's some toy code I have been playing with. The first few attempts
> work fine, but the final line, where I try to use bind variables,
> becomes a problem.
>
>
>
> > import Database.PostgreSQL.Enumerator
> > import Database.Enumerator
>
> > main :: IO ()
> > main = do
> > let connection = connect [CAdbname "tutorialDB"]
> > let foo = "test"
> > let bar = 42
> > withSession connection (execDDL (sql "create table activities (Activity
> char(20) PRIMARY KEY, cost int)"))
> > withSession connection (execDDL (sql "create table students (Student char
> (20), ID int PRIMARY KEY)"))
> > withSession connection (execDDL (sql "create table participants (Activity
> char (20) REFERENCES activities , ID int PRIMARY KEY)"))
> > withSession connection (execDDL (sql "insert into activities
> (Activity,Cost) values ('golf', 27)"))
> > withSession connection (execDML (cmdbind "insert into activities
> (Activity, Cost) values (?, ?)" [bindP foo, bindP bar]))
>
>
> tutorial.lhs:16:26:
>    Couldn't match expected type `()' against inferred type `Int'
>      Expected type: DBM mark Session ()
>      Inferred type: DBM mark Session Int
>    In the second argument of `withSession', namely
>        `(execDML
>            (cmdbind
>               "insert into activities (Activity, Cost) values (?, ?)"
>               [bindP foo, bindP bar]))'
>    In the expression:
>        withSession
>          connection
>          (execDML
>             (cmdbind
>                "insert into activities (Activity, Cost) values (?, ?)"
>                [bindP foo, bindP bar]))
>
>
> I know this means I need to fix the type, but I don't know how. I've
> been looking at the code used for testing, plus the usage examples
> from Enumerator.lhs. Haven't quite got it. Any help pointing me in the
> right direction would be much welcome.
>

The problem is that withSession has this type:
> withSession :: (Typeable a, IE.ISession sess) =>
>     IE.ConnectA sess -> (forall mark. DBM mark sess a) -> IO a

execDML has this type:
> execDML :: IE.Command stmt s => stmt -> DBM mark s Int

So, your call withSession (execDML ...), must have type:
IO Int

The type of main is IO ().  Since the call to withSession appears last in
main there is a conflict between the Int that withSession is trying to
return and the type of main.

One fix is to add a line right after your last withSession that is just
"return ()".  Once you do that, you'll start getting a crazy error message
about overlapping instances.  The problem in that case is that bar has
polymorphic type, "Num a => a".  You'll need to provide an explicit type
signature for bar.  A working version of your program looks like this:

\begin{code}
import Database.PostgreSQL.Enumerator
import Database.Enumerator

main :: IO ()
main = do
  let connection = connect [CAdbname "tutorialDB"]
  let foo = "test"
  let bar :: Int
      bar = 42
  withSession connection (execDDL (sql "create table activities (Activity
char(20) PRIMARY KEY, cost int)"))
  withSession connection (execDDL (sql "create table students (Student char
(20), ID int PRIMARY KEY)"))
  withSession connection (execDDL (sql "create table participants (Activity
char (20) REFERENCES activities , ID int PRIMARY KEY)"))
  withSession connection (execDDL (sql "insert into activities
(Activity,Cost) values ('golf', 27)"))
  withSession connection (execDML (cmdbind "insert into activities
(Activity, Cost) values (?, ?)" [bindP foo, bindP bar]))
  return ()
\end{code}

I hope that helps!
Jason
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://projects.haskell.org/pipermail/takusen/attachments/20100811/5efb8289/attachment.htm 


More information about the Takusen mailing list