Добавление монады состояний в базу данных haskell kv

Играя со старым кодом, обзор здесь простой-дб. и застрял, когда я добавил State Monad в него для дальнейшего сокращения кода.

Я почему-то чувствую, что делаю это неправильно. repl cmd = getCmd >>= execCmd cmd >>= displayResult >>= continue изменить интерфейс execCmd означает изменить все функции вдоль линии.

если я буду следовать этому подходу, как заставить его работать?

как правильно сделать предложенный рефакторинг, используя state Монада?

--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 ответ

Решение

Для начала, ваш код не проверяет тип, поэтому давайте просто сосредоточимся на первой части 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
Другие вопросы по тегам