我以 finally tagless 风格从磁盘反序列化数据结构。即
class SYM repl where
a :: repl
include :: FilePath -> repl
myParser :: SYM r => Parser r
我正在解析的语言包含指令。
我正在使用 attoparsec
,它不是 monad 转换器,所以我不能简单地提供一个类型 Loader = FilePath -> IO (Maybe Text)
。
我可以使用以下 SYM
实例编写解释器,解析包含。
instance SYM r => SYM (Loader -> IO (Either String r)) where
include path loader =
maybe (Left "cannot load") (parseOnly myParser) <$> loader path
不幸的是,包含在包含文件中的内容没有得到解决。当然我可以解决它们两次以解决下一层。但如果我想为每个可能的级别都这样做,那会导致无限类型。
现在我预加载所有包含(在 HashMap
中)并绑定(bind)它们,所以我可以将 FilePath -> Maybe Text
传递给解析器并解析包含在那里,但这显然不是最优的。 (并且 include 不再是 SYM
的一部分。)
我的问题是,finally 无标签样式如何解决这个问题?
编辑:我在 lpaste 上发布了一个完整的示例:http://lpaste.net/105182
最佳答案
事后看来这很容易,但通常是这样。
单层解析简单如下。
instance SYM r => SYM (Loader -> IO (Either String r)) where
token t _ = return . Right $ token t
include path loader =
maybe (Left "cannot load") (parseOnly myParser) <$> loader path
即它将在(成功)加载的文件上运行 parseOnly myParser::Either String r
。
resolve-everything 只需要为 myParser
选择 SYM (Loader -> IO (Either String r))
实例并添加 loader
参数:
include path loader =
maybe (return $ Left "cannot load")
(either (return ∘ Left) ($ loader) . parseOnly myParser)
=<< loader path
关键的一步是它将额外的参数加载器提供给新的parseOnly
d SYM
repl,从而选择正确的实例。
完整的片段在带注释的 lambda 粘贴中:http://lpaste.net/105182 .输入“include include token”进行测试
关于haskell - finally 无标记解析和递归单子(monad) Action ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24078311/