将 state monad 添加到 haskell kv 数据库
adding state monad to the haskell kv database
在这里玩旧代码审查 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
首先,您的代码没有类型检查,所以我们只关注 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
显然这是行不通的,因为 get
和 put
正在与一对 (DB, r)
一起操作,但是您的类型签名说状态类型只是 DB
.
这里的r
是什么?你需要它吗? execCmd
的定义与类型签名一致:
execCmd :: Command -> State DB Result
execCmd (Set key val) = do
db@(DB map) <- get
let newMap = M.insert key val map
put (DB newMap)
return $ Result Nothing False
在这里玩旧代码审查 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
首先,您的代码没有类型检查,所以我们只关注 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
显然这是行不通的,因为 get
和 put
正在与一对 (DB, r)
一起操作,但是您的类型签名说状态类型只是 DB
.
这里的r
是什么?你需要它吗? execCmd
的定义与类型签名一致:
execCmd :: Command -> State DB Result
execCmd (Set key val) = do
db@(DB map) <- get
let newMap = M.insert key val map
put (DB newMap)
return $ Result Nothing False