lambda/lambda.hs

87 lines
3.4 KiB
Haskell

import Data.List
data Expression s = ESymbol s
| EReference Int
| EExpr (Expression s) (Expression s)
| ELambda s (Expression s)
makeUnique :: [String] -> String -> String
makeUnique context s =
let apostrophes = iterate ('\'' :) ""
modified = zipWith (++) (repeat s) apostrophes
available = filter (not . (`elem` context)) modified
in head available
renameUniquely :: (Show s) => Expression s -> Expression String
renameUniquely = rename_ []
-- rename_ :: (Show s) => [String] -> Expression s -> Expression String
where rename_ c (EReference r) = EReference r
rename_ c (ESymbol s) = ESymbol . makeUnique c . show $ s
rename_ c (EExpr a b) = EExpr (rename_ c a) (rename_ c b)
rename_ c (ELambda s e) = let name = makeUnique c . show $ s
in ELambda name (rename_ (name : c) e)
instance (Show s) => Show (Expression s) where
show = show_ [] . renameUniquely
-- show_ :: Expression String -> String
where show_ c (EReference n)
| n >= 0 && n < length c = c !! n
| otherwise = "ERR" -- TODO: Do this better?
show_ c (ESymbol s) = s
show_ c (EExpr a b@(EExpr _ _)) = show_ c a ++ " (" ++ show_ c b ++ ")"
show_ c (EExpr a b) = show_ c a ++ " " ++ show_ c b
show_ c (ELambda s e@(EExpr _ _)) = "\\" ++ s ++ ".(" ++ show_ (s : c) e ++ ")"
show_ c (ELambda s e) = "\\" ++ s ++ "." ++ show_ (s : c) e
instance Eq (Expression s) where
(ESymbol _) == (ESymbol _) = True
(EReference a) == (EReference b) = a == b
(EExpr a b) == (EExpr c d) = a == c && b == d
(ELambda _ a) == (ELambda _ b) = a == b
_ == _ = False
insertExpr :: Expression s -> Expression s -> Expression s
insertExpr = insert_ 0
where insert_ level replace ref@(EReference n)
| n == level = replace
| otherwise = ref
insert_ level replace (EExpr a b) = EExpr (insert_ level replace a) (insert_ level replace b)
insert_ level replace (ELambda s e) = ELambda s (insert_ (level + 1) replace e)
insert_ _ _ symbol = symbol
apply :: Expression s -> Expression s
apply (EExpr l@(ELambda s e) b) = insertExpr b e
apply (EExpr e@(EExpr _ _) b) = EExpr (apply e) b
apply e = e
takeWhileUnique :: (Eq a) => [a] -> [a]
takeWhileUnique l = map fst $ takeWhile (\a -> not $ fst a `elem` snd a) $ zip l (inits l)
evaluate :: Expression s -> [Expression s]
evaluate = takeWhileUnique . iterate apply
_s = ESymbol
_e = EExpr
_r = EReference
_l = ELambda
main = do
putStrLn "Test nested expressions and parentheses"
print (_e (_e (_s 1) (_s 2)) (_e (_s 3) (_s 4)))
print (_e (_e (_s 1) (_e (_s 2) (_s 3))) (_s 4))
putStrLn "Test references and symbols in lambda expressions"
print (_l 5 (_l 2 (_e (_s 3) (_r 0))))
print (_l 5 (_l 2 (_e (_s 3) (_r 1))))
print (_l 5 (_l 2 (_e (_s 3) (_r 2)))) -- should fail in some way
putStrLn "More reference tests"
print (_l 1 (_e (_l 2 (_r 0)) (_l 3 (_r 1))))
print ((_r 0) :: Expression Int) -- should also fail in some way
putStrLn "Test insertion"
let t = (_l 1 (_l 2 (_r 1)))
f = (_l 1 (_l 2 (_r 0)))
n = (_l 1 (_e (_e (_r 0) f) t))
print t
print f
print n
putStrLn "Evaluating..."
mapM_ print . evaluate $ (_e n t)