我在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
模式匹配变量decls
为decls :: [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
底部似乎是&gt;&gt; =运算符为Either所做的事情,所以这让我觉得这是一种时尚,单一的方式来做我想要的事情,没有案例等等。我很想知道这里最好的风格。
答案 0 :(得分:3)
这不是问题的答案,因为它没有解决您关于$kernel = new AppKernel('prod', true);
的问题......但我根本不会使用foldM
。我认为执行所有foldM
更清晰,然后分别连接结果。这将有两个好处:
codegenDecl
连接操作,它可以先构建一个适当大小的缓冲区,然后再一次填充它。这比重复追加更有效,后者必须多次重新运行ByteString
并分配许多缓冲区。ByteString
而不是mapM
- 读者可以少关注并且仍然可以得出正确的结论。这是看起来的样子:
foldM
答案 1 :(得分:2)
(++) :: [a] -> [a] -> [a]
追加列表
output :: ByteString
codegenDecl decl :: Either String ByteString
output
与(++)
的第一个参数的预期类型不匹配(除非它在某处重新定义,例如,在基本前奏中),并且codegenDecl
没有&# 39; t匹配(++)
的第二个参数的预期类型。
这个lambda应该是typecheck(来自(<>)
的{{1}}):
Data.Monoid