将状态monad添加到haskell kv数据库

时间:2016-06-02 15:44:48

标签: haskell state-monad

在此处使用旧代码审核simple-db。当我将State Monad添加到其中以进一步减少代码时卡住了。

我不知何故觉得我没有正确地做到这一点。 repl cmd = getCmd >>= execCmd cmd >>= displayResult >>= continue更改execCmd的界面意味着更改该行的所有功能。

如果我遵循这种方法,如何让它发挥作用?

使用state Monad进行建议重构的正确方法是什么?

--import qualified
import Data.Map as M
import Control.Monad.State

type History = [String]

data Result = Result (Maybe String) Bool

data Command = Invalid | End | Get String | Set String String
data DB = DB (M.Map String String)


execCmd :: Command -> State DB Result
execCmd (Set key val) = do
  (db@(DB map), r) <- get
  let newMap = M.insert key val map
  put ((DB newMap), r)
  return $ Result Nothing False 
execCmd (Get key) = do
  (db@(DB map), r) <- get
  return $ Result (M.lookup key map) False 
execCmd End = do
  return $ Result Nothing True 
execCmd Invalid = do
  return $ Result Nothing False 

getCmd = getLine >>= return . parseCmd

parseCmd :: String -> Command
parseCmd s =
  case words s of
    ("set":key:value:_) -> Set key value
    ("get":key:_)       -> Get key
    ("end":_)           -> End
    _                   -> Invalid

displayResult :: Result -> IO Result
displayResult r@(Result (Just s) _ ) = putStrLn s >> return r
displayResult r                      = return r

continue :: Result -> IO ()
continue (Result _ end) = if end then return () else repl 

repl cmd = getCmd >>= execCmd cmd >>= displayResult >>= continue

startState = ((DB M.empty), (Result Nothing False))

--main = repl Invalid 

1 个答案:

答案 0 :(得分:1)

对于初学者,您的代码不会进行类型检查,因此我们只关注execCmd的第一部分:

execCmd :: Command -> State DB Result
execCmd (Set key val) = do
  (db@(DB map), r) <- get
  let newMap = M.insert key val map
  put ((DB newMap), r)
  return $ Result Nothing False

显然,这不起作用,因为getput正在使用(DB, r)对进行操作,但您的类型签名表明状态类型只是{{1} }}

这里DB是什么?你需要它吗? r的定义与类型签名一致:

execCmd