是否可以通过修改这个简单的减速器来展示不同的评估策略?

时间:2015-04-25 18:32:16

标签: 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)

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

在我看来,上面的“减少”功能更多地讲述了Lambda微积分而不是解释的页面,我希望在我开始学习时能够看到它。您还可以看到它实现了一种非常严格的评估策略,即使在抽象内部也是如此。在这种精神上,如何修改代码以说明LC可以具有的许多不同的评估策略(按名称,懒惰评估,按值调用,按分享呼叫,部分评估等)?

2 个答案:

答案 0 :(得分:1)

按名称呼叫只需要进行一些更改:

  1. 不评估lambda抽象的主体:reduce (Lam body) = (Lam body)

  2. 不评估应用程序的参数。相反,我们应该按原样替换它:

    reduce (App left right) = case reduce left of
        Lam body -> reduce (substitute right body)
    
  3. 按需调用(即懒惰评估)似乎更难(或可能不可能)以完全声明的方式实现,因为我们需要记住表达式的值。我没有看到通过微小变化实现它的方法。

    分享呼叫不适用于简单的lambda演算,因为我们这里没有对象和赋值。

    我们也可以使用完全的beta减少,但我们需要选择一些确定性的评估顺序(我们不能选择“任意”的重新索引并使用我们现在的代码来减少它)。该选择将产生一些评估策略(可能是上述的一种)。

答案 1 :(得分:1)

主题非常广泛。我只想写一些想法。

建议的reduce执行并行重写。也就是说,它将App t1 t2映射到App t1' t2'(提供的t1'不是抽象)。一些策略,如CBV和CBN更顺序,因为它们只有一个重新索引。

为了描述它们,我会修改reduce,以便它返回是否实际进行了减少,或者是否相反,该术语是正常形式。这可以通过返回Maybe Term来完成,其中Nothing表示正常形式。

通过这种方式,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

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

如果我没记错的话,懒惰的评估(共享)不能用术语表达。它需要图表来表示正在共享一个子项。