Haskell 是否可以通过修改这个简单的缩减器来展示不同的评估策略?
我是那种喜欢通过看代码而不是阅读冗长解释来学习的人。这可能是我不喜欢长篇学术论文的原因之一。代码是明确的,紧凑的,无噪音的,如果你没有得到一些东西,你可以用它玩-不需要问作者 这是Lambda演算的完整定义:Haskell 是否可以通过修改这个简单的缩减器来展示不同的评估策略?,haskell,lambda,functional-programming,lazy-evaluation,lambda-calculus,Haskell,Lambda,Functional Programming,Lazy Evaluation,Lambda Calculus,我是那种喜欢通过看代码而不是阅读冗长解释来学习的人。这可能是我不喜欢长篇学术论文的原因之一。代码是明确的,紧凑的,无噪音的,如果你没有得到一些东西,你可以用它玩-不需要问作者 这是Lambda演算的完整定义: -- A Lambda Calculus term is a function, an application or a variable. data Term = Lam Term | App Term Term | Var Int deriving (Show,Eq,Ord) --
-- A Lambda Calculus term is a function, an application or a variable.
data Term = Lam Term | App Term Term | Var Int deriving (Show,Eq,Ord)
-- Reduces lambda term to its normal form.
reduce :: Term -> Term
reduce (Var index) = Var index
reduce (Lam body) = Lam (reduce body)
reduce (App left right) = case reduce left of
Lam body -> reduce (substitute (reduce right) body)
otherwise -> App (reduce left) (reduce right)
-- Replaces bound variables of `target` by `term` and adjusts bruijn indices.
-- Don't mind those variables, they just keep track of the bruijn indices.
substitute :: Term -> Term -> Term
substitute term target = go term True 0 (-1) target where
go t s d w (App a b) = App (go t s d w a) (go t s d w b)
go t s d w (Lam a) = Lam (go t s (d+1) w a)
go t s d w (Var a) | s && a == d = go (Var 0) False (-1) d t
go t s d w (Var a) | otherwise = Var (a + (if a > d then w else 0))
-- If the evaluator is correct, this test should print the church number #4.
main = do
let two = (Lam (Lam (App (Var 1) (App (Var 1) (Var 0)))))
print $ reduce (App two two)
在我看来,上面的“reduce”函数更多地说明了Lambda演算,而不是一页页的解释,我希望我开始学习时能看看它。您还可以看到,它实现了一个非常严格的评估策略,甚至可以在抽象中使用。本着这种精神,如何修改该代码以说明LC可以拥有的许多不同的评估策略(按名称调用、延迟评估、按值调用、按共享调用、部分评估等)?按名称调用只需要一些更改:
reduce(Lam-body)=(Lam-body)
reduce (App left right) = case reduce left of
Lam body -> reduce (substitute right body)
我们也可以使用完整的beta缩减,但是我们需要选择一些确定的评估顺序(我们不能选择一个“任意”的redex并使用我们现在的代码进行缩减)。这种选择将产生某种评估策略(可能是上述策略之一) 这个话题相当广泛。我会写一些想法 建议的
reduce
执行并行重写。也就是说,它将App t1 t2
映射到App t1't2'
(前提是t1'
不是抽象)。有些策略,如CBV和CBN,更具有顺序性,因为它们只有一个redex
为了描述它们,我将修改reduce
,以便它返回是否实际进行了缩减,或者该术语是否为标准形式。这可以通过返回一个可能的术语
,其中无
表示正常形式
这样,CBN将是
reduce :: Term -> Maybe Term
reduce (Var index) = Nothing -- Vars are NF
reduce (Lam body) = Nothing -- no reduction under Lam
reduce (App (Lam body) right) = Just $ substitute right body
reduce (App left right) =
(flip App right <$> reduce left) <|> -- try reducing left
(App left <$> reduce right) -- o.w., try reducing right
reduce::Term->Maybe Term
reduce(Var索引)=Nothing--Var是NF
减少(林体)=无——林下无减少
减少(应用程序(林体)右侧)=仅$替换右侧体
减少(应用程序左/右)=
(翻转应用程序右减左)--尝试左减
(应用程序左减右)--o.w.,尝试右减
而CBV将是
reduce :: Term -> Maybe Term
reduce (Var index) = Nothing
reduce (Lam body) = Nothing -- no reduction under Lam
reduce (App (Lam body) right)
| reduce right == Nothing -- right must be a NF
= Just $ substitute right body
reduce (App left right) =
(flip App right <$> reduce left) <|>
(App left <$> reduce right)
reduce::Term->Maybe Term
减少(Var指数)=无
减少(林体)=无——林下无减少
减少(应用程序(林体)右侧)
|reduce right==Nothing--right必须是NF
=仅需$替换右体
减少(应用程序左/右)=
(翻转应用程序右减左)
(应用程序左减右)
如果我没记错的话,懒散的评估(共享)不能用术语来表达。它需要图表来表示子项正在被共享。这是一个非常有趣的主题,尽管根据StackOverflow指南,我怀疑这个问题是否与主题有关。@leftaroundabout实际上,我也有一些疑问。然而,我认为这可以被看作是一个编程问题,因为底部的问题是关于如何调整代码以适应多种策略(可能以优雅的方式)。这不仅仅是关于lambda演算。