2013-02-23 11 views
8

Tôi đã cố gắng tìm ra một cách đơn giản và trực quan để sử dụng cơ sở dữ liệu với Haskell. Tôi đã lấy mã này từ số Yesod book và cố gắng xóa nó để dễ hiểu và dễ sử dụng hơn.Haskell/Persistent-Sqlite: "Không có trường hợp nào cho (Control.Monad.Trans.Resource.MonadResource IO)"

{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings #-} 
{-# LANGUAGE GADTs, FlexibleContexts #-} 

import Database.Persist 
import Database.Persist.Sqlite (withSqliteConn, runSqlConn, runMigration) 
import Database.Persist.TH (share, mkPersist, mkMigrate, sqlSettings, persist) 

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persist| 
Person        -- Table name 
    name String      -- String value 
    age Int Maybe     -- Numerical value 
|] 

updateDB x y = withSqliteConn "data.db" $ runSqlConn $ do 
    runMigration migrateAll   -- Creates "Person" table if one doesn't exist 
    insert $ Person x $ Just y  -- Inserts values into .db file 

main = do 
    updateDB "Frank Silver" 40  -- adds name "Frank Silver" and age "40" to data.db file 

Mã này gần công trình, nhưng tôi nhận được lỗi sau đây mà tôi đã không thể giải quyết.

No instance for (Control.Monad.Trans.Resource.MonadResource IO) 
     arising from a use of `updateDB' 
    Possible fix: 
     add an instance declaration for 
     (Control.Monad.Trans.Resource.MonadResource IO) 
    In a stmt of a 'do' block: updateDB "Frank Silver" 40 
    In the expression: do { updateDB "Frank Silver" 40 } 
    In an equation for `main': main = do { updateDB "Frank Silver" 40 } 

Mọi đề xuất chỉ tôi đi đúng hướng sẽ được đánh giá cao.

+1

Bạn cần ít nhất một 'runResourceT' xung quanh' updateDB' trong 'main'. Tôi không chắc liệu điều đó có đủ hay không. –

+0

viết lại dòng như runResourceT $ updateDB "Frank Silver" 40 đã hoạt động! Cảm ơn bạn. Có thể bạn muốn đăng nhận xét của mình dưới dạng câu trả lời? –

+4

Tôi đã có vấn đề này bằng cách sử dụng liên tục là tốt, nhưng tôi cũng đã có một lỗi với một trường hợp của MonadLogger cho IO mất tích. Tôi để nó ở đây với hy vọng nó giúp một số linh hồn nghèo khác. Điều quan trọng là sử dụng 'runResourceT '. Control.Monad.Logger.runNoLoggingT', như trường hợp cho MonadLogger IO đã được gỡ bỏ. – Khanzor

Trả lời

8

Với

main = do 
    updateDB "Frank Silver" 40 

loại updateDB "Frank Silver" 40 được suy ra được IO(), vì đó là loại mặc định cho main (nó phải có loại IO a đối với một số a). Nhưng từ định nghĩa, loại của nó được suy ra là MonadRescource m => m a đối với một số a (có lẽ là a =(), nhưng tôi không chắc chắn) và không có instance MonadResource IO. Vì vậy, bạn cần một cái gì đó để chuyển đổi updateDB đến một hành động IO, theo cách thông thường để làm điều đó là runResourceT, mà biến đổi một ResourceT m a thành một m a (ở đây m = IO), do đó

main = runResourceT $ updateDB "Frank Silver" 40 

công trình.

+0

Tôi đã sử dụng Haskell gần một năm và vẫn đang học cách sử dụng hệ thống kiểu. : D Cảm ơn một lần nữa vì sự giúp đỡ và trả lời của bạn. –