【问题标题】:Haskell: Memoising using MonadState inside a FreeMonad InterpreterHaskell:在 FreeMonad 解释器中使用 MonadState 进行记忆
【发布时间】:2016-07-15 09:28:06
【问题描述】:

鉴于我有以下 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,这样如果已经为给定的 Id 检索到 Thing,则不会再调用 SomeApi

假设我已经知道如何使用getput 编写记忆版本,但我遇到的问题是在runMyDsl 中运行MonadState。 我在想解决方案看起来类似于:

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 aevalStateT 期望 StateT ThingMap m a

【问题讨论】:

    标签: haskell memoization monad-transformers state-monad free-monad


    【解决方案1】:

    使用iterTM 代替iterT

    runMyDsl :: (MonadLogger m, MonadIO m, MonadCatch m) => MyDslT m a -> m a
    runMyDsl dsl = evalStateT (iterTM run dsl) Map.empty
      where
      run (Log message continue)      = logger message >> continue
      run (GetThingById id' continue) = do
        m <- get 
        case Map.lookup id' m of
          Nothing -> do 
             thing <- getThingById id' 
             put (Map.insert id' thing m)
             continue thing
          Just thing -> continue thing
    

    同样,如果您首先使用hoistFT liftMyDsl m a 提升为MyDsl (StateT Int m) a,则可以使用iterT,如下所示:

    runMyDsl :: (MonadLogger m, MonadIO m, MonadCatch m) => MyDslT m a -> m a
    runMyDsl dsl = evalStateT (iterT run (hoistFT lift dsl)) Map.empty
    

    这使得dsl 成为实际上不涉及任何状态更新的MyDsl (StateT Int m) a,尽管run 确实涉及状态转换。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-27
      • 1970-01-01
      • 2016-04-11
      • 2018-02-28
      • 1970-01-01
      • 2020-10-25
      • 2011-03-13
      • 2015-04-16
      相关资源
      最近更新 更多