Haskell foldM从列表到单个Either

时间:2018-02-22 07:46:06

标签: haskell

我在Haskell写了一个类型的翻译,到目前为止它非常有趣。我在Codegen步骤中(获取解析器结果,将其打印到代码中),我尝试做的一件事情如下:

我有模块,我的模块有声明。

codegen :: Module -> Either String ByteString
codegen Module { what = "module", declarations = decls } = Right $ foldM (\output decl ->
    output ++ (codegenDecl decl)) (empty :: ByteString) decls -- generate declarations    
codegen Module { what = s } = Left $ "Bad module 'what' key " ++ s

codegenDecl :: Declaration -> Either String ByteString
codegenDecl Declaration { what = dt, name = dn, argnames = Just al, constructors = Just lc } = Right $ "Declaration " ++ dn ++ " of type " ++ dt

模式匹配变量declsdecls :: [Declaration],我使用Either monad进行错误跟踪。 <期望

foldM (\output decl -> output ++ (codegenDecl decl)) (empty :: ByteString) decls

如果所有声明都正确,或者返回Left $ "Error writing a declaration"

,是连接所有ByteStrings吗?

但我认为我在这里错过了一些东西,因为守门员抱怨道。如果其中一个声明失败,我希望整个模块失败。如果所有这些都成功,我想将它们连接成一个ByteString。

[decls] --------> Right result -------> Right $ foldM (++) accumulator result                                                      |
    |                 ^                                 |
    |                 -----------------------------------
    |
    |-----------> Left err ------------> Left $ err

底部似乎是&gt;&gt; =运算符为Either所做的事情,所以这让我觉得这是一种时尚,单一的方式来做我想要的事情,没有案例等等。我很想知道这里最好的风格。

2 个答案:

答案 0 :(得分:3)

这不是问题的答案,因为它没有解决您关于$kernel = new AppKernel('prod', true);的问题......但我根本不会使用foldM。我认为执行所有foldM更清晰,然后分别连接结果。这将有两个好处:

  1. 它将执行单个codegenDecl连接操作,它可以先构建一个适当大小的缓冲区,然后再一次填充它。这比重复追加更有效,后者必须多次重新运行ByteString并分配许多缓冲区。
  2. 因为它使用的组合器可以“少做一些事情” - ByteString而不是mapM - 读者可以少关注并且仍然可以得出正确的结论。
  3. 这是看起来的样子:

    foldM

答案 1 :(得分:2)

  • (++) :: [a] -> [a] -> [a]追加列表

  • output :: ByteString

  • codegenDecl decl :: Either String ByteString

output(++)的第一个参数的预期类型不匹配(除非它在某处重新定义,例如,在基本前奏中),并且codegenDecl没有&# 39; t匹配(++)的第二个参数的预期类型。

这个lambda应该是typecheck(来自(<>)的{​​{1}}):

Data.Monoid