我正在学习haskell,在思考我遇到的许多haskell表达式时遇到了很多困难。
当然,我希望通过足够的练习,精神解析haskell将成为第二天性,但与此同时,为了理解我遇到的问题,我想找到一些自动方式将任意"标准的haskell" 1 表达式翻译成一个表达式,其中所有"不明确的" 2 子表达式已被消除介绍必要的括号。
例如,它会翻译表达式
f g h i
...成
((f g) h) i
......,或
a -> b -> c -> d
...成
a -> (b -> (c -> d))
......等等。
最好,这是我可以使用手机访问的工具,因为我在远离正确的计算机时对haskell进行了很多阅读。
1 当然,没有这样的工具可以使用未知固定性和关联性的自定义操作符。通过"标准haskell"我指的是前奏和标准haskell库中定义的东西。
2 我正在使用"模棱两可的"这里作为"在没有优先规则的情况下模棱两可的简写"。例如。 2 + 3 * 5
含糊不清除非有一些优先规则可以解决首先执行哪两项操作的问题。
答案 0 :(得分:10)
如果你真的想去做它的工作,你可以写一个TemplateHaskell
函数来为你做这个 - 你基本上只是走AST并随意添加parens。我开始这样做了,但意识到它会变得非常冗长乏味。我认为现在可能更方便你只考虑实际发挥作用时的currying(功能没有完全应用)。
但是,您可以使用一个技巧来解决问题的一个子问题:围绕运营商的问题,这些运营商的固定性和关联性不熟悉。在GHCi中,在使用正确的标志启动之后,只需将您感兴趣的表达式包装在$([| <expression> |])
中进行检查。然后,您可以在评估结果之前看到表达式的括号版本。
$ ghci -ddump-splices -XTemplateHaskell
Prelude> $([| 1 + 2 ^ 3 * 4 |])
<interactive>:1:3-21: Splicing expression
[| 1 + 2 ^ 3 * 4 |] ======> (1 + ((2 ^ 3) * 4))
33
Prelude> $([| 1 <$ pure 4 >>= \x -> const mempty =<< [(+),(*)] <*> [1,2] <* [False] |])
<interactive>:2:3-77: Splicing expression
[| 1 <$ pure 4
>>=
(\ x_a6PT -> const mempty =<< [(+), (*)] <*> [1, 2] <* [False] |]
======>
((1 <$ (pure 4))
>>=
(\ x_a6PT
-> ((const mempty) =<< (([(+),(*)] <*> [1,2]) <* [False]))))
[]
Prelude>
然而,这绝对不会以您想要的方式修复类型签名或功能应用程序。
答案 1 :(得分:4)
这不完全是你所要求的,但是当我写 Haskell时,我发现使用HLint警告我不必要的麻烦'正在阅读。
您可能还会发现Bernie Pope's "A tour of the Haskell Prelude"第23页上的图表很有帮助。我在下面附上了一份副本。