我想實作 lambda 運算式的惰性縮減。它應該只減少該運算式,直到它位于 WHNF 中。
型別LExpr定義如下:
data LExpr = Var String
| App LExpr LExpr
| Lam String LExpr
到目前為止我做了什么:
lazy :: LExpr -> LExpr
lazy (Var v) = Var v
lazy (Lam x e) = Lam x e
lazy (App e1 e2) =
case e1 of
(Lam x e) -> if (x `elem` bound e1)
then lazy $ subst e2 x e
else App e1 e2
(App e3 e4) -> App (lazy $ App e3 e4) e2
_ -> App e1 e2
(bound是系結在運算式中的所有字串的串列;將運算式中subst的字串替換為運算式x,并在必要時進行 alpha 轉換)ee2
但這只是減少了一個論點。例如,如果我打電話lazy給(\x -> x) (\y -> f y) a b
它將減少為: (\y -> f y) a b
但我想擁有: f a b
所以基本上在我想呼叫的第二個案例陳述中:
(App e2 e3) -> lazy $ App (lazy $ App e3 e4) e2
但這不起作用。如何在由所述函式修改的引數上呼叫函式?也許,我可以強迫 Haskell 減少lazyfirst 的內部呼叫?
我也嘗試使用fold:
lazy' :: LExpr -> LExpr
lazy' = lfold (\x -> Var x)
(\x y -> lazy $ (App x y))
(\x y -> Lam x y)
對于上面的示例,它作業正常。但是,不適用于此示例:(\z x. (\x. x) z) x
這將減少為: (\x' -> x)
但正確的結果是: (\x' -> (\x -> x) x)
我不知道如何解決這個問題。也許有人有一個想法并想與我分享?非常感謝您提前。
PS:我使用的“ lfold”或“ subst”等所有功能都是以前的功課,所以我知道實作是正確的。如果您想查看實作,我可以添加它們。
uj5u.com熱心網友回復:
在這種情況下,我首先想到的是根本不使用case。我不能試一試,但也許這個想法會有所幫助:
lazy :: LExpr -> LExpr
lazy (Var v) = Var v
lazy (Lam x e) = Lam x e
lazy (App e1@(Lam x e) e2) = if (x `elem` bound e1) then lazy $ subst e2 x e else App e1 e2
lazy (App e1@(App _ _) e2) = App (lazy e1) e2
lazy (App e1 e2@(Var _)) = App e1 e2
lazy (App e1 e2) = App e1 (lazy e2)
uj5u.com熱心網友回復:
感謝大家。我發現了問題。
如果我(App e3 e4) -> lazy $ App (lazy $ App e3 e4) e2在第二個 case 陳述句中呼叫,我只想在lazy $ App e3 e4導致 lambda 運算式的情況下這樣做。如果它是變數(或變數和運算式)的應用程式,它將被一遍又一遍地呼叫。所以在我呼叫lazy修改后的運算式之前,我只需要檢查它是否是形式Lam x e。
現在lazy作業正常。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/416353.html
標籤:
上一篇:Data.Aeson匯入密鑰
