[英]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.