[Haskell-cafe] Newtype, Data.Text and instance declarations...

Guy-Laurent Subri guy-laurent at subri.ch
Fri Apr 12 04:40:34 UTC 2019


Hi all,

There are a few things that I don't understand involving Data.Text and
instance declarations...

I'm building a small web app to practise Haskell and am using the
SQLite.Simple library.

I have defined a few types and functions like so:

'''
data BookmarkDB = BookmarkDB Connection Table
newtype Table = Table Text
instance ToField Table where
    toField = SQLText

initDB :: FilePath -> Table -> IO BookmarkDB
initDB fp table = do
    let query = Query ("CREATE TABLE IF NOT EXISTS :table "
                    <> " (url TEXT, tags TEXT, date INTEGER)")
    conn <- open fp
    executeNamed conn query [":table" := table]
    return $ BookmarkDB conn table
'''

1. My first question is about the instance declaration. Why would
'''
instance ToField Table where
    toField = SQLText
'''

return this error ?
'''
Couldn't match type ‘Table’ with ‘Text’
      Expected type: Table -> SQLData
        Actual type: Text -> SQLData
    • In the expression: SQLText
      In an equation for ‘toField’: toField = SQLText
      In the instance declaration for ‘ToField Table’
'''

I've noticed that if I write
'''
instance ToField Table where
    toField (Table t) = SQLText t
'''

I have no error and it compiles. I don't get it, what is 'toField'
supposed to receive except a Table?

2. My second question is concerning the initDB function. If I write it
that way, the code compiles, but I get an error during execution:

bkmrk: SQLite3 returned ErrorError while attempting to perform prepare
"CREATE TABLE IF NOT EXISTS :table  (url TEXT, tags TEXT, date
INTEGER)": near ":table": syntax error

I don't understand what is wrong with the code and I doubt that my query
is wrong because everything works with the last code snippet I wrote
(see question #3).

3. Trying to get around the error I've noticed a few things. If I try to
write this instead:

'''
initDB :: FilePath -> Table -> IO BookmarkDB
initDB fp table = do
    let query = Query ("CREATE TABLE IF NOT EXISTS " <> table
                    <> " (url TEXT, tags TEXT, date INTEGER)")
    conn <- open fp
    execute_ conn query
    return $ BookmarkDB conn table
'''

it doesn't compile because table is of type Table and not
Data.Text.Internal.Text, which I get, but I don't know what is the
Haskell way of resolving this.

I've also noticed that this will help:

'''
initDB :: FilePath -> Table -> IO BookmarkDB
initDB fp t@(Table table) = do
    let query = Query ("CREATE TABLE IF NOT EXISTS " <> table
                    <> " (url TEXT, tags TEXT, date INTEGER)")
    conn <- open fp
    execute_ conn query
    return $ BookmarkDB conn t
'''

But I *really* don't get why! The most confusing part for me is that the
last initDB function will do exactly what I want it to do, but I am
unable to understand why it works...Why am I able to concatenate the
'table' now and not before and why is 't' of a different type than
'table'?

All of this is very confusing and I find myself unable to reason about
it. Sorry if this is a big/messy question. I hope everything is clear
enough to answer...

Thank you all!


More information about the Haskell-Cafe mailing list