我一直在玩“freer monads”和可扩展效果,在freer-effects包中实现,我遇到了一个似乎可行但我无法解决的问题。
我编写了一个表示与文件系统的简单交互的类型:
data FileSystem v where
ReadFile :: FilePath -> FileSystem String
WriteFile :: FilePath -> String -> FileSystem ()
为此编写解释器IO
很容易,但很无聊。我真正感兴趣的是编写一个State
内部使用的纯解释器。我可以有效地将 的实现内联runState
到我的解释器中FileSystem
,但这似乎有点违背了目的。我真正想做的是编写这两种类型之间的转换,然后重用State
解释器。
编写这样的转换很简单:
fsAsState :: forall v r. FileSystem v -> Eff (State [(FilePath, String)] ': r) v
fsAsState (ReadFile a) = (lookup a <$> get) >>=
maybe (fail "readFile: file does not exist") return
fsAsState (WriteFile a b) = modify $ \fs ->
(a, b) : filter ((/= a) . fst) fs
现在我想要一个可以接受我的转换并通过重用解释器来解释我的通用reencode
函数。有了这样的功能,我就可以编写以下解释器:fsAsState
FileSystem
State
runInMemoryFS :: forall r w. [(FilePath, String)] -> Eff (FileSystem ': r) w -> Eff r (w, [(FilePath, String)])
runInMemoryFS fs m = runState (reencode fsAsState m) fs
棘手的事情实际上是实施reencode
。我得到了几乎可以进行类型检查的东西:
reencode :: forall r w f g. (forall v. f v -> Eff (g ': r) v) -> Eff (f ': r) w -> Eff (g ': r) w
reencode f m = loop m
where
loop :: Eff (f ': r) w -> Eff (g ': r) w
loop (Val x) = return x
loop (E u q) = case decomp u of
Right x -> qComp q loop =<< f x
Left u' -> E (weaken u') undefined
不幸的是,我不知道如何E
在loop
. 我认为我不了解优化FTCQueue
类型如何工作的实现细节,以便了解我是否需要在这里做一些简单的事情,或者我正在做的事情是不可能的。
这可能吗?如果答案是否定的,并且事实证明我正在做的事情实际上是不可能的,那么我会对帮助我理解原因的解释感兴趣。