2

モナドを効率的に操作することに関しては、まだ「そこ」に達していないことを認めなければならないので、これが簡単な質問である場合はご容赦ください。また、この質問は私が現在取り組んでいる実際の実装よりも概念に関連しているため、動作するコードを提供していないことをお詫びする必要があります。

私は SQLite(3) データベースに対して作業を行っています。もちろん、それにクエリを送信して結果を取得したいと考えています。すでに IO にあるため、関数は変換が必要な をfetchAllRows返します。[[SqlValue]]SQLite はテキストと浮動小数点値に関して非常にリベラルであるため (Haskell は型に関してはまったくリベラルではありません)、安全な変換を使用するのsafeFromSqlが適切と思われます。さて、これらすべてを 1 つの関数で行うことができた場合、その関数は次のようになります。

myfunc :: String -> [SqlValue] -> IO [[ Either ConvertError a]]

またはそのようなものですよね?ネストされたモナドの構造を扱うことは、私が気付いていない作業を容易にする標準的な方法があるほど一般的である(そして十分に面倒である)ように思えますか?

4

1 に答える 1

0

問題は、いくつかの特定の関数によってのみ解決されるようで、最も明確なのは do 構文です。以下の関数は、SQLite データベースへの direct-sqlite3 パッケージ アクセスの問題を解決します (また、REGEXP ハンドラーを挿入します)。

import Text.Regex.Base.RegexLike
import qualified Text.Regex.PCRE.ByteString as PCRE
import qualified Data.ByteString as BS
import Data.Text (pack,Text,append)
import Data.Text.Encoding (encodeUtf8)
import Data.Int (Int64)
import Database.SQLite3

pcreRegex :: BS.ByteString -> BS.ByteString -> IO Int64
pcreRegex reg b = do
    reC <- pcreCompile reg
    re <- case reC of
        (Right r) -> return r
        (Left (off,e) ) -> fail e
    reE <- PCRE.execute re b
    case reE of
        (Right (Just _)) -> return (1 :: Int64)
        (Right (Nothing)) -> return (0 :: Int64)
        (Left (c,e)) -> fail e -- Not a good idea maybe, but I have no use for error messages.
    where pcreCompile = PCRE.compile defaultCompOpt defaultExecOpt



sqlRegexp :: FuncContext -> FuncArgs -> IO ()
sqlRegexp ctx args = do
    r <- fmap encodeUtf8 $ funcArgText args 0
    t <- fmap encodeUtf8 $ funcArgText args 1
    res <- pcreRegex r t
    funcResultInt64 ctx res 

getRows :: Statement -> [Maybe ColumnType] -> [[SQLData]] -> IO [[SQLData]]
getRows stmt coltypes acc = do
  r <- step stmt
  case r of
    Done -> return acc
    Row -> do
      out <- typedColumns stmt coltypes
      getRows stmt coltypes (out:acc)


runQuery q args columntypes dbFile = do
    conn <- open $ pack dbFile
    createFunction conn "regexp" (Just 2) True sqlRegexp
    statement <- prepare conn q
    bind statement args
    res <- fmap reverse $ getRows statement (fmap Just columntypes) [[]]
    Database.SQLite3.finalize statement
    deleteFunction conn "regexp" (Just 2) 
    close conn
    return $ res

これが誰かに役立つことを願っています。

于 2016-06-03T10:48:57.090 に答える