不返回组合表达式的所有可能的一步缩减

Not returning all possible one-step reductions for combinatory expressions

提问人:idkDude 提问时间:5/1/2023 更新时间:5/3/2023 访问量:109

问:

我正在尝试在 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]
Haskell lambda-calculus 组合逻辑

评论

2赞 chi 5/2/2023
这种情况不允许发生任何减少 、 或 的情况。其他案例也有类似的问题。请注意,当我们处于早期情况之一时,不会使用一般。(S :@ x :@ y :@ z)xyzc :@ d
0赞 Paul Johnson 5/2/2023
@chi这看起来像是一个答案。你能把它写成一个吗?谢谢。

答:

1赞 chi 5/2/2023 #1

案例

step (I :@ x) = [x]
step (K :@ x :@ y) = [x]
step (S :@ x :@ y :@ z) = [x :@ z :@ (y :@ z)]

不允许在 、 或 内进行约简。xyz

请注意,当我们陷入上述情况之一时,不考虑更一般的方程式。step (c :@ d)

最后,我不确定你是否真的想要,因为这将执行两个并行的步骤。[c' :@ d' | c' <- step c, d' <- step d]

2赞 Jon Purdy 5/3/2023 #2

[ 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 _ = []

现在返回您期望的结果,您可以使用 和 (或 ) 计算约简序列。stepiterateconcatMap=<<

λ 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]

我在这里用来说明,过滤掉重复的解决方案(汇合约简),但我应该指出,它非常低效——不仅因为它本身,还因为生成将被丢弃的项。nubnub