haskell 不返回组合表达式的所有可能的一步归约

rryofs0p  于 2023-05-07  发布在  其他
关注(0)|答案(2)|浏览(128)

我正在尝试在Haskell中实现组合逻辑,目前正在编写一个函数step,它使用标准归约规则返回所有可能的一步归约列表。当对变量S(SI)(KI)(SI K)I运行阶跃函数时,它返回第一次约简的正确表达式,但是当我再次使用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]
4xrmg8kj

4xrmg8kj1#

[ 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' | …]部分,因为它是两个并行的步骤。
它还意味着step (S :@ x :@ y :@ z)应该产生[S :@ x :@ y :@ z' | z' <- step z],但它没有,因为这已经与step的第三个(S)方程匹配。
换句话说,你的评估者有点太懒了:它省略了一些由参数的急切求值所完成的步骤,因为它只在调用没有完全饱和时才求值参数。
一个可能的解决方案是总是访问每个子表达式,* 即使 * 减少整个应用程序是可能的;并分别考虑整个表达式是否可约。如果我们让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返回您期望的结果,您可以使用iterateconcatMap(或=<<)计算减少的序列。

λ 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本身,还因为生成将被丢弃的项。

dfuffjeb

dfuffjeb2#

案件

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],因为它将执行两个并行步骤。

相关问题