Debugging Haskell调试任意lambda表达式

Debugging Haskell调试任意lambda表达式,debugging,haskell,lambda,Debugging,Haskell,Lambda,我有一组lambda表达式,我正在传递给其他lambda。所有lambda只依赖于它们的参数,它们不调用任何外部函数。当然,有时它会变得非常混乱,我会将参数数量不正确的函数传递给另一个函数,从而创建一个GHCi异常 我想制作一个调试函数,它将接受一个任意lambda表达式(具有未知数量的参数),并根据lambda的结构和函数返回一个字符串 例如,假设我有以下lambda表达式: i = \x -> x k = \x y -> x s = \x y z -> x z (y z)

我有一组lambda表达式,我正在传递给其他lambda。所有lambda只依赖于它们的参数,它们不调用任何外部函数。当然,有时它会变得非常混乱,我会将参数数量不正确的函数传递给另一个函数,从而创建一个GHCi异常

我想制作一个调试函数,它将接受一个任意lambda表达式(具有未知数量的参数),并根据lambda的结构和函数返回一个字符串

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

i = \x -> x
k = \x y -> x
s = \x y z -> x z (y z)
debug(sk)
应返回
“\ab->b”

debug(sk)
应该返回
“\ab->aba”
(如果我正确简化了它)

debug s
应返回
“\a b c->a c(b c)”


这样做的好方法是什么?

我认为这样做的方法是在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"))))
同样地,对于
s
i
。然后编写/使用求值函数,以便编写

debug e = eval e
debug (App s k)
这将以您自己的语法提供最终形式。此外,您还需要一种解释器来将DSL语法转换为Haskell,以便您可以实际使用代码中的函数

实现这一点看起来确实需要很多(棘手的)工作,而且这可能不是您想要的(特别是如果您需要对类型化语法进行评估),但我相信这将是一次很好的学习体验。一个好的参考是。使用现有的实现会容易得多(但没有那么有趣:)

如果这仅仅是为了调试目的,您可以查看ghc编译到的核心语法。请参见,要使用的ghc标志是-ddump siml。但这意味着要查看生成的代码,而不是在程序中生成表示。我也不确定您能够在多大程度上轻松地识别核心代码中的特定函数(我没有这方面的经验)


如果使用show on函数可以提供您描述的输出类型,那当然很酷,但可能有很好的理由说明函数不是show的一个实例(我不能告诉您)。

您实际上可以通过使用模板Haskell的漂亮打印来实现这一点,该模板是GHC现成的

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

然后使用它:

{-# 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的名称(使用
)并将结果(这是一个带引号的字符串表达式)拼接到某个表达式中(使用
$(…)
)。

在Haskell中不是这样,这种信息在编译时会被删除。您可能可以使用模板haskell来实现它,但这并不简单。在实现lambda演算方面有很多资源。是一个特别好的方法,包括不同复杂程度的计算实现。在Hackage上似乎还有一些小的实现,您可以使用它们。Haskell是一种静态类型语言。它实际上并没有深入地涉及lambda演算,除非lambda恰好是一种编写笛卡尔闭范畴表达式的有用方法。但是直接使用类型来了解函数的功能要比查看一些等价的lambda表达式更有效率。对于您试图实现的目标,类似于Scheme的语言更合适。有帮助吗?对不起,我的解决方案似乎是错误的
reify
ing变量声明实际上并不包含其定义,因此
showDef
仅显示类型。这就是文档中对主体的描述:“目前,该值始终为零:由于缺乏兴趣,返回RHS尚未实现。”
*Main> test
"Main.y :: forall a_0 . a_0 -> a_0"