提问人:idkDude 提问时间:5/1/2023 更新时间:5/3/2023 访问量:109
不返回组合表达式的所有可能的一步缩减
Not returning all possible one-step reductions for combinatory expressions
问:
我正在尝试在 Haskell 中实现组合逻辑,目前正在编写一个函数步骤,它使用标准简化规则返回所有可能的一步缩减的列表。当在变量 S (S I) (K I) (S I K) I 上运行 step 函数时,它返回第一个约简的正确表达式,但是当我使用 step (head it) 再次约简它时,它只返回一个可能的约简。
这是我的代码
module Main where
data Combinator
= I
| K
| S
| V String
| Combinator :@ Combinator
deriving (Eq, Ord)
instance Show Combinator where
show = f 0
where
f _ I = "I"
f _ K = "K"
f _ S = "S"
f _ (V s) = s
f i (c :@ d) = if i == 1 then "(" ++ s ++ ")" else s where s = f 0 c ++ " " ++ f 1 d
step :: Combinator -> [Combinator]
step (I :@ x) = [x]
step (K :@ x :@ y) = [x]
step (S :@ x :@ y :@ z) = [x :@ z :@ (y :@ z)]
step (c :@ d) = [c' :@ d | c' <- step c] ++ [c :@ d' | d' <- step d] ++
[c' :@ d' | c' <- step c, d' <- step d]
step _ = []
parse :: String -> Combinator
parse s = down [] s
where
down [] (' ' : str) = down [] str
down cs ('(' : str) = down (Nothing : cs) str
down cs ('I' : str) = up cs I str
down cs ('K' : str) = up cs K str
down cs ('S' : str) = up cs S str
down cs (c : str) = up cs (V [c]) str
up [] c [] = c
up (Just c : cs) d str = up cs (c :@ d) str
up (Nothing : cs) d (')' : str) = up cs d str
up cs d str = down (Just d : cs) str
main :: IO ()
main = do
putStrLn $ "Combinatory Logic in Haskell"
在 GHCi 中运行时,我的目标是这一点——
*Main> parse "S(SI)(KI)(SIK)I"
S (S I) (K I) (S I K) I
*Main> step it
[S I (S I K) (K I (S I K)) I]
*Main> step (head it)
[ I (K I (S I K)) (S I K (K I (S I K))) I, S I (S I K) I I ]
I am getting -
ghci> parse "S(SI)(KI)(SIK)I"
S (S I) (K I) (S I K) I
ghci> step it
[S I (S I K) (K I (S I K)) I]
ghci> step (head it)
[I (K I (S I K)) (S I K (K I (S I K))) I]
答:
案例
step (I :@ x) = [x]
step (K :@ x :@ y) = [x]
step (S :@ x :@ y :@ z) = [x :@ z :@ (y :@ z)]
不允许在 、 或 内进行约简。x
y
z
请注意,当我们陷入上述情况之一时,不考虑更一般的方程式。step (c :@ d)
最后,我不确定你是否真的想要,因为这将执行两个并行的步骤。[c' :@ d' | c' <- step c, d' <- step d]
[ I (K I (S I K)) (S I K (K I (S I K))) I, S I (S I K) I I ]
这意味着应该产生 ,它确实由 的最后一个方程 产生。但是,如果您一次只想探索一个步骤,则应跳过此等式的部分,因为它使两个步骤并行。step ((S :@ x :@ y :@ z) :@ I)
[s :@ I | s <- step (S :@ x :@ y :@ z)]
step
[c' :@ d' | …]
它还意味着应该产生 ,但事实并非如此,因为这已经与 的第三个 (S) 方程匹配。step (S :@ x :@ y :@ z)
[S :@ x :@ y :@ z' | z' <- step z]
step
换句话说,你的赋值器有点太懒了:它省略了一些通过急切评估参数来完成的步骤,因为它只在调用没有完全饱和时才评估参数。
一种可能的解决方案是始终访问每个子表达式,即使可以减少整个应用程序;并单独考虑整个表达式是否可约化。如果我们总是只执行一次,如果没有单步减少,则返回一个空列表,这可能更容易正确。step
step (f :@ z) = outer ++ left ++ right
where
-- I z ~> z
-- ( K y) z ~> y
-- ((S x) y) z ~> xz(yz)
outer = case f of
I -> [z]
K :@ y -> [y]
S :@ x :@ y -> [(x :@ z) :@ (y :@ z)]
_ -> []
-- f ~> f'
-- -----------
-- f z ~> f' z
left = [f' :@ z | f' <- step f]
-- z ~> z'
-- -----------
-- f z ~> f z'
right = [f :@ z' | z' <- step z]
step _ = []
现在返回您期望的结果,您可以使用 和 (或 ) 计算约简序列。step
iterate
concatMap
=<<
λ import Data.List (nub)
λ reductions input = iterate (nub . concatMap step) [parse input]
λ import Data.Foldable (traverse_)
λ traverse_ print $ takeWhile (not . null) $ reductions "K(I(K(Ia)))bc"
[K (I (K (I a))) b c]
[I (K (I a)) c,K (K (I a)) b c,K (I (K a)) b c]
[K (I a) c,I (K a) c,K (K a) b c]
[I a,K a c]
[a]
我在这里用来说明,过滤掉重复的解决方案(汇合约简),但我应该指出,它非常低效——不仅因为它本身,还因为生成将被丢弃的项。nub
nub
评论
(S :@ x :@ y :@ z)
x
y
z
c :@ d