我正在尝试在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]
2条答案
按热度按时间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
返回您期望的结果,您可以使用iterate
和concatMap
(或=<<
)计算减少的序列。我在这里使用
nub
来进行说明,以过滤掉重复的解决方案(汇合约简),但我应该指出,它非常低效-不仅因为nub
本身,还因为生成将被丢弃的项。dfuffjeb2#
案件
不允许在
x
、y
或z
范围内减少。注意,当我们落入上述情况之一时,不考虑更一般的方程
step (c :@ d)
。最后,我不确定您是否真的需要
[c' :@ d' | c' <- step c, d' <- step d]
,因为它将执行两个并行步骤。