packages feed

zot-0.0.1: src/ReadLambda.hs

module ReadLambda where

import Parse
import Data.Char

-- data SKI = S | K | I deriving Show

data Lambda = Var String | Apply Lambda Lambda | Fun String Lambda
	| S | K | I
	deriving Show

churchTwo :: Lambda
churchTwo =
	Fun "f" $ Fun "x" $ Apply ( Var "f" ) $ Apply ( Var "f" ) ( Var "x" )

lambdaToSKI :: Lambda -> Lambda
lambdaToSKI ( Fun x e ) = out x e
lambdaToSKI ( Apply f a ) = Apply ( lambdaToSKI f ) ( lambdaToSKI a )
lambdaToSKI nf = error $ "lambdaToSKI error: " ++ show nf

onlySKI :: Lambda -> Bool
onlySKI ( Fun _ _ )	= False
onlySKI ( Var _ )	= False
onlySKI ( Apply f a )	= onlySKI f && onlySKI a
onlySKI S		= True
onlySKI K		= True
onlySKI I		= True

notHave :: String -> Lambda -> Bool
notHave x0 ( Var x1 )
	| x0 == x1		= False
	| otherwise		= True
notHave x0 ( Fun _ e )		= notHave x0 e
notHave x0 ( Apply f a )	= notHave x0 f && notHave x0 a
notHave _ _			= True

out :: String -> Lambda -> Lambda
out x0 e
	| onlySKI e	= Apply K $ e
out x0 ( Var x1 )
	| x1 == x0	= I
	| otherwise	= Apply K $ Var x1
{-
out x0 ( Apply f ( Var x1 ) )
	| x1 == x0 && notHave x0 f	= f
-}
out x0 ( Apply f a )	= Apply ( Apply S  $ out x0 f ) $ out x0 a
out x0 ( Fun x1 e )
	| x0 == x1	= Apply K $ out x0 e
	| otherwise	= ( out x0 ) $ out x1 e
out x0 S		= Apply K S
out x0 K		= Apply K K
out x0 I		= Apply K I
-- out x0 ski		= Apply K $ ski

showApply :: Lambda -> String
showApply S = "s"
showApply K = "k"
showApply I = "i"
showApply ( Apply f a ) = "`" ++ showApply f ++ showApply a
showApply other = show other

showSKI = showApply . lambdaToSKI

readLambda :: String -> Lambda
readLambda = fst . fst . head . ( parseLambda >*> eof ) . lexer

parseLambda :: Parse String Lambda
parseLambda = parseApply `alt` parseFun

parseAtom :: Parse String Lambda
parseAtom = ( spot ( isLower . head ) `build` Var ) `alt`
	parseParens

parseParens :: Parse String Lambda
parseParens = ( token "(" >*> parseLambda >*> token ")" ) `build`
	( \( "(", ( body, ")" ) ) -> body )

parseApply :: Parse String Lambda
parseApply = recL1 Apply parseAtom

parseFun :: Parse String Lambda
parseFun =
	( token "\\" >*> parsePars >*> token "->" >*> parseLambda )
		`build` ( \( "\\", ( vs, ( "->", e ) ) ) -> makeFun vs e )

makeFun :: [ String ] -> Lambda -> Lambda
makeFun [ p ] ex	= Fun p ex
makeFun ( p : ps ) ex	= Fun p $ makeFun ps ex

parsePars :: Parse String [ String ]
parsePars = ( spot ( isLower . head ) `build` (:[]) ) `alt`
	( ( spot ( isLower . head ) >*> parsePars ) `build`
		( \( x, xs ) -> x : xs ) )

lexer :: String -> [ String ]
lexer "\n"			= [ ]
lexer ""			= [ ]
lexer ( '\\' : rest )		= "\\" : lexer rest
lexer ( '-' : '>' : rest )	= "->" : lexer rest
lexer ( ' ' : rest )		= lexer rest
lexer ( '\n' : rest )		= lexer rest
lexer ( '(' : rest )		= "(" : lexer rest
lexer ( ')' : rest )		= ")" : lexer rest
lexer ca@( c : _ )
	| isLower c		= let ( ret, rest ) = span isAlphaNum ca in
					ret : lexer rest
lexer ca			= error $ "lexer error: " ++ ca