2014-10-10 46 views
1

我試圖創建一個網站,它將通過URL路徑獲取信息,然後將此信息傳遞到HDBC SQLITE3數據庫。我已經想出瞭如何使用Scotty通過參數獲取信息,以及如何使用HDBC創建數據庫。但是我無法將參數信息傳遞給數據庫。我得到這個錯誤:(對不起,這樣的初學者的問題,我只用哈斯克爾約3個星期)Scotty以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),但是您給出的簽名不提供該保證(a0a1可以是任何類型)。

最簡單的選擇是刪除createUserDB的類型簽名,並讓編譯器推斷它。或者,也可以將其限制爲Text值(因爲nameuserIdText類型和Database.HDBC.SqlValue限定實例爲Convertible Text SqlValue):

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

通常還可以使用在功能簽名的上下文來限制類型:

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

但這可能不是一個好主意,其中類型顯然是SQL字符串,可能映射到varchars。

+0

感謝您的幫助,它在刪除類型簽名時有效。這不就是不正確嗎? – 2014-10-11 03:41:32

+1

可以在發展中刪除簽名_例如,向編譯器詢問最常用的簽名是什麼或避免不斷地改變它們。但是通常應該在發佈之前添加它們,至少在導出的函數上添加它們。 – 2014-10-11 10:17:24

+1

它也可以使用簽名的「文本」版本,所以你可以使用它(確保你導入了'Data.Text.Lazy(Text)')。如果使用'-Wall'選項進行編譯,當離開沒有類型簽名的頂層定義(例如上面的'databaseFilepath')時,ghc會發出警告。像'hlint'這樣的工具也很有用。 – 2014-10-11 14:08:07