最后无标记解析和递归monadic动作

时间:2014-06-06 09:19:51

标签: haskell encoding attoparsec

我以最终无标记样式从光盘反序列化数据结构。即。

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

1 个答案:

答案 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”来测试它