gpt4 book ai didi

haskell - 代数数据类型的递归自下而上遍历

转载 作者:行者123 更新时间:2023-12-03 15:01:35 25 4
gpt4 key购买 nike

在 Haskell 中处理相当大的代数数据类型时,有一个特殊的递归遍历不能通过折叠数据类型来捕获。例如,假设我有一个简单的数据类型来表示命题逻辑中的公式,并在它上面定义了一个折叠:

type FAlgebra α φ =
(φ, φ, -- False, True
α -> φ, -- Atom
φ -> φ, -- Negation
φ -> φ -> φ, -- Conjunction
φ -> φ -> φ, -- Disjunction
φ -> φ -> φ, -- Implication
φ -> φ -> φ) -- Bi-implication

fold :: FAlgebra α φ -> Form α -> φ
fold (f,t,lit,not,con,dis,imp,iff) = fold' where
fold' (Fls) = f
fold' (Tru) = t
fold' (Lit α) = lit α
fold' (Not φ) = not (fold' φ)
fold' (Con φ ψ) = con (fold' φ) (fold' ψ)
fold' (Dis φ ψ) = dis (fold' φ) (fold' ψ)
fold' (Imp φ ψ) = imp (fold' φ) (fold' ψ)
fold' (Iff φ ψ) = iff (fold' φ) (fold' ψ)

此递归方案为评估或查找文字等递归提供了简洁的答案:
eval :: (Ord α) => Map α Bool -> Form α -> Bool
eval v = fold (False, True, (fromJust . flip M.lookup v),
not, (&&), (||), ((||) . not), (==))

literals :: (Ord α) => Form α -> Set α
literals = fold (S.empty, S.empty, S.singleton, id,
S.union, S.union, S.union, S.union)

但是,当我希望“扫描”数据类型时,它的表现并不好。在下文中, simp 是由必要的模式匹配定义的辅助函数:
simplify :: Form α -> Form α
simplify (Not φ) = simp (Not (simplify φ))
simplify (Con φ ψ) = simp (Con (simplify φ) (simplify ψ))
simplify (Dis φ ψ) = simp (Dis (simplify φ) (simplify ψ))
simplify (Imp φ ψ) = simp (Imp (simplify φ) (simplify ψ))
simplify (Iff φ ψ) = simp (Imp (simplify φ) (simplify ψ))
simplify φ = φ

当然,使用折叠定义简化会产生不正确的结果。例如,以下不等价:
simplify = fold (Fls, Tru, Lit, (simp . Not), con Con, con Dis, con Imp, con Iff)
where con f φ ψ = simp (f φ ψ)

像简化这样的递归的最佳解决方案是什么?我应该定义一个类似于折叠数据类型的通用遍历,还是有一个标准的递归模式来定义这些函数?

最佳答案

你试过Uniplate ?对于仅适用于单一类型的操作,它可以执行自下而上的重写和重写直到一个固定点。

例如:

import Data.Generics.Uniplate.Direct
import qualified Data.Map as M

data Form a = Fls | Tru | Lit a
| Not (Form a)
| Con (Form a) (Form a)
| Dis (Form a) (Form a)
-- etc.
deriving (Show, Eq)

instance Uniplate (Form a) where
uniplate (Not f) = plate Not |* f
uniplate (Con f1 f2) = plate Con |* f1 |* f2
uniplate (Dis f1 f2) = plate Dis |* f1 |* f2
-- one case for each constructor that may contain nested (Form a)s
uniplate x = plate x

simplify :: Form a -> Form a
simplify = transform simp
where
simp (Not (Not f)) = f
simp (Not Fls) = Tru
simp (Not Tru) = Fls
simp x = x

test =
simplify (Not (Not (Not (Not (Lit "a"))))) == Lit "a"

为您提供的相关功能是 transform rewrite .

有关 Uniplate 的更深入的文档还有 a paper (PDF) .

关于haskell - 代数数据类型的递归自下而上遍历,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4907024/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com