tag:blogger.com,1999:blog-11295132.post115699923292640924..comments2015-09-16T20:54:40.355-07:00Comments on A Neighborhood of Infinity: Geometric Algebra for Free!Dan Piponihttps://plus.google.com/107913314994758123748noreply@blogger.comBlogger24125tag:blogger.com,1999:blog-11295132.post-51203566774604748192013-06-13T17:46:08.685-07:002013-06-13T17:46:08.685-07:00Yes, i figured out that you work at Google. I am ...Yes, i figured out that you work at Google. I am a first level link to Peter. (He is very busy and has many of these.) He is my friend actually.John Roodhttp://www.blogger.com/profile/16126451592989412577noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1310508757805317972013-06-13T17:22:55.300-07:002013-06-13T17:22:55.300-07:00@john rood I work at the same company as Peter Nor...@john rood I work at the same company as Peter Norvig.<br /><br />I'm actually not really sure what the relationship is between dual numbers and SDG. Dual numbers have nilpotents because they're an ordinary algebraic structure in a classical framework. SDG has nilpotents because it's in a non-classical logic where for the relevant notion of real number, d^2=0 doesn't imply d=0.Dan Piponihttp://www.blogger.com/profile/08096190433222340957noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-26869424138796933942013-06-13T17:10:39.481-07:002013-06-13T17:10:39.481-07:00I will want to absorb this. For me, this is a &qu...I will want to absorb this. For me, this is a "random find". I was looking for links between dual numbers and synthetic differential geometry on the net and this blog came up.<br /><br />I will give three hints about myself. I am old--age 62. I just finished Coursera's Exploring Quantum Physics MOOC of Galitski and Clark. I am a coauthor of a paper with Peter Norvig from very long ago (cf Norvig.com).John Roodhttp://www.blogger.com/profile/16126451592989412577noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-57657523293241965462013-06-13T16:53:37.744-07:002013-06-13T16:53:37.744-07:00@john rood It is what it is :-)@john rood It is what it is :-)Dan Piponihttp://www.blogger.com/profile/08096190433222340957noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-29229779702173693752013-06-13T16:43:25.460-07:002013-06-13T16:43:25.460-07:00Hmmm. Mentions Bott Periodicity. So we are into ...Hmmm. Mentions Bott Periodicity. So we are into K-Theory. Maybe get to the Atiyah-Singer Index Theorem.<br /><br />And we are implementing things in Haskell. Very interesting.<br /><br />What IS this blog??John Roodhttp://www.blogger.com/profile/16126451592989412577noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-62658662987136896342013-06-13T16:39:41.843-07:002013-06-13T16:39:41.843-07:00Hmmm. Very interesting.
I'm coming here from...Hmmm. Very interesting.<br /><br />I'm coming here from the page about Synthetic Differential Geometry.<br /><br />This gives at least some partial indications about the relationship of that stuff to Clifford Algebras, at least by implication ... .<br /><br />Supersymmetry, etc??John Roodhttp://www.blogger.com/profile/16126451592989412577noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-35783130311573548662007-11-21T14:28:00.000-08:002007-11-21T14:28:00.000-08:00The link you gave to my preprint at UNSW does not ...The link you gave to my preprint at UNSW does not work. <BR/>The reference is:<BR/>Paul Leopardi, "A generalized FFT for Clifford algebras", Bulletin of the Belgian Mathematical Society - Simon Stevin, Volume 11, Number 5, 2005, pp. 663-688. <BR/> Preprint: <A HREF="http://www.maths.unsw.edu.au/applied/files/2004/amr04_17.pdf" REL="nofollow">UNSW Applied Mathematics Report AMR04/17, March 2004.</A> <BR/> <BR/>See also the <A HREF="http://glucat.sf.net" REL="nofollow">GluCat</A> C++ template library.penguianhttp://www.blogger.com/profile/14921873057415307983noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157668288466536582006-09-07T15:31:00.000-07:002006-09-07T15:31:00.000-07:00Before I forget again, let me thank sigfpe for thi...Before I forget again, let me thank sigfpe for this post. I'd heard of geometric algebra, but I'd never been interested enough to find out what it is. Also, it's cool to know what Complex (Complex Float) means.<BR/><BR/>augustss: <I>Using Template Haskell isn't always an option. It turns the creation of the type into something static, which isn't always what you want [...]</I><BR/><BR/>True enough. My suspicion is that most programs using Clifford algebras will know which algebra they want at compile time, but it is possible to defer the choice to run time.<BR/><BR/>Ignoring the parameterization over the base field, we can write:<BR/><BR/>cliff :: Int -> (forall a. (Clifford a, Num a) => a -> w) -> w<BR/>cliff 1 k = k (undefined :: Cliff1)<BR/>cliff 2 k = k (undefined :: Cliff2)<BR/>cliff n k = cliff' (n-2) (\(_::a) -> k (undefined :: Quaternion a))<BR/><BR/>cliff' :: Int -> (forall a. (Clifford a, Num a) => a -> w) -> w<BR/>cliff' 1 k = k (undefined :: Cliff1')<BR/>cliff' 2 k = k (undefined :: Cliff2')<BR/>cliff' n k = cliff (n-2) (\(_::a) -> k (undefined :: Matrix a))<BR/><BR/>Doing this while parameterizing over the base field is trickier, because we need to construct the dictionaries, but I'm confident it can be done.Dave Menendezhttp://www.blogger.com/profile/10628628100970152906noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157648874675528932006-09-07T10:07:00.000-07:002006-09-07T10:07:00.000-07:00Often when you find symmetries like that it's for ...<EM><BR/>Often when you find symmetries like that it's for some reason.<BR/></EM><BR/>The Clifford algebras are all about symmetries. But overall "e 0" upsets more symmetries than it appears to reveal.sigfpehttp://www.blogger.com/profile/08096190433222340957noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157637507533524572006-09-07T06:58:00.000-07:002006-09-07T06:58:00.000-07:00Dave,Using Template Haskell isn't always an option...Dave,<BR/><BR/>Using Template Haskell isn't always an option. It turns the creation of the type into something static, which isn't always what you want (well, I know next to nothing of Geometric Algebra, so I'm guessing).<BR/>Also, using TH gives up static type checking in the same sense as using templates in C++. I don't like that.augustsshttp://www.blogger.com/profile/05153404423721072935noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157606548731608522006-09-06T22:22:00.000-07:002006-09-06T22:22:00.000-07:00That looks rather neat. :) And it's the right thin...<I>That looks rather neat. :) And it's the right thing to do. The I type was a hack. But does it extend to the MkCliff class in a natural way?</I><BR/><BR/>Probably, although I haven't tried.<BR/><BR/>I don't know enough about geometric algebra to judge usage cases, but it seems to me that it would be easier to generate types for Clifford algebras using Template Haskell.<BR/><BR/>Something along these lines::<BR/><BR/>cliff 1 r = [t| Complex $r |]<BR/>cliff 2 r = [t| Quaternion $r |]<BR/>cliff n r = [t| Quaternion $(cliff' (n-2) r) |]<BR/><BR/>cliff' 1 r = [t| Split $r |]<BR/>cliff' 2 r = [t| Matrix $r |]<BR/>cliff' n r = [t| Matrix $(cliff (n-2) r) |]<BR/><BR/>(Unfortunately, GHC won't accept this. Apparently, you can't splice in a type declaration, so you'd have to work directly with the expression tree.)<BR/><BR/>Going further, it should be possible to write a metaprogram that takes a description of a Clifford algebra and codes up an appropriate optimized implementation.Dave Menendezhttp://www.blogger.com/profile/10628628100970152906noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157599806398094842006-09-06T20:30:00.000-07:002006-09-06T20:30:00.000-07:00Dave,That looks rather neat. :) And it's the rig...Dave,<BR/>That looks rather neat. :) And it's the right thing to do. The I type was a hack. But does it extend to the MkCliff class in a natural way?<BR/><BR/>So what this whole thing really needs is dependent types. But not having that, I think we could fake something with type level naturals for getting the type of e right. It really needs to have size n.augustsshttp://www.blogger.com/profile/05153404423721072935noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157599570417293482006-09-06T20:26:00.000-07:002006-09-06T20:26:00.000-07:00sigfpe,So I can see that e :: Vector n -> Cliff n ...sigfpe,<BR/>So I can see that e :: Vector n -> Cliff n would make sense. But just looking at the code, it looks like 'i' is begging to be 'e 0'. :)<BR/>Often when you find symmetries like that it's for some reason.augustsshttp://www.blogger.com/profile/05153404423721072935noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157593187972972932006-09-06T18:39:00.000-07:002006-09-06T18:39:00.000-07:00The code you wrote can be parameterized on R witho...<I>The code you wrote can be parameterized on R without any tricks at all, see below. The only troublesome case is 'instance Clifford R'.</I><BR/><BR/>It doesn't have to be. Instead of trying to define a general instance, Clifford r r, just write separate instances for any base field you want.<BR/><BR/>instance Clifford Float Float where<BR/>{ i a = a<BR/>; e _ _ = undefined<BR/>}<BR/><BR/>Incidentally, what about defining e to return a list of basis vectors? (Assuming I have the terminology right.)<BR/><BR/>class (Num a) => Clifford r a where<BR/>{ i :: r -> a<BR/>; e :: [a]<BR/>}<BR/><BR/>instance Clifford Double Double where<BR/>{ i a = a<BR/>; e = []<BR/>}<BR/><BR/>instance (Clifford r a) => Clifford r (Quaternion a) where<BR/>{ i a = Q (i a) 0 0 0<BR/>; e = [Q 0 1 0 0, Q 0 0 1 0] ++ [Q 0 0 0 a | a <- e]<BR/>}Dave Menendezhttp://www.blogger.com/profile/10628628100970152906noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157589707487727122006-09-06T17:41:00.000-07:002006-09-06T17:41:00.000-07:00augustss,A followup to saying:In a suitable progra...augustss,<BR/><BR/>A followup to saying:<BR/><BR/><EM>In a suitable programming language I'd replace e with something of type e :: Vector(n) -> Cliff(n).<BR/></EM><BR/><BR/>I could have written the code like this from day 1. But I'm interested in eventually figuring out an efficient implementation of this function that doesn't simply map multiples of each basis element in turn and then sum the results. (I think that's what the FFT paper I linked to does but I'm deliberately trying not to read that paper yet...)sigfpehttp://www.blogger.com/profile/08096190433222340957noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157589463387850822006-09-06T17:37:00.000-07:002006-09-06T17:37:00.000-07:00augustss,First,Why is 'i' a separate method? Would...augustss,<BR/><BR/><EM><BR/>First,<BR/>Why is 'i' a separate method? Wouldn't 'e 0' instead of 'i' make sense?<BR/></EM><BR/><BR/>I definitely want to keep i and e separate. Conceptually they do different things: one is embedding the base field in the algebra and the other is embedding an n-dimensional vector space in the algebra. In a suitable programming language I'd replace e with something of type e :: Vector(n) -> Cliff(n). I definitely don't want to fold in the scalar part to get Vector(n+1) -> Cliff(n) because Cliff(n) acts on Vector(n) in an important way.<BR/><BR/><EM>Second,<BR/>The code you wrote can be parametrized on R without any tricks at all, see below. The only troublesome case is 'instance Clifford R'....<BR/></EM><BR/>Yes, that's exactly where I had trouble. I even played with fundeps but didn't quite get the solution you have.<BR/><BR/>I'll probably fold your latest addition into the code I added last weekend. I wrote stuff to deal with isomorphisms between algebraic structures eg. Quaternion (Quaternion a) is, in some sense, isomorphic to Matrix (Matrix a), although the isomorphism is non-trivial. Turns out these isomorphisms have a nice application and I'll post something about it eventually.sigfpehttp://www.blogger.com/profile/08096190433222340957noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157549704810109432006-09-06T06:35:00.000-07:002006-09-06T06:35:00.000-07:00A few more comments:First,Why is 'i' a separate me...A few more comments:<BR/><BR/>First,<BR/>Why is 'i' a separate method? Wouldn't 'e 0' instead of 'i' make sense?<BR/><BR/>Second,<BR/>The code you wrote can be parametrized on R without any tricks at all, see below. The only troublesome case is 'instance Clifford R'. When you make R a parameter this gets to be a very general instance declaration, and those are often "dangerous", by that I mean that they apply far to often. So I've introduced the I type that is just the identity.<BR/><BR/>Furthermore, the 'b -> r' part of the class declaration is only important if you want to avoid adding a lot of type signatures. It just says that the base type, r, is uniquely determined by the Clifford type itself (which is true). Without this vital clue the compiler sometimes cannot deduce types.<BR/><BR/>> type Cliff1 r = Complex r<BR/>> type Cliff1' r = Split r<BR/>> type Cliff2 r = Quaternion r<BR/>> type Cliff2' r = Matrix r<BR/>> type Cliff3 r = Quaternion (Cliff1' r)<BR/>> type Cliff3' r = Matrix (Cliff1 r)<BR/>> type Cliff4 r = Quaternion (Cliff2' r)<BR/>> type Cliff4' r = Matrix (Cliff2 r)<BR/><BR/>> class Clifford b r | b -> r where<BR/>> i :: r -> b<BR/>> e :: Int -> r -> b<BR/><BR/>> newtype I r = I r deriving (Eq, Ord, Show, Num)<BR/>> instance Clifford (I r) r where<BR/>> i a = I a<BR/>> e _ _ = error ""<BR/><BR/>> instance (Num r) => Clifford (Complex r) r where<BR/>> i a = C a 0<BR/>> e 1 a = C 0 a<BR/><BR/>> instance (Num r) => Clifford (Split r) r where<BR/>> i a = S a a<BR/>> e 1 a = S a (-a)<BR/><BR/>> instance (Num b,Clifford b r) => Clifford (Quaternion b) r where<BR/>> i a = Q (i a) 0 0 0<BR/>> e 1 a = Q 0 (i a) 0 0<BR/>> e 2 a = Q 0 0 (i a) 0<BR/>> e n a = Q 0 0 0 (e (n-2) a)<BR/><BR/>> instance (Num b,Clifford b r) => Clifford (Matrix b) r where<BR/>> i a = let b = i a in M b 0 0 b<BR/>> e 1 a = let b = i a in M (-b) 0 0 b<BR/>> e 2 a = let b = i a in M 0 b b 0<BR/>> e n a = let b = e (n-2) a in M 0 b (-b) 0<BR/><BR/><BR/>> type Cliff5 r = Quaternion (Cliff3' r)<BR/>> type Cliff5' r = Matrix (Cliff3 r)<BR/>> type Cliff6 r = Quaternion (Cliff4' r)<BR/>> type Cliff6' r = Matrix (Cliff4 r)<BR/>> type Cliff7 r = Quaternion (Cliff5' r)<BR/>> type Cliff7' r = Matrix (Cliff5 r)<BR/>> type Cliff8 r = Quaternion (Cliff6' r)<BR/>> type Cliff8' r = Matrix (Cliff6 r)<BR/>> type Cliff9 r = Quaternion (Cliff7' r)<BR/>> type Cliff9' r = Matrix (Cliff7 r)<BR/><BR/>> t i = e i 1 :: (Cliff9 Float)<BR/>> t' i = e i 1 :: (Cliff9' Float)augustsshttp://www.blogger.com/profile/05153404423721072935noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157495310400253892006-09-05T15:28:00.000-07:002006-09-05T15:28:00.000-07:00The (c :: * -> *) is just there to tell the type c...The (c :: * -> *) is just there to tell the type checker that the type variable c has kind *->*. The class declaration itself does not contain enough information to determine the kind otherwise, so the compiler would assume *.<BR/>The 'n -> c' part just says that n uniquely determines c.<BR/><BR/>Yes, many things that are simple in mathematics get more complicated in programming languages. The big reason being that mathematicians are smarter than computers. :)augustsshttp://www.blogger.com/profile/05153404423721072935noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157493660395111622006-09-05T15:01:00.000-07:002006-09-05T15:01:00.000-07:00Hey! That was quick work!Now you're using Haskell ...Hey! That was quick work!<BR/><BR/>Now you're using Haskell features I'm not familiar with, like the line "class MkCliff n (c :: * -> *) | n -> c". It's going to take me some time to digest this.<BR/><BR/>I think Clifford algebras might make a great case study for developing ideas about statically typed programming languages specifically for mathematics. Haskell is good, but you're having to use ingenious tricks to express things that mathematicians would like to be easy.sigfpehttp://www.blogger.com/profile/08096190433222340957noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157486078750486642006-09-05T12:54:00.000-07:002006-09-05T12:54:00.000-07:00There's more than one way to skin a cat, but here'...There's more than one way to skin a cat, but here's one way to make the base type a parameter.<BR/><BR/>I've also introduced a new method in Clifford that returns the grade so the test is more generic.<BR/><BR/>The use of I and Compose is a bit of an ugly trick since Haskell only allows data types in instance declarations. There must be a neater way to do this.<BR/><BR/>It's interesting how MkCliff only builds the data type structure of the algebra and then the Clifford class provides the computational contents.<BR/><BR/><BR/>class Clifford b r where<BR/> i :: r -> b r<BR/> e :: Int -> r -> b r<BR/> g :: b r -> Int -- the grade<BR/><BR/>newtype I a = I a<BR/><BR/>instance Clifford I a where<BR/> i a = I a<BR/> e _ _ = error ""<BR/> g _ = 0<BR/><BR/>instance (Num a) => Clifford Complex a where<BR/> i a = C a 0<BR/> e 1 a = C 0 a<BR/> g _ = 1<BR/><BR/>instance (Num a) => Clifford Split a where<BR/> i a = S a a<BR/> e 1 a = S a (-a)<BR/> g _ = 1<BR/><BR/>newtype Compose f g a = O (f (g a)) deriving (Eq, Show, Num)<BR/><BR/>instance (Num (b r), Clifford b r) => Clifford (Compose Quaternion b) r where<BR/> i a = O $ Q (i a) 0 0 0<BR/> e 1 a = O $ Q 0 (i a) 0 0<BR/> e 2 a = O $ Q 0 0 (i a) 0<BR/> e n a = O $ Q 0 0 0 (e (n-2) a)<BR/> g ~(O (Q a _ _ _)) = 2 + g a<BR/><BR/>instance (Num (b r), Clifford b r) => Clifford (Compose Matrix b) r where<BR/> i a = O $ let b = i a in M b 0 0 b<BR/> e 1 a = O $ let b = i a in M (-b) 0 0 b<BR/> e 2 a = O $ let b = i a in M 0 b b 0<BR/> e n a = O $ let b = e (n-2) a in M 0 b (-b) 0<BR/> g ~(O (M a _ _ _)) = 2 + g a<BR/><BR/>class MkCliff n (c :: * -> *) | n -> c<BR/>class MkCliff' n (c :: * -> *) | n -> c<BR/><BR/>instance MkCliff N0 I<BR/>instance MkCliff' N0 I<BR/>instance MkCliff N1 Complex<BR/>instance MkCliff' N1 Split<BR/><BR/>instance (MkCliff' n c) => MkCliff (Plus2 n) (Compose Quaternion c)<BR/>instance (MkCliff n c) => MkCliff' (Plus2 n) (Compose Matrix c)<BR/><BR/>mk_i :: (MkCliff n c, Clifford c a) => n -> a -> c a<BR/>mk_i _ = i<BR/>mk_e :: (MkCliff n c, Clifford c a) => n -> Int -> a -> c a<BR/>mk_e _ = e<BR/>mk'_i :: (MkCliff' n c, Clifford c a) => n -> a -> c a<BR/>mk'_i _ = i<BR/>mk'_e :: (MkCliff' n c, Clifford c a) => n -> Int -> a -> c a<BR/>mk'_e _ = e<BR/><BR/>n9 = undefined :: N9<BR/><BR/>t i = mk_e n9 i (1::Double)<BR/>t' i = mk'_e n9 i (1::Double)<BR/><BR/>test a t = map (\(i,j) -> (t i)*(t j)+(t j)*(t i)==0) [(i,j) | i <- [1..n], j <- [1..(i-1)]] ++<BR/> map (\i -> (t i)*(t i)==a) [1..n]<BR/> where n = g (t undefined)<BR/><BR/>fulltest = and $ (test (-1) t) ++ (test 1 t')augustsshttp://www.blogger.com/profile/05153404423721072935noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157472750403901332006-09-05T09:12:00.000-07:002006-09-05T09:12:00.000-07:00augustss,That's pretty nice. I particularly liked ...augustss,<BR/><BR/>That's pretty nice. I particularly liked the use of 'undefined' that almost makes the type N9 feel like a first class object in Haskell. I'd not seen that trick before.<BR/><BR/>One thing I couldn't figure out was how to make all of the code generic with respect to the base field - so I locked it down with 'type R = Float'. I tried lots of messing about with multiparameter type classes and fundeps but a compile error would always crop up somewhere.<BR/><BR/>And I'm kinda surprised that someone actually did something with my code!sigfpehttp://www.blogger.com/profile/08096190433222340957noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157469833051285402006-09-05T08:23:00.000-07:002006-09-05T08:23:00.000-07:00When you say some things are better described in C...When you say some things are better described in C++, I presume you mean the function that takes an n and generates the type Cliff(n).<BR/><BR/>But just to show that how it looks in Haskell here's some code. The big difference between the Haskell and C++ versions of doing this is that the Haskell version is actually type checked, whereas in C++ it would only be checked when instantiating the template. (Also the Haskell version allows the argument n to be a dynamic (runtime) argument rather than static.)<BR/><BR/><BR/>First some preliminaries no define type level natural numbers.<BR/><BR/>> data Zero<BR/>> data Succ a<BR/>> type N0 = Zero<BR/>> type N1 = Succ N0<BR/>> type N2 = Succ N1<BR/>> type N3 = Succ N2<BR/>> type N4 = Succ N3<BR/>> type N5 = Succ N4<BR/>> type N6 = Succ N5<BR/>> type N7 = Succ N6<BR/>> type N8 = Succ N7<BR/>> type N9 = Succ N8<BR/>> type Plus2 n = Succ (Succ n)<BR/><BR/>The MkCliff and MkCliff' classes are really functions from n, a type level nutural, to c, which is Cliff(n) resp. Cliff'(n).<BR/><BR/>> class MkCliff n c | n -> c<BR/>> class MkCliff' n c | n -> c<BR/><BR/>The base cases for the Clifford algebras.<BR/><BR/>> instance MkCliff N0 R<BR/>> instance MkCliff' N0 R<BR/>> instance MkCliff N1 (Complex R)<BR/>> instance MkCliff' N1 (Split R)<BR/><BR/>And finally the inductive cases.<BR/><BR/>> instance (MkCliff' n c) => MkCliff (Plus2 n) (Quaternion c)<BR/>> instance (MkCliff n c) => MkCliff' (Plus2 n) (Matrix c)<BR/><BR/>Define the i and e functions, but now taking an extra argument that define which algebra to embed into.<BR/><BR/>> mk_i :: (MkCliff n c, Clifford c) => n -> R -> c<BR/>> mk_i _ = i<BR/>> mk_e :: (MkCliff n c, Clifford c) => n -> Int -> R -> c<BR/>> mk_e _ = e<BR/>> mk'_i :: (MkCliff' n c, Clifford c) => n -> R -> c<BR/>> mk'_i _ = i<BR/>> mk'_e :: (MkCliff' n c, Clifford c) => n -> Int -> R -> c<BR/>> mk'_e _ = e<BR/><BR/>And then define t and t' again.<BR/><BR/>> n9 = undefined :: N9<BR/><BR/>> t i = mk_e n9 i 1<BR/>> t' i = mk'_e n9 i 1augustsshttp://www.blogger.com/profile/05153404423721072935noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157397821203799162006-09-04T12:23:00.000-07:002006-09-04T12:23:00.000-07:00Dude, you rock. Very interesting stuff.Dude, you rock. Very interesting stuff.Slava Pestovhttp://www.blogger.com/profile/06320065558397702966noreply@blogger.comtag:blogger.com,1999:blog-11295132.post-1157213069620522052006-09-02T09:04:00.000-07:002006-09-02T09:04:00.000-07:00It would be great to have your blog on planet.hask...It would be great to have your blog on planet.haskell.org . You can email antti [dash] juhani [at] kaijanaho.info to confirm if you like, as he won't add you on without your permission.Jim Applehttp://www.blogger.com/profile/04833814608894128430noreply@blogger.com