2015-09-07 21 views
6

Tôi có một tập hợp các biểu thức lambda mà tôi chuyển sang các lambdas khác. Tất cả lambdas chỉ dựa vào lập luận của chúng, chúng không gọi bất kỳ chức năng bên ngoài nào. Tất nhiên, đôi khi nó khá khó hiểu và tôi sẽ chuyển một hàm với số lượng đối số không chính xác sang một đối số khác, tạo ra một ngoại lệ GHCi.Haskell gỡ lỗi biểu thức lambda tùy ý

Tôi muốn tạo một hàm gỡ lỗi sẽ nhận biểu thức lambda tùy ý (với số lượng đối số không xác định) và trả về chuỗi dựa trên cấu trúc và hàm của lambda.

Ví dụ, nói tôi có biểu thức lambda sau:

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

debug (s k) nên trở "\a b -> b"

debug (s s k) nên trở "\a b -> a b a" (nếu tôi đơn giản mà chính xác)

debug s nên trở "\a b c -> a c (b c)"

Wha t sẽ là một cách tốt để làm điều này?

+1

Không thực sự ở Haskell, loại thông tin này sẽ bị xóa tại thời gian biên dịch. Bạn có thể sử dụng mẫu haskell để thực hiện nó, có thể, nhưng điều đó không đơn giản. – bheklilr

+0

Có rất nhiều tài nguyên để triển khai phép tính lambda ngoài đó. [TaPL] (http://www.cis.upenn.edu/~bcpierce/tapl/) là một đặc biệt tốt, và bao gồm việc triển khai tính toán các mức độ tinh tế khác nhau. Dường như có một số triển khai nhỏ trên Hackage mà bạn có thể chơi cùng. –

+0

Haskell là ngôn ngữ được nhập tĩnh. Nó thực sự không liên quan sâu sắc đến tính toán lambda, ngoại trừ trong trường hợp lambdas xảy ra là một cách hữu ích để viết các biểu thức của một thể loại đóng cửa Descartes. Nhưng sẽ hiệu quả hơn khi trực tiếp sử dụng các loại để có được ý tưởng về chức năng của một hàm, thay vì xem xét một số biểu thức lambda tương đương. Đối với những gì bạn đang cố gắng đạt được, một ngôn ngữ như Scheme sẽ phù hợp hơn. – leftaroundabout

Trả lời

1

Tôi nghĩ cách để thực hiện điều này sẽ là xác định DSL tính toán lambda nhỏ trong Haskell (hoặc sử dụng triển khai hiện tại). Bằng cách này, thay vì sử dụng các công thức Haskell bản xứ, bạn sẽ viết một cái gì đó giống như

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")))) 

và tương tự cho si. Sau đó, bạn sẽ viết/sử dụng hàm đánh giá để bạn có thể viết

debug e = eval e 
debug (App s k) 

sẽ cung cấp cho bạn biểu mẫu cuối cùng theo cú pháp của riêng bạn. Ngoài ra, bạn sẽ cần một loại thông dịch viên để chuyển đổi cú pháp DSL của bạn thành Haskell, để bạn có thể thực sự sử dụng các hàm trong mã của mình.

Thực hiện điều này có vẻ khá phức tạp (khó khăn), và có lẽ không chính xác những gì bạn nghĩ (đặc biệt nếu bạn cần đánh giá cú pháp đã nhập), nhưng tôi chắc chắn nó sẽ là một điều tuyệt vời kinh nghiệm học tập. Một tham chiếu tốt sẽ là chapter 6 of "Write you a Haskell". Sử dụng triển khai hiện có sẽ dễ dàng hơn nhiều (nhưng ít thú vị hơn :)).

Nếu đây chỉ là mục đích gỡ lỗi, bạn có thể hưởng lợi từ việc xem xét cú pháp chính của ghc biên dịch. Xem chapter 25 of Real world Haskell, cờ ghc để sử dụng là -ddump-đơn giản. Nhưng điều này có nghĩa là xem xét mã được tạo ra thay vì tạo ra một biểu diễn bên trong chương trình của bạn. Tôi cũng không chắc chắn về mức độ nào bạn có thể xác định các chức năng cụ thể trong mã Core một cách dễ dàng (tôi không có kinh nghiệm với YMMV này). Tất nhiên nó sẽ khá tuyệt nếu sử dụng chương trình trên các chức năng sẽ cung cấp cho loại đầu ra mà bạn mô tả nhưng có lẽ các chức năng lý do rất tốt không phải là một ví dụ của Show (tôi sẽ không thể nói cho bạn biết).

1

Bạn thực sự có thể đạt được điều đó bằng cách sử dụng khá in từ Mẫu Haskell, đi kèm với GHC ra khỏi hộp.

Thứ nhất, chức năng định dạng cần được xác định trong mô-đun riêng biệt (đó là một hạn chế 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 

Sau đó sử dụng nó:

{-# LANGUAGE TemplateHaskell #-} 
import LambdaPrint 

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

test = $(showDef 'y) 

Kết quả là nhiều hay ít có thể đọc được, không kể tên đủ điều kiện:

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

Vài từ về những gì đang diễn ra. showDef là một chức năng macro mà reifies định nghĩa của một số tên từ môi trường và in đẹp nó trong một biểu thức chuỗi chữ. Để sử dụng nó, bạn cần phải báo tên của lambda (sử dụng ') và ghép kết quả (là biểu thức chuỗi được trích dẫn) vào một số biểu thức (sử dụng $(...)).

+0

Tôi xin lỗi, nhưng giải pháp của tôi có vẻ sai. 'reify'ing khai báo biến không thực sự chứa định nghĩa của nó, do đó' showDef' chỉ hiển thị kiểu. Đó là những gì tài liệu nói về cơ thể: "Hiện tại, giá trị này là _always_ Không có gì: trả lại RHS chưa được thực hiện vì thiếu sự quan tâm." – Yuuri

Các vấn đề liên quan