Search
Tag Archive
« IBM and Sun - A Cloud Play? | Main | Why I prefer Twitter over Plurk »
11:49PM

The Haskell Experiment: HaskellDB, HTTP, and Monads

It's day two of my Haskell experiment and I've got a brain full of functional programming goodness. For one thing, I think nothing is better when learning a new programming language than trying it out on a real-world project. So far, in one whole day of moving forward at snail-pace steps, I am definitely thankful that I've invested a lot more time in learning Haskell today than doing anything else. This post contains lots of tidbits I've learned along the way regarding dealing with databases, using an HTTP client library, and getting used to the concept of a Monad.

Databases

Let's say you already have an existing database and you'd like to deal with the data that's available there. And let's say you have tons and tons of data in a database that's accessed by programs in another programming language. Do you deal with SQL when doing Haskell programming and worry about maintaining SQL and Haskell code? Sure you could... But why, when you have such a nice database library package that abstracts the underlying SQL code for you in its own Domain Specific Embedded Language?

Yes, you can deal with Haskell objects from the database in your program without having to think about the SQL. All you have to do is:

cabal install HDBC HDBC.ODBC HaskellDB

And once it's downloaded and installed in your local cabal store, you can start enjoying the exquisite means of dealing with data from databases from Haskell.

Note: You may have to install and configure ODBC for your system. If you're like me and developing/testing on Linux, you're going to want to go ahead and read up on manuals for installing and configuring Unix ODBC and the ODBC adapters for your favorite RDBMS.

Let's say you have a database called 'database' and for example you work for 'Copmany X'. If you want to create modules for Haskell to be easily used with HaskellDB, you can go ahead and do the following:

import Database.HaskellDB
import Database.HaskellDB.DBSpec.DBSpecToDBDirect
import Database.HaskellDB.DBSpec
import Database.HaskellDB.HDBC.ODBC
import Database.HaskellDB.DBSpec.PPHelpers

withDB dsn = (connect driver) [ ("dsn",dsn) ]

main =
    do db_info <-
            withDB "database" $ \db -> dbToDBSpec False mkIdentPreserving "database" db 
         dbInfoToModuleFiles "" "CompanyX.Data" db_info
         putStrLn "Ok!"

And that's pretty much it. HaskellDB will then create the Haskell module files you want/need to have to be able to deal with the data that's already in your database. It will introspect your database structure and create the table representations for you. It will even place it in a module named "CompanyX.Data" for you!

That ladies and gentlemen is the first step. Somehow you'll want to deal with your data so you'll probably want to see an example. I might have to write that example some other time, but to give you a teaser let's say you have a table named 'Messages' and you want to find an entries given a certain source. Your query would pretty much look like this:

getMessages :: Int -> Database -> IO [(Int, String, String)]
getMessages src =
    do  let q = do
               t <- table CopmanyX.Data.Messages.messages
               restrict ( (t!source) .==. (constant src) )
               order [asc t date]
               return t
          rs <- query db q
          return $ map (\x -> ((x!dest),(x!subject),(x!messages))) rs
 

Absolutely no SQL necessary on your part. Isn't that cool?

Monads

I'd probably not be the first one to say this, but I had some trouble understanding what Monads are. And once I stop reading the high-level documentation and just think about it, I think I've gotten the realization that monads are means of expressing sequence, state, or side effects in Haskell. It's a mechanism which allows for mathematically expressing the notion of state and mutation of state in a purely functional programming language.

If I may say so myslef, I think this is just brilliant. Doing a context switch between monadic thinking and pure functional programming thinking doesn't take much because all you're doing even when dealing with monads is just applying a function and modifying a context in sequence. The good part is, monads can call pure functions but pure functions can't call mondas (or so I think) so now you can decompose your problems into parts which interact with the outside world (literally, Input/Output) and those that stay in the functional world. I just think it's brilliant.

Whoever invented the notion of monads should be given a prize for Mathematics and/or Computer Science!

Anyway, continuing on, the simplest monadic function we can deal with is the main function:

main = return ()

Notice here that we did not do anything and that's by design. For instance we want to do the typical "Hello, World!" program C-style:

main = putStrLn "Hello, World!"

That's not much, but believe me, it gets a lot better.

HTTP

So let's say you want to impress your friends and want to pull your blog's front page and dump it out to the screen. How do we do it? Simple:

import Network.HTTP
import Network.URI
import Data.Maybe

main =
  do
      resp <- simpleHTTP request
      case resp of
        Left x -> printStrLn ("Error connecting: " ++ show x)
        Right r ->
          case rspCode r of
            (2,_,_) -> printStrLn ( rspBody r )
            _ -> printStrLn ("Got response status other than 2XX!")
  where request = Request {
                                 rqURI = uri,
                                 rqMethod = GET,
                                 rqHeaders = [],
                                 rqBody = ""
                              } 
             uri = fromJust $ parseURI "http://www.deanberris.com/"

And that's it!

Imagine the kinds of things you can do with this, and quickly you'll see that the succinctness of the code and the stuff you can layer on top of each other is definitely surprising.

What I learned

So not only is Haskell powerful as a functional programming language, but it's also one of those programming languages with great libraries -- and for good reason I think. The community that forms around Haskell is a community which almost always has good ideas and I think are capable enough to execute at a high level. Considering that Haskell takes a while to grasp and master, only a handful of those determined will definitely be able to survive and excel.

I think I'm definitely at home with functional programming -- for some reason, now that my brain has been rewired I start thinking about solving larger problems in a functional programming mindset. May it be Haskell or C++, I'm definitely going to start thinking more in functional programming terms.

Update: Added missing parts in HTTP example.

Reader Comments (4)

> The good part is, monads can call pure functions but pure functions can't call
> mondas (or so I think) so now you can decompose your problems into parts
> which interact with the outside world (literally, Input/Output) and those that
> stay in the functional world.
Actually, pure functions can call into monadic code -- it depends on which monad is used. You can't hide the use of IO, for example, but you can implement pure functions using Maybe, Get, State, or other monads easily.

March 18, 2009 | Unregistered CommenterName

How would it handle the work when you would have used a 'join' in an sql statement?

March 18, 2009 | Unregistered CommenterAnonymous

@Anonymous:

It does the join in the database.

The query monad basically just builds up a SQL query for you, kind of like LINQ.

March 19, 2009 | Unregistered CommenterEdward Kmett

And once I stop reading the high-level documentation and just think about it, I think I've gotten the realization that monads are means of expressing sequence, state, or side effects in Haskell.

Nope. Everyone goes through that misconception though.

March 21, 2009 | Unregistered CommenterJam

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>