2014-10-10 7 views
1

Я пытаюсь создать веб-сайт, который получит информацию через URL-маршруты, а затем передаст эту информацию в базу данных HDBC SQLITE3. Я выяснил, как получить информацию через параметры с помощью Скотти, а также как создать базу данных с использованием HDBC. Но мне трудно передать информацию о параметрах в базу данных. Я получаю эту ошибку: (извините за такую ​​проблему новичка, я только использую Haskell около трех недель)Скотти Параметры для подачи в Sqlite3

Controllers/Home.hs:51:48: 
No instance for (Convertible a0 SqlValue) 
    arising from a use of `toSql' 
Possible fix: 
    add an instance declaration for (Convertible a0 SqlValue) 
In the expression: toSql 
In the expression: toSql $ userId 
In the third argument of `run', namely 
    `[toSql $ userId, toSql $ name]' 

Controllers/Home.hs:51:64: 
No instance for (Convertible a1 SqlValue) 
    arising from a use of `toSql' 
Possible fix: 
    add an instance declaration for (Convertible a1 SqlValue) 
In the expression: toSql 
In the expression: toSql $ name 
In the third argument of `run', namely 
    `[toSql $ userId, toSql $ name]' 

Вот код, который я пытаюсь запустить:

import Control.Monad 
import Web.Scotty (ScottyM, ActionM, get, html, param) 
import Data.Monoid (mconcat) 
import Database.HDBC 
import Database.HDBC.Sqlite3 
import Control.Monad.Trans (MonadIO(liftIO)) 
import Data.Convertible 
createUser :: ScottyM() 
createUser = get "/create/user/:userId/:name" $ do 
    name <- param "name" 
    userId <- param "userId" 
    liftIO $ createUserDB name userId 
    html $ mconcat ["<p>/create/user/" , userId , "/" , name ,"</p>"] 
createUserDB :: a1 -> a0 -> IO() 
createUserDB name userId = do 
    conn <- connectSqlite3 databaseFilePath 
    run conn "INSERT INTO users VALUES (? , ?)" [toSql $ userId, toSql $ name] 
    commit conn 
    disconnect conn 
databaseFilePath = "data/mydb.db" 

Если кто-то может указать, как исправить это, а также , почему их исправление работает, это было бы очень полезно!

ответ

1

Я думаю, что компилятор жалуется, потому что код требует, чтобы аргументы createUserDB удовлетворяют ограничение в сообщении об ошибке (т.е. что они могут быть конвертированы в Sqlvalue), но подпись вы дали не дает гарантии, что (a0 и a1 может быть любого типа).

Самый простой вариант - удалить подпись типа для createUserDB и просто дать компилятору сделать вывод. В качестве альтернативы вы можете ограничить его Text значений (так как name и userId имеют тип Text и Database.HDBC.SqlValue определяет экземпляр для Convertible Text SqlValue):

createUserDB :: Text -> Text -> IO() 

В общем, вы можете также использовать контекст в подписи функции для ограничения типов:

createUserDB :: (Convertible a0 SqlValue, Convertible a1 SqlValue) => a1 -> a0 -> IO() 

, но это, вероятно, не отличная идея здесь, где типы явно SQL строка и, вероятно, сопоставляются с типом VARCHAR.

+0

Благодарим вас за помощь, она работает при удалении подписей типа. Разве это не слишком само по себе? –

+1

Это нормально, чтобы удалить подписи _while develop_, например. спросить у компилятора, что такое самая общая подпись, или не менять их постоянно. Но вы должны добавить их перед выпуском, по крайней мере, на экспортированные функции. –

+1

Он также будет работать с версией «Text» подписи, поэтому вы можете просто использовать ее (убедитесь, что вы импортируете «Data.Text.Lazy (Text)»). Если вы скомпилируете параметр '-Wall', ghc выдаст предупреждение, когда вы оставите определение верхнего уровня без сигнатуры типа (например,' databaseFilepath' выше). Также полезны такие инструменты, как 'hlint'. –