Объединение монады состояний с распространением ошибок в любом стиле - PullRequest
6 голосов
/ 10 марта 2020

Я довольно новичок в Haskell. Я пытаюсь объединить Государственную монаду с распространением ошибок, рассматривая Либо как монаду. Я хотел бы использовать абстрактное синтаксическое дерево (например, для написания интерпретатора над операторами и выражениями) таким образом, что мне не нужно явно обрабатывать состояние или ошибки. У меня сложилось впечатление, что самый простой способ сделать это - использовать монадный преобразователь ExceptT. Вот мой пример кода, который компилируется:

import Control.Monad.Except
import Control.Monad.State
import qualified Data.Map.Strict as M

-- simple expression language supporting crude let bindings
data Exp = Lit Int | Var String
         | Add (Exp, Exp) | Let (String, Exp, Exp) deriving Show

okExp =  -- let x = 2 in let y = x + 3 in x + y -- evaluate to 7
    Let ("x", Lit 2,
             Let ("y", Add (Var "x", Lit 3),
                      Add (Var "x", Var "y")))
badExp = Var "x"  -- error: x is not defined

type St = M.Map String Int
initialState :: St
initialState = M.empty

type EvalMonad = ExceptT String (State St)

evalExp :: Exp -> EvalMonad Int
evalExp (Lit n) = return n
evalExp (Var v) = do
    mp <- lift get
    case M.lookup v mp of
        Just i -> return i
        Nothing -> throwError (v ++ " not found")
evalExp (Add (a, b)) = do
    x <- evalExp a
    y <- evalExp b
    return (x + y)

I wi sh для запуска evalExp на простых примерах (okExp, badExp, например). Я не уверен в трех вещах:

  1. Как получить начальное состояние в расчете?
  2. Как использовать runExceptT для извлечения результата?
  3. ( Гораздо более общий): это «правильный» способ решить эту проблему?

1 Ответ

3 голосов
/ 10 марта 2020

Похоже, отличное начало! Вот небольшой пример, показывающий, как использовать runExceptT и runState вместе в ghci:

> runState (runExceptT (evalExp (Add (Lit 3, Lit 4)))) initialState
(Right 7,fromList [])
> runState (runExceptT (evalExp (Add (Lit 3, Var "x")))) initialState
(Left "x not found",fromList [])
...