import Text.Parsec
data Expr
= V
Int -- Value (Index) | L Expr -- Lambda
| A Expr Expr -- Application
beta :: Expr -> Expr -- reduction
beta (A (L v) n) = beta $ subst 0 v $ beta n
beta (A m n) = beta $ A (beta m) n
beta e = e
subst
:: Int -> Expr
-> Expr
-> Expr
-- substitudesubst v (L w) e = L (subst (v + 1) w e)
subst v (A m n) e = A (subst v m e) (subst v n e)
subst v (V n) e | n < v = V n
| n == v = subst' 0 v e
| n > v = V (n - 1)
where subst' t v (L w) = L (subst' (t + 1) v w)
subst' t v (A m n) = A (subst' t v m) (subst' t v n)
subst' t v (V n) | n <= t = V n
| n > t = V (n + v - 1)
s = L (L (L (A (A (V 2) (V 0)) (A (V 1) (V 0)))))
k = L (L (V 1))
i = L (V 0)
zero = (L (L (V 0)))
succ = (L (L (L (A (V 1) (A (A (V 2) (V 1)) (V 0))))))
cons = (L (L (L (A (A (V 0) (V 2)) (V 1)))))
car = (L (A (V 0) (L (L (V 1)))))
cdr = (L (A (V 0) (L (L (V 0)))))
pExpr, pTerm, pS, pK, pI, pPa :: Parser Expr
pExpr = foldl1 A <$> many1 pTerm
pTerm = pS <|> pK <|> pI <|> pPa
pS = char 'S' >> return s
pK = char 'K' >> return k
pI = char 'I' >> return i
pPa = between (char '(') (char ')') pExpr
codeToExpr = parse pExpr ""
main = case codeToExpr "(SK)K" of
Left err -> print err
Right val -> print (beta val)