2015-09-07 4 views
6

私は他のラムダに渡すラムダ式のセットを持っています。すべてのラムダは引数だけに依存しており、外部関数を呼び出すことはありません。もちろん、ときどきかなり混乱し、誤った数の引数を持つ関数を別の関数に渡して、GHCi例外を作成します。Haskellは任意のラムダ式をデバッグします

私は任意のラムダ式(未知数の引数を持つ)をとり、ラムダの構造と関数に基づいて文字列を返すデバッグ関数を作りたいと思います。

例えば、私は、次のラムダ式を持っていると言う:

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)を返す必要があります

debug s"\a b c -> a c (b c)"

を返す必要があります(私が正しく、その簡素化場合) "\a b -> a b a"を返す必要があります

さんこれを行う良い方法でしょうか?

+1

実際、Haskellではこの種の情報はコンパイル時に消去されます。テンプレートhaskellを使用して実装することは可能でしょうが、それは簡単ではありません。 – bheklilr

+0

そこにはラムダ計算を実装するための多くのリソースがあります。 [TaPL](http://www.cis.upenn.edu/~bcpierce/tapl/)は、特に優れたものであり、さまざまな洗練されたレベルの計算を実装しています。あなたが演奏できるHackageには、いくらか小さな実装があるようです。 –

+0

Haskellは静的型付けされた言語です。実際にラムダがデカルト閉じられたカテゴリの式を書くのに便利な方法である限り、ラムダの微積分は深く関わっていません。しかし、同等のラムダ式を調べるのではなく、関数が何をするのかを知るために型を直接使うのははるかに生産的です。あなたが達成しようとしているものについては、Schemeのような言語がもっと適しています。 – leftaroundabout

答えて

1

これを行う方法は、Haskellで小さなラムダ計算法DSLを定義することです(または既存の実装を使用する)。この方法では、代わりにネイティブHaskellの製剤を使用して、あなたは

siため
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")))) 

と同様のようなものを書くでしょう。次に、評価関数を作成/使用して、書けるようにします。

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-simpleです。しかし、これはプログラム内で表現を生成するのではなく、生成されたコードを見ることを意味します。私は、あなたがコアコード内の特定の機能を容易にどの程度特定できるかもわかりません(私はこのようにYMMVを経験していません)。

show関数を使用すると、出力の種類がわかりますが、関数がShowのインスタンスではないという非常に良い理由があります(私はあなたに伝えられません)。

1

実際にGHCに付属のテンプレートHaskellからのきれいな印刷を利用することで、これを実現できます。

まず、フォーマット機能(つまりTH制限'S)別個のモジュールで定義されなければならない。

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は、ある名前の定義を環境から再定義し、それを文字列リテラル式できれいに印刷するマクロ関数です。それを使用するには、ラムダの名前を('を使用して)引用し、結果(引用された文字列式)を($(...)を使用して)何らかの式にスプライスする必要があります。

+0

申し訳ありませんが、私の解決策は間違っているようです。変数宣言の 'reify'は実際にその定義を含んでいないので、' showDef'はその型だけを示します。それは文書が身体について語っているものです:「現在のところ、この価値は何もありません。RHSを返すことは、興味の欠如のためにまだ実施されていません。 – Yuuri