簡體   English   中英

在haskell中打印lambda表達式

[英]Printing lambda expressions in haskell

我正在嘗試漂亮地打印以下類型的 Lambda 表達式

data LamExpr = LamApp LamExpr LamExpr | LamAbs Int LamExpr | LamVar Int deriving (Show, Eq)

我想我的模式匹配犯了一些邏輯錯誤,它錯誤地將事物括起來,我不確定為什么。 我嘗試添加更多案例,但我認為這使事情變得過於復雜。

printLambda :: LamExpr -> String
printLambda (LamAbs x f)                            = printf "\\x%d -> %s" x (printLambda f)
printLambda (LamVar x)                              = printf "x%d" x
printLambda (LamApp (LamAbs x f) (LamApp g h))      = printf "(%s) (%s)" (printLambda (LamAbs x f)) (printLambda (LamApp g h))
printLambda (LamApp m (LamApp f g))                 = printf "%s (%s)" (printLambda m) (printLambda (LamApp f g))
printLambda (LamApp (LamApp f g) m)                 = printf "(%s) %s" (printLambda (LamApp f g)) (printLambda m) 
printLambda (LamApp m n)                            = printf "%s %s" (printLambda m) (printLambda n) 

示例案例:

printLambda (LamApp (LamAbs 1 (LamVar 1)) (LamAbs 1 (LamVar 1))) == "(\\\\x1 -> x1) \\\\x1 -> x1"

相反,我得到了這個:

"\\\\x1 -> x1 \\\\x1 -> x1"

printLambda的調用中的數據結構是LamApp LamAbs(...) LamAbs(...) 讓我們看看為什么函數中的模式不匹配:

  • LamApp (LamAbs xf) (LamApp gh)不匹配,因為您有LamAbs ,而不是LamApp作為第二個參數
  • LamApp m (LamApp fg)同樣的原因, LamApp m (LamApp fg)不匹配
  • LamApp (LamApp fg) m不匹配,因為您有LamAbs ,而不是LamApp作為第一個參數
  • 最后, LamApp mn匹配任何LamApp並輸出兩個未括在括號中的LamApp

執行此操作的更常見方法(注意Show類也像這樣工作)是向printLambda添加一個額外參數,該參數告訴您優先上下文。

data Prec = Free | Fun | Arg deriving (Eq, Ord)
printLambda :: Prec -> LamExpr -> String

Free上下文中,該術語沒有被更高優先級的操作“撕裂”的危險,因此不需要括號。 術語的頂層打印在Free上下文中,每個 lambda 抽象的主體也是Free Fun上下文出現在應用程序的左側。 在這里,任何 lambda 表達式都必須用括號括起來,否則它將“吸收”參數( (\\x1 -> x1) x2變為\\x1 -> x1 x2 )。 但是,應用程序很好,因為它們是左關聯的( (fx) y變為fxy保持(fx) y )。 Arg上下文是最嚴格的。 你不能有一個 lambda 表達式,否則它會消耗它右邊的任何東西( f (\\x1 -> x1) x2)變成f \\x1 -> x1 x2 )。 您不能擁有應用程序,否則它將被切碎( f (gx)變為fgx變為(fg) x )。

這個輔助函數有條件地添加括號(參見內置的showParen ):

parens :: Bool -> String -> String
parens True s = "(" ++ s ++ ")"
parens False s = s

這讓一切變得更容易:

printLambda _ (LamVar i) = "x" ++ show i
printLambda p (LamAbs i b) = parens (p > Free) $ "\\x" ++ show i ++ " -> " ++ printLambda Free b
printLambda p (LamApp f x) = parens (p > Fun) $ printLambda Fun f ++ " " ++ printLambda Arg x

對於您的示例,這會產生(\\x1 -> x1) (\\x1 -> x1) 輸出(\\x1 -> x1) \\x1 -> x1 ,正如所問的,通常被認為是不正確的。 這不是模棱兩可,但添加的東西在它的右邊意味着將側面來看,這是奇怪的括號內。 你可以用一個名為Block的新Prec來實現它(這個名字是因為 GHC 調用這個語法BlockArguments

data Prec = Free | Fun | Arg | Block deriving (Eq, Ord)

直接在Free下替換Arg

printLambda _ (LamVar i) = "x" ++ show i
printLambda p (LamAbs i b) = parens (p > Free && p /= Block) $ "\\x" ++ show i ++ " -> " ++ printLambda Free b
printLambda p (LamApp f x) = parens (p > Fun) $ printLambda Fun f ++ " " ++ printLambda arg x
  where arg = if p > Free then Arg else Block

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM