鉴于我有以下 DSL(使用 Free Monad)及其解释器:
data MyDslF next =
GetThingById Int (Thing -> next)
| Log Text next
type MyDslT = FT MyDslF
runMyDsl :: (MonadLogger m, MonadIO m, MonadCatch m) => MyDslT m a -> m a
runMyDsl = iterT run
where
run :: (MonadLogger m, MonadIO m, MonadCatch m) => MyDslF (m a) -> m a
run (Log message continue) = Logger.log message >> continue
run (GetThingById id' continue) = SomeApi.getThingById id' >>= continue
我想在内部更改解释器以使用 MonadState ,以便如果 aThing
已经为给定检索到Id
,则没有第二次调用SomeApi
假设我已经知道如何使用get
and编写记忆版本put
,但我遇到的问题是在MonadState
内部运行runMyDsl
。我在想解决方案看起来类似于:
type ThingMap = Map Int Thing
runMyDsl :: (MonadLogger m, MonadIO m, MonadCatch m) => MyDslT m a -> m a
runMyDsl = flip evalStateT mempty . iterT run
where
run :: (MonadLogger m, MonadIO m, MonadCatch m, MonadState ThingMap m) => MyDslF (m a) -> m a
run ..
但是类型不对齐,因为run
返回(.. , MonadState ThingMap m) => m a
和evalStateT
期望StateT ThingMap m a
。