我以最终无标记样式从光盘反序列化数据结构。即。
class SYM repl where
a :: repl
include :: FilePath -> repl
myParser :: SYM r => Parser r
我正在解析的语言包含指令。
我正在使用不是monad变换器的attoparsec
,所以我不能简单地提供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
中)并绑定它们,因此我可以将FilePath -> Maybe Text
传递给解析器并解析包含在那里,但这显然不是最佳的。 (并且不再包括SYM
的一部分。)
我的问题是,最终无标签风格如何解决这个问题?
编辑:我发布了关于lpaste的完整示例:http://lpaste.net/105182
答案 0 :(得分:1)
后见之明很容易,但通常是。
仅限一级解析就是以下几点。
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
。
解决方案 - 所有内容只需为SYM (Loader -> IO (Either String r))
选择myParser
实例并添加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”来测试它