Haskell调试任意lambda表达式

时间:2015-09-07 02:22:50

标签: debugging haskell lambda

我有一组lambda表达式,我将其传递给其他lambda。所有的lambdas都只依赖于他们的论点,他们不会调用任何外部函数。当然,有时它会让人感到困惑,我会将一个参数数量不正确的函数传递给另一个函数,从而产生GHCi异常。

我想创建一个调试函数,它将采用一个任意的lambda表达式(带有未知数量的参数),并根据lambda的结构和函数返回一个字符串。

例如,假设我有以下lambda表达式:

i = \x -> x
k = \x y -> x
s = \x y z -> x z (y z)

debug (s k)应该返回"\a b -> b"

debug (s s k)应该返回"\a b -> a b a"(如果我已正确简化)

debug s应该返回"\a b c -> a c (b c)"

这样做的好方法是什么?

2 个答案:

答案 0 :(得分:2)

我认为这样做的方法是在Haskell中定义一个小的lambda演算DSL(或使用现有的实现)。这样,您可以编写类似

的内容,而不是使用本机Haskell公式
k = Lam "x" (Lam "y" (App (Var "x") (Var "y")))
s = Lam "x" (Lam "y" (Lam "z" (App (App (Var "x") (Var "z")
                                   (App (Var "y") (Var "z"))))

,同样适用于si。然后,您将编写/使用评估函数,以便您可以编写

debug e = eval e
debug (App s k)

它将以您自己的语法为您提供最终形式。另外,您需要一种解释器来将您的DSL语法转换为Haskell,以便您可以实际使用代码中的函数。

实现这看起来确实很多(棘手的)工作,并且它可能不是你想到的(特别是如果你需要对类型语法进行评估),但我相信这将是一个很好的学习经验。一个很好的参考是chapter 6 of "Write you a Haskell"。使用现有的实现会容易得多(但不那么有趣:))。

如果仅用于调试目的,您可以从查看ghc编译的核心语法中受益。请参阅chapter 25 of Real world Haskell,要使用的ghc标志是-ddump-simpl。但这意味着要查看生成的代码而不是在程序中生成表示。我也不确定你能在多大程度上轻松识别核心代码中的特定功能(我没有这方面的经验,所以YMMV)。

如果在函数上使用show会给出你描述的那种输出,那当然会很酷,但是可能有很好的理由,函数不是Show的实例(我不能告诉你)。< / p>

答案 1 :(得分:1)

你可以通过使用模板Haskell的漂亮打印来实现这一点,而模板Haskell开箱即用了GHC。

首先,格式化函数应该在单独的模块中定义(这是一个TH限制):

module LambdaPrint where

import Control.Monad
import Language.Haskell.TH.Ppr
import Language.Haskell.TH.Syntax

showDef :: Name -> Q Exp
showDef = liftM (LitE . StringL . pprint) . reify

然后使用它:

{-# LANGUAGE TemplateHaskell #-}
import LambdaPrint

y :: a -> a
y = \a -> a
$(return []) --workaround for GHC 7.8+

test = $(showDef 'y)

结果或多或少可读,不计算完全限定名称:

*Main> test
"Main.y :: forall a_0 . a_0 -> a_0"

关于发生了什么的几句话。 showDef是一个宏函数,它从环境中统一某个名称的定义,并在字符串文字表达式中进行漂亮打印。要使用它,您需要引用lambda的名称(使用')并将结果(带引号的字符串表达式)拼接成某个表达式(使用$(...))。