haskell - finally 无标记解析和递归单子(monad) Action

标签 haskell encoding attoparsec

我以 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

关键的一步是它将额外的参数加载器提供给新的parseOnlyd SYM repl,从而选择正确的实例。

完整的片段在带注释的 lambda 粘贴中:http://lpaste.net/105182 .输入“include include token”进行测试

关于haskell - finally 无标记解析和递归单子(monad) Action ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24078311/

相关文章:

haskell - 我应该如何正确传递列表参数?通过这种方式,解释器给出了预期类型的​​错误

haskell - 支持(多个)子类型化/子类化的定理证明者/证明助手

java - BASE64Encoder 是内部 API,可能会在未来的版本中删除

使用 Attoparsec 解析简单的分子名称

haskell - 将函数分配给 monad 内的变量时丢失多态性

haskell - 在编译时或运行时生成一个随机字符串,并在程序的其余部分使用它

javascript - 使用Javascript的atob解码base64不能正确解码utf-8字符串

c# - 字节串在python和c#中是相同的,但是md5 hashcode是不同的

parsing - 在 Attoparsec 中使用 sepBy 字符串

haskell - 使用 endOfInput 解析器输入不完整