11

まず、達成したいタスクの単純化されたバージョンです。複数の大きなファイル (30 GB に達する) があり、重複するエントリを取り除く必要があります。この目的のために、データのハッシュのデータベースを確立し、ファイルを 1 つずつ開き、各アイテムをハッシュし、ハッシュがまだデータベースにない場合はデータベースと出力ファイルに記録します。

私はこれを反復子、列挙子で行う方法を知っており、コンジットを試してみたかったのです。コンジットでそれを行う方法も知っていますが、今はコンジットと永続を使用したいと考えています。型に問題があり、おそらく の概念全体に問題がありますResourceT

問題を説明するための疑似コードを次に示します。

withSqlConn "foo.db" $ runSqlConn $ runResourceT $ 
     sourceFile "in" $= parseBytes $= dbAction $= serialize $$ sinkFile "out"

問題はdbAction機能にあります。当然、ここでデータベースにアクセスしたいと思います。それが行うアクションは基本的に単なるフィルターなので、最初は次のように書くことを考えました:

dbAction = CL.mapMaybeM p
     where p :: (MonadIO m, MonadBaseControl IO (SqlPersist m)) => DataType -> m (Maybe DataType)
           p = lift $ putStrLn "foo" -- fine
           insert $ undefined -- type error!
           return undefined

私が得る特定のエラーは次のとおりです。

Could not deduce (m ~ b0 m0)
from the context (MonadIO m, MonadBaseControl IO (SqlPersist m))
  bound by the type signature for
             p :: (MonadIO m, MonadBaseControl IO (SqlPersist m)) =>
                           DataType -> m (Maybe DataType)
  at tools/clean-wac.hs:(33,1)-(34,34)
  `m' is a rigid type variable bound by
      the type signature for
        p :: (MonadIO m, MonadBaseControl IO (SqlPersist m)) =>
                      DataType -> m (Maybe (DataType))
      at tools/clean-wac.hs:33:1
Expected type: m (Key b0 val0)
  Actual type: b0 m0 (Key b0 val0)

これは、型シグネチャを設計する際に行った間違った仮定が原因である可能性があることに注意してください。型シグネチャをコメントアウトし、liftステートメントも削除すると、エラー メッセージは次のようになります。

No instance for (PersistStore ResourceT (SqlPersist IO))
  arising from a use of `p'
Possible fix:
  add an instance declaration for
  (PersistStore ResourceT (SqlPersist IO))
In the first argument of `CL.mapMaybeM', namely `p'

つまり、これは?PersistStore経由でまったくアクセスできないことを意味します。ResourceT

を使用せずに、独自のコンジットを作成することもできませんCL.mapMaybeM

dbAction = filterP
filterP :: (MonadIO m, MonadBaseControl IO (SqlPersist m)) => Conduit DataType m DataType
filterP = loop
    where loop = awaitE >>= either return go
          go s = do lift $ insert $ undefined -- again, type error
                    loop

これにより、完全には理解できないさらに別の型エラーが発生しました。

Could not deduce (m ~ b0 m0)
from the context (MonadIO m, MonadBaseControl IO (SqlPersist m))
  bound by the type signature for
             filterP :: (MonadIO m,
                                 MonadBaseControl IO (SqlPersist m)) =>
                                Conduit DataType m DataType
     `m' is a rigid type variable bound by
      the type signature for
        filterP :: (MonadIO m,
                            MonadBaseControl IO (SqlPersist m)) =>
                           Conduit DataType m DataType
Expected type: Conduit DataType m DataType
  Actual type: Pipe
                 DataType DataType DataType () (b0 m0) ()
In the expression: loop
In an equation for `filterP'

だから、私の質問は、コンジット内で意図したように永続的に使用することは可能ですか? もし、どうやって?liftIOコンジット内で使用できるので、たとえば を使用するだけでよいことは承知していますHDBCが、永続化がどのように機能するかを理解するために明示的に永続化を使用したいと考えていました。

4

1 に答える 1

7

以下のコードは、私にとっては問題なくコンパイルされます。フレームワークがその間に移動し、物事がうまく機能する可能性はありますか?

ただし、世界が少し変わったか、すべてのコードを持っていなかったため、次の変更を行う必要があったことに注意してください。GHC 7.6.3でconduit-1.0.9.3とpersistent-1.3.0を使用しました。

  • 省略parseBytesserialise、私はあなたの定義を持っていないので、DataType = ByteString代わりに定義しました。

  • 型ファミリの単射性の問題を回避するために、Proxyパラメーターと値の明示的な型シグネチャを導入しました。undefinedこれらは、実際のコードでは発生しない可能性がありますval

  • 中古awaitではなく、そのままケース代わりのタイプとしてawaitE使用され、引退しました。()LeftawaitE

  • ダミーのConnection作成関数をに渡しましたwithSqlConn-おそらく、Sqlite 固有の関数を使用する必要がありましたか?

コードは次のとおりです。

{-# LANGUAGE FlexibleContexts, NoMonomorphismRestriction,
             TypeFamilies, ScopedTypeVariables #-}

module So133331988 where

import Control.Monad.Trans
import Database.Persist.Sql
import Data.ByteString
import Data.Conduit
import Data.Conduit.Binary
import Data.Proxy

test proxy =
    withSqlConn (return (undefined "foo.db")) $ runSqlConn $ runResourceT $ 
         sourceFile "in" $= dbAction proxy $$ sinkFile "out"

dbAction = filterP

type DataType = ByteString

filterP
    :: forall m val
     . ( MonadIO m, MonadBaseControl IO (SqlPersist m)
       , PersistStore m, PersistEntity val
       , PersistEntityBackend val ~ PersistMonadBackend m)
    => Proxy val
    -> Conduit DataType m DataType
filterP Proxy = loop
    where loop = await >>= maybe (return ()) go
          go s = do lift $ insert (undefined :: val)
                    loop
于 2014-01-02T07:37:38.540 に答える