我想提一下 ; 的另一种用法fix
。假设您有一种由加法、负数和整数文字组成的简单语言。也许您已经编写了一个解析器,它接受 aString
并输出 a Tree
:
data Tree = Leaf String | Node String [Tree]
parse :: String -> Tree
-- parse "-(1+2)" == Node "Neg" [Node "Add" [Node "Lit" [Leaf "1"], Node "Lit" [Leaf "2"]]]
现在您想将您的树评估为单个整数:
fromTree (Node "Lit" [Leaf n]) = case reads n of {[(x,"")] -> Just x; _ -> Nothing}
fromTree (Node "Neg" [e]) = liftM negate (fromTree e)
fromTree (Node "Add" [e1,e2]) = liftM2 (+) (fromTree e1) (fromTree e2)
假设其他人决定扩展语言;他们想加乘法。他们必须有权访问原始源代码。他们可以尝试以下方法:
fromTree' (Node "Mul" [e1, e2]) = ...
fromTree' e = fromTree e
但是 thenMul
只能出现一次,在表达式的顶层,因为调用fromTree
不会知道Node "Mul"
大小写。Tree "Neg" [Tree "Mul" a b]
行不通,因为原版fromTree
没有"Mul"
. 但是,如果使用以下方法编写相同的函数fix
:
fromTreeExt :: (Tree -> Maybe Int) -> (Tree -> Maybe Int)
fromTreeExt self (Node "Neg" [e]) = liftM negate (self e)
fromTreeExt .... -- other cases
fromTree = fix fromTreeExt
然后可以扩展语言:
fromTreeExt' self (Node "Mul" [e1, e2]) = ...
fromTreeExt' self e = fromTreeExt self e
fromTree' = fix fromTreeExt'
现在,extendedfromTree'
将正确评估树,因为self
infromTreeExt'
指的是整个函数,包括“Mul”案例。
这里使用了这种方法(上面的例子是论文中使用的一个紧密改编的版本)。