I'm trying to implement combinatory logic in Haskell, and am currently writing a function step, which returns a list of all possible one step reductions using the standard reduction rules. When running the step function on the variable S (S I) (K I) (S I K) I, it returns the correct expression for the first reduction, but when I reduce it again with step (head it) it returns only one of the possible reductions.
This is my code
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"
I am aiming for this when running in 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]
The cases
do not allow reductions within
x,y, orz.Note that the more general equation
step (c :@ d)is not considered when we fall in one of the above cases.Finally, I'm not sure if you really want
[c' :@ d' | c' <- step c, d' <- step d]since that will perform two parallel steps.