Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 使用免费monad测试Redis调用_Haskell_Monad Transformers_State Monad_Free Monad - Fatal编程技术网

Haskell 使用免费monad测试Redis调用

Haskell 使用免费monad测试Redis调用,haskell,monad-transformers,state-monad,free-monad,Haskell,Monad Transformers,State Monad,Free Monad,我试图通过使用免费monad将Redis请求的执行与使用分开。为了使用hedis作为Redis客户端,我对提供的代码做了一些小的更改,这些更改似乎是类型检查。不幸的是,我无法找到或编写满足runTest和runRedis函数的类型约束的类型类实例,并且在使用foo调用runTest时出现以下错误 No instance for (Control.Monad.State.Class.MonadState FakeDB IO) 存储/类型.hs {-# LANGUAGE TemplateHaske

我试图通过使用免费monad将Redis请求的执行与使用分开。为了使用hedis作为Redis客户端,我对提供的代码做了一些小的更改,这些更改似乎是类型检查。不幸的是,我无法找到或编写满足runTest和runRedis函数的类型约束的类型类实例,并且在使用foo调用runTest时出现以下错误

No instance for (Control.Monad.State.Class.MonadState FakeDB IO)
存储/类型.hs

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}

module Storage.Types where

import Control.Monad.Free
import Control.Monad.Free.TH

data RedisCmd next = Get' String (Maybe String -> next) |
                     Set' String String next      |
                     Multi' (RedisCmdM ()) next deriving (Functor)

type RedisCmdM = Free RedisCmd

makeFree ''RedisCmd
存储/实现.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE UndecidableInstances #-}

module Storage.Implementations where

import Control.Monad.State
import Control.Monad.State.Class
import Control.Monad.Free
import Control.Monad.Free.TH
import Data.Functor
import Data.Map (Map)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as C8
import qualified Data.Map as M
import qualified Database.Redis as R
import Storage.Types

runDebug :: RedisCmdM a -> IO a
runDebug = iterM run
  where
    run :: RedisCmd (IO a) -> IO a
    run (Get' k f) = do
      putStrLn $ unwords ["GET", k]
      f . Just =<< getLine
    run (Set' k v n) = do
      putStrLn $ unwords ["SET", k, v]
      n
    run (Multi' txn n) = do
      putStrLn "MULTI"
      runDebug txn
      putStrLn "EXEC"
      n

-- newtype FakeDB = FakeDB { insideFDB :: Map String String }
type FakeDB = Map String String

-- instance (MonadIO m) => MonadState R.Connection m where
--   get = lift get
--   put = lift . put

runTest :: MonadState FakeDB m => RedisCmdM a -> m a
runTest = iterM run
  where
    run (Get' k f) = f =<< gets (M.lookup k)
    run (Set' k v n) = do
      modify $ M.insert k v
      n
    run (Multi' txn n) = do
      runTest txn
      n

getC :: R.Connection -> String -> IO (Maybe String)
getC c k = R.runRedis c (getRedis k)

getRedis :: String -> R.Redis (Maybe String)
getRedis k = convert <$> (R.get . C8.pack) k
  where
   convert (Left _)  = Nothing
   convert (Right r) = C8.unpack <$> r

setC :: R.Connection -> String -> String -> IO ()
setC c k v = do
  _ <- R.runRedis c $ R.set (C8.pack k) (C8.pack v)
  return ()

multi :: R.Connection -> (RedisCmdM ()) -> IO ()
multi = undefined

db :: IO R.Connection
db = R.connect R.defaultConnectInfo

runRedis :: (MonadState R.Connection m, MonadIO m) => RedisCmdM a -> m a
runRedis rcmd = withConn $ \c -> (iterM (run c) rcmd)
  where
    run :: R.Connection -> RedisCmd (IO a) -> IO a
    run c (Get' k f) = f =<< getC c k
    run c (Set' k v n) = setC c k v >> n
    run c (Multi' txn n) = undefined --multi c txn >> n
    withConn action = liftIO (join (action <$> db))
{-#语言灵活上下文}
{-#语言类型同义词实例}
{-#语言不可判定实例}
模块存储。实现在哪里
进口控制单体状态
导入控制.Monad.State.Class
进口管制,不含单子
进口管制.Monad.Free.TH
导入数据。函子
导入数据.Map(Map)
导入Data.ByteString(ByteString)
将符合条件的Data.ByteString.Char8导入为C8
导入符合条件的数据。映射为M
将符合条件的数据库.Redis作为R导入
导入存储类型
runDebug::RedisCmdM a->IO a
runDebug=itermrun
哪里
运行::RedisCmd(IO a)->IO a
跑(得到k f)=做
putStrLn$unwords[“GET”,k]
FJust=单数据状态R.连接m,其中
--得到
--放=举。放
runTest::MonadState FakeDB m=>RedisCmdM a->ma
runTest=iterM运行
哪里
运行(获取'kf)=f=String->IO(可能是String)
getC k=R.runRedis c(getRedis k)
getRedis::String->R.Redis(可能是String)
getRedis k=convert(R.get.C8.pack)k
哪里
转换(左)=无
转换(右r)=C8
setC::R.连接->字符串->字符串->IO()
setC v=do
_(RedisCmdM())->IO()
多重=未定义
db::IO R.连接
db=R.connect R.defaultConnectInfo
runRedis::(MonadState R.Connection m,MonadIO m)=>RedisCmdM a->ma
runRedis rcmd=withConn$\c->(iterM(run c)rcmd)
哪里
运行::R.连接->RedisCmd(IO a)->IO a
运行c(获取'kf)=f=>n
withConn动作=liftIO(连接(动作db))
Main.hs

{-# LANGUAGE OverloadedStrings #-}

import Storage.Types
import Storage.Implementations (runDebug, runTest, runRedis)

foo :: RedisCmdM ()
foo = do
  mv <- get' "foo"
  case mv of
    Nothing -> return ()
    Just v -> multi' $ do
      set' "foo1" v
      set' "foo2" v

main = do
  runTest foo
{-#语言重载字符串}
导入存储类型
导入存储。实现(runDebug、runTest、runRedis)
foo::RedisCmdM()
foo=do

mv查看
runTest
的类型签名:只要
m
MonadState FakeDB
,它就会在monad
m
中返回一个值。因此,当您调用runTest时,您需要将它绑定到这样一个monad中,
IO
不是(这就是错误消息告诉您的)。尝试
runStateT(runTest foo)Map.empty
(它在其第一个参数中创建了这样一个一元上下文)。

查看
runTest
的类型签名:只要
m
MonadState FakeDB,它就会在monad
m
中返回一个值。因此,当您调用
runTest
时,您需要将它绑定到这样一个monad中,而
IO
不是(这就是错误消息告诉您的)。请尝试
runStateT(runTest foo)Map.empty
(它在第一个参数中创建了这样一个一元上下文)。感谢您的解释@luqui,您的建议确实有效。@luqui既然您的评论解决了问题,您介意将其作为答案发布吗?