晚上好。
Haskell在从事一个构建简单语言解释器的项目中,由于其功能性而被选中。
我的问题如下。我有很多实际计算某些功能的功能(这些功能内的模式匹配)。我想在屏幕上为我的所有功能在每个功能应用程序上打印一个参数(上下文类型)。
范例:
booleanExpression (And b1 b2) ctx = b1' and b2'
booleanExpression (Or b1 b2) ctx = b1' or b2'
...
arithmeticExpression (Multiply a1 a2) ctx = a1' * a2'
....
Run Code Online (Sandbox Code Playgroud)
对于这些函数,我想在每次调用函数时打印ctx。有没有一种优雅的简单方法可以做到这一点?还是我必须用类似的东西封装每个功能
arithmeticExpression (Multiply a1 a2) ctx = printAndExec ctx $ a1' * a2'
Run Code Online (Sandbox Code Playgroud)
谢谢。
在Haskell中,通常认为在每次评估之间打印某些内容的想法不高。它以一种复杂的方式将纯净有效的计算交织在一起,使推理代码变得更加困难。它也不像严格的语言那样具有确定性,因为懒惰意味着纯代码中的打印语句可能在没有警告的情况下被评估多次,或者根本没有评估。
一种自然的解决方案是在排序Monad中执行事情。Writer是一个相当纯净的Monad,它允许您“打印” ctx到缓冲区,然后在以后的阶段实际写出该缓冲区。懒惰实际上会使缓冲和写操作结合在一起,从而使它们看起来无缝。
另一个选择是将您的计算引入单IO声道,并具有完整的音序和访问所有效果的能力。看来您的计算涉及通过某种AST进行递归-您可以从每个递归调用中返回单子动作,IO Int而不是它们的纯表亲Int,并以此方式遍历树时构建不纯净的计算。
如果您仅需要出于调试目的而打印ctx,Debug.Trace则要考虑的最后一件事是该模块,该模块的确包含在纯代码中间不纯打印的方法。但是,将这些功能包含在生产代码中是一个错误的决定。