2015-09-07 130 views
6

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

我想制作一个调试函数,它将采用任意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)"

Wha吨会是这样做的好方法?

+1

不是真的在Haskell中,这种信息在编译时被擦除。你可以使用模板haskell来实现它,但这并不简单。 – bheklilr

+0

在那里实现lambda演算有很多资源。 [TaPL](http://www.cis.upenn.edu/~bcpierce/tapl/)是一个特别好的项目,并且包括各种复杂程度的结石的实现。在Hackage上似乎也有一些小的实现,你可以使用它。 –

+0

Haskell是一种静态类型语言。其实并不是深度涉及lambda微积分,除非lambda恰好是写笛卡尔封闭类别表达式的有用方式。但直接使用类型来了解函数的作用,而不是查看一些等效的lambda表达式会更有效率。对于你想要达到的目标,像Scheme这样的语言会更合适。 – leftaroundabout

回答

1

我认为这样做的方法是在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。但是这意味着查看生成的代码而不是在程序中生成表示。我也不确定在多大程度上能够轻松识别Core代码中的特定功能(我对YMMV没有经验)。

如果在函数中使用show会给出你描述的那种输出,但是可能有很好的理由,函数不是Show的一个实例(我无法告诉你),这当然会很酷。

1

实际上,您可以通过利用模板哈斯克尔的漂亮打印来实现这一点,该模板与开箱即用的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的名称(使用')并将结果(它是带引号的字符串表达式)拼接到某个表达式中(使用$(...))。

+0

我很抱歉,但我的解决方案似乎是错误的。变量声明实际上并不包含其定义,所以'showDef'只显示类型。这就是文件中关于这个机构的说法:“目前,这个价值是无关紧要的:返回RHS由于缺乏兴趣而尚未实施。” – Yuuri