【问题标题】:Haskell foldM from list to a single EitherHaskell foldM 从列表到单个 Either
【发布时间】:2018-02-22 07:46:06
【问题描述】:

我正在用 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"

但我认为我在这里遗漏了一些东西,因为类型检查器会抱怨。如果任何一个声明失败,我希望整个模块失败。如果它们都成功了,我想将它们连接成一个 ByteString。

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

底部部分似乎是 >>= 运算符为 Either 所做的,所以这让我觉得有一种时尚的、单子的方式来做我想做的事,而无需案例等。我很想知道这里最好的风格是什么。

【问题讨论】:

  • 关于“类型检查器抱怨”:当这种情况发生时,您应该始终发布(完整)错误消息。否则,你会强迫读者在头脑中执行类型检查,试图找出问题所在,或者试图从你的代码构建一个 MCVE——两者都需要不小的努力。这样就不太可能有人回答您的问题。
  • 你想要concat <$> mapM codegenDecl decls这样的东西吗?

标签: haskell


【解决方案1】:

这并不是问题的真正答案,因为它没有解决您关于foldM 的问题...但我什至根本不会使用foldM。我认为做你所有的codegenDecling 会更干净,然后分别连接结果。这将有两个好处:

  1. 它将执行单个ByteString 连接操作,它可以先构建一个适当大小的缓冲区,然后遍历一次以填充它。这将比重复追加更有效,因为重复追加必须提前多次ByteStrings 并分配许多缓冲区。
  2. 因为它使用的组合器可以“做更少的事情”——mapM 而不是foldM——读者可以减少注意力,但仍然可以对正在发生的事情得出正确的结论。

如下所示:

mconcat <$> mapM codegenDecl decls

【讨论】:

  • 非常感谢!所以只是澄清一下,如果结果数组有多个“左错误”,mconcat 实际上不会 concat 对吗?
  • @rausted 正确:一旦codegenDecldecls 之一返回Left,整个计算将立即中止并返回Left
【解决方案2】:
  • (++) :: [a] -&gt; [a] -&gt; [a] 追加列表

  • output :: ByteString

  • codegenDecl decl :: Either String ByteString

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

此 lambda 应进行类型检查(使用来自 Data.Monoid(&lt;&gt;)):

\output decl -> fmap (output <>) (codegenDecl decl)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-14
    • 1970-01-01
    • 2019-10-09
    • 1970-01-01
    相关资源
    最近更新 更多