[Haskell-cafe] Using Template Haskell to make type-safe database access

Mads Lindstrøm mads_lindstroem at yahoo.dk
Thu May 8 11:32:25 EDT 2008


Hi Wouter,

Wouter Swierstra wrote:

> Nice! I have to admit, it's much nicer than I expected it to be. Just  
> out of curiousity, what happens when you write:
> 
> selectTupleList :: Connection -> IO [Integer]
> 
> instead of
> 
> selectTupleList :: Connection -> IO [(Integer, String, String)]
> 
> What kind of error message do you get? More specifically, is this  
> error caught statically or dynamically.

The type annotation in UseSqlExpr.hs was just for the reader. The
compiler can infer the types completely. Thus when I make the suggested
change I get a compile time error. It looks like this:

UseSqlExpr.hs:27:6:
    Couldn't match expected type `Integer'
           against inferred type `(Integer, String, String)'
      Expected type: IO [Integer]
      Inferred type: IO [(Integer, String, String)]
    In the expression:
        (return
       $ (map
            (\ [x0[a2ZY], x1[a2ZZ], x2[a300]]
                 -> (readInteger x0[a2ZY],
                     readString x1[a2ZZ],
                     readString x2[a300]))
            rows[a2ZX]))
    In the expression:
        do rows[a2ZX] <- fetchRows
                           dsn[a2ZW]
                           ['S', 'E', 'L', 'E', 'C', 'T', ' ', 'u', 's', 'e', 'r', '_', 'i',
                            'd', ',', ' ', 'u', 's', 'e', 'r', '_', 'n', 'a', 'm', 'e', ',',
                            ' ', 'u', 's', 'e', 'r', '_', 'r', 'e', 'a', 'l', '_', 'n', 'a',
                            'm', 'e', ' ', 'F', 'R', 'O', 'M', ' ', 'u', 's', 'e', 'r', ';']
           (return
          $ (map
               (\ [x0[a2ZY], x1[a2ZZ], x2[a300]]
                    -> (readInteger x0[a2ZY],
                        readString x1[a2ZZ],
                        readString x2[a300]))
               rows[a2ZX]))
make: *** [all] Fejl 1

> 
> The only other limitation I can think of, would be in the situation  
> where you don't have compile-time access to the database, e.g.  
> developing software for a client with a database that can only be  
> accessed from their intranet. I have no idea how much of a limitation  
> that is.

True, but this limitation is only relevant when you do not have access
to the production database or a database with identical metadata. How
often do people develop like that? How are they testing? I have a hard
time picturing a setup without a test database with identical metadata
to the production database.

> >> Perhaps I should explain my own thoughts on the subject a bit better.
> >> I got interested in this problem because I think it makes a nice
> >> example of dependent types "in the real world" - you really want to
> >
> > But won't you end up implementing all the functionality of an SQL
> > parser? While possible, it does seem like a huge job. With a TH  
> > solution
> > you will safe a lot of work.
> 
> Yes - but parsing the result of an SQL describe statement is pretty  
> easy.
ok.

> 
> > A library that
> > will be a lot more complex to learn than what I am proposing (assuming
> > the developer already knows SQL).
> 
> Hmm. This is a rather sticky point. One might also argue that Haskell  
> developers have to learn SQL to use the solution you propose. I'm not  
> particularly convinced. Both approaches have their merits I think.

Yes. I was _not_ making what you could call a strong argument. I was
assuming that most (Haskell) developers knew SQL anyway. I have no data
to back it up. Just my gut feeling.

To be fair I should mention a couple of drawbacks with the TH-based
approach. While SQL got static typing, it is not really as powerful as
it could be. For example if you do "select sum(...) from ..." the type
system will tell you that a set of values are returned. In reality this
set will never have more than one member. Your proposal would be able to
return a Float in stead of a [Float].

Another advantage your proposal (and disadvantage of the TH based one)
would be that it can abstract over variances in different database
implementation. That is, you could translate to SQL depending on SQL
backend. This would be really nice. But I guess it would also be a big
task.

> 
> Anyhow - nice work! Have you asked Bjorn Bringert what he thinks? He's  
> a really clever and approachable guy - and he knows a lot more about  
> interfacing with databases than I do.
> 
> Kind regards,
> 
>    Wouter

/Mads Lindstrøm





More information about the Haskell-Cafe mailing list