zot-0.0.1: src/SkiToLambda.hs
module SkiToLambda ( main ) where
import System.Environment
data Lambda = Var String | Apply Lambda Lambda | Fun String Lambda
deriving Show
main :: [ String ] -> IO ()
main args = do
-- ( n : rest ) <- getArgs
let ( n : rest ) = args
case rest of
[ ] -> interact $ ( ++ "\n" ) . showLambda . applyApp . applyI .
times ( read n ) apply . one . readSKI 0
[ "-h" ] -> interact $ unlines . devide 80 . showLambdaTop . applyApp . applyI .
times ( read n ) apply . one . readSKI 0
where
one ( x, _, _ ) = x
times :: Int -> ( a -> a ) -> a -> a
times 0 _ x = x
times n f x = times ( n - 1 ) f $ f x
devide :: Int -> [ a ] -> [ [ a ] ]
devide n [ ] = [ ]
devide n xs = take n xs : devide n ( drop n xs )
skiToLambda :: String -> String
skiToLambda = fst . parens
readSKI :: Int -> String -> ( Lambda, String, Int )
readSKI n ( '`' : rest ) = let
( f, rest2, n2 ) = readSKI n rest
( a, rest3, n3 ) = readSKI n2 rest2 in
( Apply f a, rest3, n3 )
readSKI n ( 'i' : rest ) = ( Fun x $ Var x, rest, n + 1 )
where x = "x" ++ show n
readSKI n ( 'k' : rest ) = ( Fun x $ Fun y $ Var x, rest, n + 1 )
where x = "x" ++ show n
y = "y" ++ show n
readSKI n ( 's' : rest ) = ( Fun x $ Fun y $ Fun z $
Apply ( Apply ( Var x ) ( Var z ) ) ( Apply ( Var y ) ( Var z ) ), rest, n +1 )
where x = "x" ++ show n
y = "y" ++ show n
z = "z" ++ show n
showLambda, showLambdaH, showLambdaApply, showLambdaFun :: Lambda -> String
showLambda ( Var v ) = v
showLambda ( Apply f a ) = "(" ++ showLambda f ++ " " ++ showLambda a ++ ")"
showLambda ( Fun p e ) = "(\\" ++ p ++ " -> " ++ showLambda e ++ ")"
showLambdaTop ( Apply f a ) = showLambdaApply f ++ " " ++ showLambdaH a
showLambdaTop ( Fun p e ) = "\\" ++ p ++ showLambdaFun e
showLambdaTop v = showLambdaH v
showLambdaH ( Var v ) = v
showLambdaH ( Apply f a ) = "(" ++ showLambdaApply f ++ " " ++ showLambdaH a ++ ")"
showLambdaH ( Fun p ( Var v ) )
| p == v = "I"
showLambdaH ( Fun p1 ( Fun p2 ( Var v ) ) )
| p1 == v = "K"
| p2 == v = "KI"
-- | otherwise = "hoge"
showLambdaH ( Fun p e ) = "(\\" ++ p ++ showLambdaFun e ++ ")"
showLambdaApply ( Apply f a ) = showLambdaApply f ++ " " ++ showLambdaH a
-- showLambdaApply ( Fun p e ) = "\\" ++ p ++ showLambdaFun e
showLambdaApply e = showLambdaH e
showLambdaFun ( Fun p e ) = " " ++ p ++ showLambdaFun e
showLambdaFun e = " -> " ++ showLambdaApply e
parens :: String -> ( String, String )
parens ( '`' : rest ) = let
( f, rest2 ) = parens rest
( a, rest3 ) = parens rest2 in
( "(" ++ f ++ " " ++ a ++ ")", rest3 )
parens ( c : rest ) = ( [ c ], rest )
applyI :: Lambda -> Lambda
applyI ( Apply ( Fun p ( Var v ) ) ar )
| p == v = ar
| otherwise = Var v
applyI ( Apply ( Fun p1 ( Fun p2 ( Var v ) ) ) a )
| p2 == v = Fun p2 ( Var v )
| p1 == v = Fun p2 a
applyI ( Apply f a ) = Apply ( applyI f ) $ applyI a
applyI ( Fun p e ) = Fun p $ applyI e
applyI ( Var v ) = Var v
applyApp :: Lambda -> Lambda
applyApp ( Apply ( Fun p ( Apply ( Var v ) a ) ) f )
| p == v = Apply f a
applyApp ( Apply f a ) = Apply ( applyApp f ) $ applyApp a
applyApp ( Fun p e ) = Fun p $ applyApp e
applyApp ( Var v ) = Var v
apply :: Lambda -> Lambda
apply ( Apply fr ar ) = case apply fr of
Fun p e -> applyPara p ( apply ar ) e
nf -> Apply nf ( apply ar )
apply ( Fun p e ) = Fun p ( apply e )
apply ( Var v ) = Var v
applyPara :: String -> Lambda -> Lambda -> Lambda
applyPara p a1 ( Var v )
| p == v = a1
| otherwise = Var v
applyPara p a1 ( Apply f a2 ) = Apply ( applyPara p a1 f ) ( applyPara p a1 a2 )
applyPara p1 a1 ( Fun p2 e )
| p1 == p2 = Fun p2 e
| otherwise = Fun p2 $ applyPara p1 a1 e