packages feed

zot-0.0.2: src/SkiToLambda.hs

module SkiToLambda ( main ) where

import Data.List ( minimumBy )
import Data.Ord ( comparing )
import Control.Arrow ( ( &&& ) )

infixl 9 :$:
infixr 8 :->
data Lambda = Var String | Lambda :$: Lambda | String :-> Lambda | K | I

instance Show Lambda where
	show ( Var v )		= v
	show ap@( _ :$: _ )	= showAp ap
		where
		showAp ( f :$: a )	= showAp f ++ " " ++ par show a
		showAp e		= par show e
		par sh a@( _ :$: _ )	= "(" ++ sh a ++ ")" 
		par sh f@( _ :-> _ )	= "(" ++ sh f ++ ")"
		par sh e		= sh e
	show f@( _ :-> _ )		= '\\' : showFun f
		where
		showFun ( p :-> e )	= p ++ " " ++ showFun e
		showFun e		= "-> " ++ show e
	show K			= "K"
	show I			= "I"

size :: Lambda -> Int
size ( f :$: a )	= size f + size a
size ( _ :-> e )	= 1 + size e
size _			= 1

main :: [ String ] -> IO ()
main args = interact $ case args of
	[ ]		-> ( ++ "\n" ) . show . skiToLambda
	[ "-h" ]	-> unlines . devide 80 . show . ki . skiToLambda
	_		-> error "bad arguments"
	where
	devide _ [ ]	= [ ]
	devide n xs	= take n xs : devide n ( drop n xs )
	ki ( p :-> Var v )		| p == v	= I
	ki ( p1 :-> p2 :-> Var v )	| p1 == v	= K
					| p2 == v	= K :$: I
	ki ( f :$: a )					= ki f :$: ki a
	ki ( p :-> e )					= p :-> ki e
	ki kiv						= kiv

skiToLambda :: String -> Lambda
skiToLambda = betaKI .
	minimumBy ( comparing size ) . take 15 . iterate beta . fst . readSki 0

readSki :: Int -> String -> ( Lambda, ( Int, String ) )
readSki n ( '`' : cs )	= let	( f, ncs )	= readSki n cs
				( a, ncs' )	= uncurry readSki ncs in
				( f :$: a, ncs' )
readSki n ( c : cs )	= ( case c of
	'i'	-> fx x
	'k'	-> fx $ fy x
	's'	-> fx $ fy $ fz $ x :$: z :$: ( y :$: z )
	_	-> error "readSki error", ( n + 1, cs ) ) 
	where
	[ ( fx, x ), ( fy, y ), ( fz, z ) ] =
		( ( ( :-> ) &&& Var ) . ( : show n ) ) `map` "xyz"
readSki _ _		= error "readSki error"

beta, betaKI :: Lambda -> Lambda
beta ( fun :$: arg )	= case beta fun of
	p :-> e	-> para p ( beta arg ) e
	ex	-> ex :$: beta arg
	where
	para p a v@( Var x )	| p == x	= a
				| otherwise	= v
	para p a ( f :$: b )			= para p a f :$: para p a b
	para p a f@( q :-> e )	| p == q	= f
				| otherwise	= q :-> para p a e
	para _ _ ki				= ki
beta ( p :-> e )	= p :-> beta e
beta kiv		= kiv

betaKI ( ( p :-> v@( Var x ) ) :$: ar )
	| p == x	= ar
	| otherwise	= v
betaKI ( ( p :-> f@( q :-> Var x ) ) :$: a )
	| q == x	= f
	| p == x	= "_" :-> a
betaKI ( f :$: a )	= betaKI f :$: betaKI a
betaKI ( p :-> e )	= p :-> betaKI e
betaKI kiv		= kiv