module reduce

import StdGeneric, StdEnv

// or crush
generic gReduce t :: (a a -> a) a  t -> a
gReduce{|c|} op e x 					= e
gReduce{|PAIR|} fx fy op e (PAIR x y) 	= op (fx op e x) (fy op e y)
gReduce{|EITHER|} fl fr op e (LEFT x) 	= fl op e x
gReduce{|EITHER|} fl fr op e (RIGHT x) 	= fr op e x
gReduce{|CONS|} f op e (CONS x) 		= f op e x 
gReduce{|FIELD|} f op e (FIELD x) 		= f op e x
gReduce{|OBJECT|} f op e (OBJECT x) 	= f op e x

generic gReduceRSt t :: .t .st -> .st
gReduceRSt{|c|} x st 					= st
gReduceRSt{|UNIT|} x st 				= st
gReduceRSt{|PAIR|} fx fy (PAIR x y) st 	= fx x (fy y st)
gReduceRSt{|EITHER|} fl fr x st 		= reduceEITHER fl fr x st
gReduceRSt{|CONS|} f (CONS x) st 		= f x st
gReduceRSt{|FIELD|} f (FIELD x) st 		= f x st
gReduceRSt{|OBJECT|} f (OBJECT x) st 	= f x st

generic gReduceLSt t :: .t .st -> .st
gReduceLSt{|c|} x st 					= st
gReduceLSt{|UNIT|} x st 				= st
gReduceLSt{|PAIR|} fx fy (PAIR x y) st 	= fy y (fx x st)
gReduceLSt{|EITHER|} fl fr x st 		= reduceEITHER fl fr x st
gReduceLSt{|CONS|} f (CONS x) st 		= f x st
gReduceLSt{|FIELD|} f (FIELD x) st 		= f x st
gReduceLSt{|OBJECT|} f (OBJECT x) st 	= f x st

reduceEITHER fl fr (LEFT x) st 			= fl x st
reduceEITHER fl fr (RIGHT x) st 		= fr x st

fldr :: (.a -> .(.b -> .b)) .b .(t .a) -> .b | gReduceRSt{|*->*|} t & bimap{|*|} b
fldr op e xs = gReduceRSt{|*->*|} op xs e  

fldl :: (.b -> .(.a -> .b)) .b .(t .a) -> .b | gReduceLSt{|*->*|} t & bimap{|*|} b
fldl op e xs = gReduceLSt{|*->*|} (flip op) xs e

:: Tree a b = Tip a | Bin b (Tree a b) (Tree a b)
:: Rose a = Rose a .[Rose a]
:: Fork a = Fork a a
:: Sequ a = SequEmpty | SequZero .(Sequ .(Fork a)) | SequOne a .(Sequ .(Fork a))

derive gReduceRSt [], Tree, Rose, Fork, Sequ
derive gReduceLSt [], Tree, Rose, Fork, Sequ

Start = 
	( fldr cons [] [1,2,3]
	, fldl (flip cons) [] [1,2,3]
	, fldr cons [] (Rose 1 [Rose 2 [], Rose 3 []])
	, fldr cons [] (SequZero (SequOne (Fork 1 2) (SequOne (Fork (Fork 3 4) (Fork 5 6)) SequEmpty)))	
	, gReduceRSt{|*->*->*|} cons cons (Bin 1 (Tip 2) (Tip 3)) []
	)
where
	cons x xs = [x:xs]	