Approach to Conway arithmetic in Haskell.
[ Written 1999-12-06 16:25:30]
Conway numbers are named after their inventor John H. Conway. They
generalise Cantor's ordinal numbers to support subtraction, division.
They form a complete, non-Archimedean ordered field, and have many
applications within mathematics.
They arise from consideration of a certain kind of two person game. A
game configuration consists of a set of game configurations that
"Left" can move to if they move first, and a set of game
configurations that "Right" can move to if they move first. The game
configurations are supposed to be built up inductively, so that there
are no infinite plays.
For some motivation see http://www.dcs.ed.ac.uk/~pgh/conway.html.
It is reasonably easy to represent Conway games in Haskell, using
lists to represent sets. Because one has infinite lists (ie. streams),
one can event represent certain transfinite and infinitesimal Conway games.
CODE
I have no idea what should be exported. This is a guess.
> module Conway(Game,mk_game,left_moves,right_moves
> ,(+),(-),zero,swap -- commutative group
> ,(*),one -- commutative ring
> ,eq0,gt0,lt0 -- ordered
> ,(<),(<=),eq) where
> import Prelude hiding ((+),(-),(*),(<),(<=))
> infixl 6 +
> infixl 6 -
> infixr 7 *
> data Game = Game [ Game ] [ Game ] deriving Show
> left_moves (Game ls _) = ls
> right_moves (Game _ rs) = rs
> mk_game = Game
replace left with right
> swap (Game ls rs) = Game [ swap r | r <- rs ] [ swap l | l <- ls ]
> minus = swap
addition is a kind of interleaving
> (t1@(Game ls1 rs1)) + (t2@(Game ls2 rs2))
> = Game ([ l1 + t2 | l1 <- ls1 ] `union` [ t1 + l2 | l2 <- ls2 ])
> ([ t1 + r2 | r2 <- rs2 ] `union` [ r1 + t2 | r1 <- rs1 ])
> t1 - t2 = t1 + minus t2
multiplication I have just copied from Conway's book. It is
incomprehensible to me.
> (t1@(Game ls1 rs1)) * (t2@(Game ls2 rs2))
> = Game ( [ l1 * t2 + t1 * l2 - l1 * l2 | l1 <- ls1, l2 <- ls2 ]
> ++ [ r1 * t1 + t2 * r2 - r1 * r2 | r1 <- rs1, r2 <- rs2 ])
> ( [ l1 * t2 + t1 * r2 - l1 * r2 | l1 <- ls1, r2 <- rs2 ]
> ++ [ r1 * t2 + t1 * l2 - r1 * l2 | r1 <- rs1, l2 <- ls2 ])
strat1L means that you have a winning strategy if you start on the left
strat2L means that you have a winning strategy if you're left, and right starts
etc
> strat1L (t@(Game ls _))
> = or [ strat2L l | l <- ls ]
> strat2L (t@(Game _ rs))
> = and [ strat1L r | r <- rs ]
> strat1R = strat1L . swap
> strat2R = strat2L . swap
A game is positive (gt0) in Conway's sense if left has a winning
strategy regardless who is first to go.
> gt0 g = strat1L g && strat2L g
> lt0 g = gt0 . swap
eq0 means the second player to go has a winning strategy.
Clearly eq0 = eq0 . swap, and eq0 zero.
> eq0 t = strat2L t && strat2R t
= not (strat1L t || strat1R t)
eq means there is a bisimulation between the games.
> eq t1 t2 = eq0 (t1 - t2)
> instance Eq Game where (==) = eq
> instance Ord Game where (<=) = (<=)
We have a commutative ordered ring, whose elements are
equivalence classes under (==).
> t1 < t2 = gt0 (t2 - t1)
> t1 <= t2 = not (t2 < t1)
Some examples.
> zero = Game [] []
> one = Game [zero] []
> minus_one = swap one
> two = one + one
> three = two + one
> half = Game [zero] [one]
> minus_half = swap half
> quarter = Game [zero] [half,one]
> minus_three_quarters = Game [minus_one] [minus_half,zero]
Some sanity tests.
> test1 = two + three == three + two
> test2 = (two + three) + one == two + (three + one)
> test3 = two * two == two + two
> test4 = two * three == two + two + two -- crucifies computer...
test3 causes control stack overflow...
Detritus
> nub [] = []
> nub (x:xs) = x:[ y | y <- nub xs, y /= x ]
> norm (Game ls rs) = Game ls' rs'
> where ls' = (nub . sort) [ norm l' | l' <- ls ]
> rs' = (nub . sort) [ norm r' | r' <- rs ]
> union = (++)
> union xs ys = sort (xs++ys)
> union xs ys = nub (xs ++ ys)
> sort [] = []
> sort (x:xs) = sort [ y | y <- xs, y < x ] ++ (x:sort [ y | y <- xs, x < y])
------------------------------------------------
Joyal has a paper which takes Conway numbers as its
starting point, and constructs a category. As I
remember, his definition of addition is different from Conway's.
I can't find the Joyal paper.
> jplus (t1@(Game ls1 _)) (t2@(Game _ rs2))
> = Game [ jplus l1 t2 | l1 <- ls1 ]
> [ jplus t1 r2 | r2 <- rs2 ]
> jminus t1 t2 = jplus t1 (swap t2)
> jminus' (t1@(Game ls1 _)) (t2@(Game ls2 _))
> = Game [ jminus' l1 t2 | l1 <- ls1 ]
> [ jminus' t1 l2 | l2 <- ls2 ]
s0 g means there is a winning strategy for left, going second
s1 g means there is a winning strategy for left, going first
> s0 (t@(Game _ rs)) = and [ s1 r | r <- rs ]
> s1 (t@(Game ls _)) = or [ s0 l | l <- ls ]
> jzero = Game [] []
> jone = Game [jzero] []
> js = jzero : map (jplus jone) js
> js' = jzero : map (flip jplus jone) js