Hvordan integrere / heis / injisere tilpasset monade stabel med HSpec?

stemmer
1

Kontekst

Jeg har noen monadiske funksjoner for en tolk som jeg prøver å teste med HSpec. De kjører med følgende monade stack:

type AppState = StateT InterpreterState (ExceptT Events IO)
type AppReturn a = Either Events (a, PState)

runApp :: AppState a -> IO (AppReturn a)
runApp f = runExceptT (runStateT f new)

Her er et eksempel på en enkel en:

mustEvalExpr :: Expr -> S.AppState (S.Value)
mustEvalExpr e = do
    val <- evalExpr e
    case val of
        Just val' -> return val'
        Nothing   -> throw $ S.CannotEval e

Problemet er at HSpec har sin egen kontekst ( IO ()), så jeg må oversette mellom de to sammenhenger.

Nåværende Approach

Jeg bruker HSpec, og jeg skrev en transformator funksjonen for å få en runAppsammenheng fra i HSpec sammenheng.

-- imports omitted

extract :: S.AppReturn a -> a
extract st = case st of
    Right (a, _) -> a
    Left ev      -> throw ev

run :: (S.AppReturn a -> b) -> S.AppState a -> IO b
run extractor fn = do
    state <- S.runApp fn
    return $ extractor state

Så min Specser slik ut:

spec :: Spec
spec = do
    describe mustEvalExpr $ do
        let badExpr = D.VarExpr $ D.Id doesntExist
            goodExpr = D.IntExpr 1
            val = S.IntValue 1

        it should evaluate and return expression if its a Just $ do
            (run extract $ do
                I.mustEvalExpr goodExpr
                ) >>= (`shouldBe` val)

        it should throw error if it gets a Nothing $ do
            (run extract $ do
                I.mustEvalExpr badExpr
                ) `shouldThrow` anyException

Spørsmål

Er dette det beste jeg kan gjøre? Jeg føler meg som run extract $ doer bra, og jeg tror det er bra å være eksplisitt når ting blir komplisert.

Men jeg lurte på om det var en måte jeg kan integrere med HSpec, eller om det er en beste praksis for dette problemet som ikke krever egendefinert kode?

Publisert på 19/03/2020 klokken 21:58
kilden bruker
På andre språk...                            

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more