Skip to main content

Isomorphisms & Meaning

Haskell juvenilia; investigating when two theories or representations mean the same things.

Metaphors and analogies are the coin of human thought and key to interpretation in art. We often speak of systems being translatable or being equivalent in some sense, and especially we want to use systems to look at each other and gain insight; but a translation between systems with no commonality strikes us as senseless and wrong in some way. We know that some translations are good and valid, and some are not. But how are we judging this?

Mad Morphisms

Translations become more pathological the more detailed and thorough they are. That such translations are not useful, or of value, or even harmless is the reason why we need to know what separates the healthy from the ill; you may not be interested in diseased thinking, but diseased thinking is interested in you (ask survivors of ideological regimes like Communism). Umberto Eco’s Foucault’s Pendulum has a passage in chapter 66 (one of many well worth reading) on this mania:

“Last night I happened to come across a driver’s manual. Maybe it was the semidarkness, or what you had said to me, but I began to imagine that those pages were saying Something Else. Suppose the automobile existed only to serve as metaphor of creation? And we mustn’t confine ourselves to the exterior, or to the surface reality of the dashboard; we must learn to see what only the Maker sees, what lies beneath. What lies beneath and what lies above. It is the Tree of the Sefirot.”

“You don’t say.”

“I am not the one who says; it is the thing itself that says. The drive shaft is the trunk of the tree. Count the parts: engine, 2 front wheels, clutch, transmission, two axles, differential, and 2 rear wheels. Ten parts, ten Sefirot.”

“But the positions don’t coincide.”

“Who says they don’t? Diotallevi explained to us that in certain versions Tiferet isn’t the sixth Sefirah, but the eighth, below Nezah and Hod. My axle-tree is the tree of Belboth.”


“But let’s pursue the dialectic of the tree. At the summit is the engine, Omnia Movens, of which more later: this is the Creative Source. The engine communicates its creative energy to the 2 front or higher wheels: the Wheel of Intelligence and the Wheel of Knowledge.”

“If the car has front-wheel drive.”

“The good thing about the Belboth tree is that it allows metaphysical alternatives. So we have the image of a spiritual cosmos with front-wheel-drive, where the engine, in front, transmits its wishes to the higher wheels, whereas in the materialistic version we have a degenerate cosmos in which motion is imparted by the engine to the 2 lower wheels: from the depths, the cosmic emanation releases the base forces of matter.”

“What about an engine in back, rear-wheel drive?”

“Satanic. Higher and lower coincide. God is identified with the motion of crude matter. God as an eternally frustrated aspiration to divinity. The result of the Breaking of the Vessels [tsim-sun].”

“Not the Breaking of the Muffler?”

“That occurs in aborted universes, where the noxious breath of the Archons spreads through the ether. But we mustn’t digress. After the engine and 2 wheels comes the clutch, the Sefirah of grace that establishes or interrupts the flow of love that binds the rest of the tree of the Supernal Energy. A disk, a mandala that caresses another mandala. Then the coffer of change—the gear box, or transmission, as the positivists call it, which is the principle of Evil, because it allows human will to speed up or slow down the constant process of emanation. For this reason, an automatic transmission costs more, for there it is the tree itself that decides, in accordance with its own Sovereign Equilibrium. Then comes the universal joint, the axle, the drive shaft, the differential–note the opposition/repetition of the quaternion of cylinders in the engine, because the differential (Minor Keter) transmits motion to the earthly wheels. Here the function of the Sefirah of difference is obvious, as, with a majestic sense of beauty, it distributes the cosmic forces to the Wheel of Glory and the Wheel of Victory, which in an unaborted universe (front-wheel drive) are subordinate to the motion imparted by the higher wheels.”

“A coherent exegesis. And the heart of the engine, seat of the One, the Crown?”

“You have but to look with the eyes of an initiate. The supreme engine lives by an alternation of intake and exhaust. A complex, divine respiration, a cycle initially based on 2 units called cylinders (an obvious geometrical archetype), which then generate a third, and finally gaze upon one another in mutual love and bring forth the glory of a fourth. In the cycle of the first cylinder (none is first hierarchically, but only through the miraculous alternation of position), the piston (etymology: Pistis Sophia) descends from the upper neutral position to the lower neutral position as the cylinder fills with energy in the pure state. I’m simplifying, because here angelic hierarchies come into play, the valves, which, as my handbook says, ‘allow the opening and closing of the apertures that link the interior of the cylinders to the induction pipes leading out of the carburetor.’ The inner seat of the engine can communicate with the rest of the cosmos only through this mediation, and here I believe is revealed—I am reluctant to utter heresy—the original limit of the One, which, in order to create, somehow depends on the Great Eccentrics. A closer reading of the text may be required here. The cylinder fills with energy, the piston returns to the upper neutral position and achieves maximum compression–the tsim-sun. And lo, the glory of the Big Bang: combustion, expansion. A spark flies, the mixture of fuel flares and blazes, and this the handbook calls the active phase of the cycle. And woe, woe if in the mixture of fuel the Shells intrude, the qelippot, drops of impure matter like water or Coca-Cola. Then expansion does not take place or occurs in abortive starts…”

“Then the meaning of Shell is qelippot? We’d better not use it anymore. From now on, only Virgin’s Milk…”

“We’ll check. It could be a trick of the Seven Sisters, lower emanations trying to control the process of creation…In any case, after expansion, behold the great divine release, the exhaust. The piston rises again to the upper neutral position and expels the formless matter, now combusted. Only if this process of purification succeeds can the new cycle begin. Which, if you think about it, is also the Neoplatonic mechanism of Exodus and Parodos, miraculous dialectic of the Way Up and the Way Down.”

Quantum mortalia pectora ceacae noctis habent!1 And the sons of matter never realized it!”

“They never saw the connection between the philosopher’s stone and Firestone.”

“For tomorrow, I’ll prepare a mystical interpretation of the phone book.”

The acute reader will be either horrified or amused by the foregoing. Sometimes the translating is self-consciously void of any truth, and being used solely didactically; no-one reading through the tedious allegories of Pilgrim’s Progress will seriously think that the layout of a room ‘really’ has anything to do with Protestant Christianity. But then didn’t the readers of the past who made it a best-seller which every English and American family had a copy of (sitting next to their Bible) take it quite seriously? Wasn’t it a commonplace of older theological thought that everything in the Bible had—at the very least—2 meanings (such as the exoteric and esoteric)? Why is it a bad interpretation?

Telling the Good from Bad

But sometimes they are clearly wrong and senseless (such as interpreting The Rime of the Ancient Mariner through quantum mechanics), but the author plows onward convinced he is engaged in valuable interpretation, and other times they are dangerously close to being plausible (Old Testament ethics & injunctions for modern life, or perhaps economics—Keynesian or Austrian). How do we know what is a valid translation, when there is a real isomorphism?

I suggest we can test isomorphisms by seeing whether the same manipulations on the same starting points give us the same results. The more such similarities there are, the more similar the systems are; the more analogies can be trusted. When all such manipulations coincide, then we can call the 2 systems the same.

Unary versus Decimal

Here’s an example of what I mean. Suppose we had invented the decimal number system, and also an unary system. Sometimes one system is more convenient than the other—decimal’s great for multiplication & division, but an unary system can be physically instantiated with sticks or pebbles and worked with in the dark. You notice that the 2 systems seem to have a lot of shared traits, and working in one is a lot like working in the other; indeed, you happen to’ve formalized your decimals and have put a lot of effort into proving various theorems about them—wouldn’t it be nice if you could easily translate them into theorems also about your new unary system? Perhaps there are good analogies between the systems.

We can’t be sure a priori that they’re just the same, that they’re both number systems and have done with it. Complex numbers function differently from the hyperreals, which are very different from the natural numbers. Or, another example might be if we add 2 apples together, we have 2 things; but if I add 2 pails of liquids together, I have only 1 water—it’s the volume that increases, not the number of components.2

So if we were interested in showing a good translation between unary and decimal, what would this even mean? Well, it would mean that a round-trip property holds: if we take a system as a single function, ‘round-trip’ means we’re asking for a bijection between the inputs and outputs of the 2 functions. For example, we can turn a decimal into an unary and then back again into the original, and vice-versa. If we prefer to see our systems as little machines or networks of ‘states’, we’re defining their equality as a bisimulation.

Hacking the Code

OK, so how can we show that? Let’s do a little Haskell programming.

Translating Back and Forth

Unary numbers as we know are just defined as a sequence of an arbitrary token; obviously the number of these tokens, the length of the sequence, is its numerical value. So if we define a unary type which is just a list of some arbitrary marker, to turn it into a decimal, we just get its length. And we do the opposite—we ask for a list of length n for the number n. The code:

type Unary = [()]
unaryToDecimal :: Unary -> Int
unaryToDecimal = length

decimalToUnary :: Int -> Unary
decimalToUnary a = replicate a ()

And our property is that Decimal → Unary → Decimal is a lossless transformation, as is Unary → Decimal → Unary. Let’s express these as QuickCheck properties (QuickCheck doesn’t provide formal proofs, but it will test random inputs looking for disproofs of the property):

udProp x = x>=0 ==> -- discard all non-natural integers
                unaryToDecimal (decimalToUnary x) == x
duProp x = decimalToUnary (unaryToDecimal x) == x

QuickCheck duly verifies that these two properties were true for all the cases it devised.

Check Addition

Now let’s tackle a more interesting case. A mapping from just items in one system to items in another system is boring and not very valuable. What would be more valuable is if we knew some things like addition were the same!

So here our property is that if we translate 2 numbers into Unary and add them and translate the result back into Decimal, we get the same number as we would have in Decimal adding.

First, what is adding in unary? As each ‘number’ is a list of discrete elements, we can assume, I think, that concatenating the 2 lists together is enough. Haskell is nice enough to let us define + on lists if we ask politely:

{-# LANGUAGE TypeSynonymInstances #-}

type Unary = [()]

instance Num Unary where
    (+) = (++)
-- We reuse the + defined on Ints, of course

This seems intuitively right. If ||||→4, and |||||→5, and 9→|||||||||, then the obvious way from |||| and ||||| to ||||||||| is to smash them together. (Is intuition not good enough a justification? Well, it’s simple; and it’s not like all the other possible operators for implementing addition in unary have any better claim to our attention. The ultimate justification is whether it works.)

So two properties looks like:

unEqualDec x y = (x>=0 && y>=0) ==> x+y == unaryToDecimal ((decimalToUnary x) + (decimalToUnary y))
decEqualUn x y = x+y == decimalToUnary ((unaryToDecimal x) + (unaryToDecimal y))

QuickCheck again will tell us that they pass the testcases it devised.

Success? Not quite.

Essential vs Accidental

We can think of other properties that decimals have, but which unary can’t. For example, one can note that (, , etc.)

How would we express this in unary? The key is that we’re speaking about 0—and yet unary has no 0! That’s part of the definition, for if it had one symbol for nothingness, and another symbol for something, then it’s a binary number system and not unary. That’s why we’ve dealt with natural numbers throughout: zero is present in unary by the absence of any unary number at all. There is no naming of it, no indirection that allows us to speak of or mention it. We can’t say anything like ‘if 0 is in the ones place, then adding the leading numeral gives us a typographical duplication’. Suppose we tried some contorted scheme involving division by 10; but would this work when we try to find an isomorphism to, say, octal or hexadecimal?

If this example doesn’t satisfy you, consider other possible properties. How about properties based on how many vowels the English words of a number have? We can get sillier, but I think the point is clear: there are ‘essential’ properties and ‘accidental’ ones. The vowel-count of ‘five’ is accidental, but something like is essential.

When the systems are formalized such that we can ask for their bijection or their bisimulation, then we have well-defined ways to see whether essential properties hold. (Peter de Blanc suggests that if an agent has a simple model of the world, it can update its model based on surprising observations by picking a new, more complex model, which accounts for all past observations but differs minimally—as defined by Kullback-Leibler divergence—from the previous model.)

How to know when something is essential, and when the property is accidental, is unclear, and this is because, as Alan J. Perlis reminds us, “One can’t proceed from the informal to the formal by formal means.”

Appendix: the Code

A few notes on the code:

  • we have that LANGUAGE pragma there so we can define our own addition on lists (as the default List type doesn’t define a silly thing like addition); - the very acute Haskeller will be asking himself, “why not define the abstract structure as that of a monoid (see Data.Monoid3), and get list concatenation & integer addition for free?” That’s because while there’s only one sensible monoid on lists, there are 2 for integers—Sum and Product.

  • we’re actually using Ints here which allow for both negative and positive integers, while unary notation is usually just for the naturals (and the encoding of negative numbers into unary is tedious), so we generally ignore the possibility of negative numbers except our test property, unEqualDec, which just discards any negative numbers.

  • we don’t define a newtype or data for Unary because that’s overkill

The consolidated code, with type signatures and a test harness:

{-# LANGUAGE TypeSynonymInstances #-}
import Test.QuickCheck

type Unary = [()]

instance Num Unary where
    (+) = (++)

unaryToDecimal :: Unary -> Int
unaryToDecimal = length

decimalToUnary :: Int -> Unary
decimalToUnary a = replicate a ()

-- Roundtrip: number->number
udProp :: Int -> Property
udProp x = x>=0 ==> -- discard all non-natural integers
                unaryToDecimal (decimalToUnary x) == x

duProp :: Unary -> Bool
duProp x = decimalToUnary (unaryToDecimal x) == x

-- Roundtrip: addition->concatenation
unEqualDec :: Int -> Int -> Property
unEqualDec x y = (x>=0 && y>=0) ==> x+y == unaryToDecimal ((decimalToUnary x) + (decimalToUnary y))

decEqualUn :: Unary -> Unary -> Bool
decEqualUn x y = x+y == decimalToUnary ((unaryToDecimal x) + (unaryToDecimal y))

-- test harness
test :: IO ()
test = do quickCheck udProp
          quickCheck duProp
          quickCheck unEqualDec
          quickCheck decEqualUn

  1. “ye gods, how much dark night there is / in mortal breasts!” Ovid.↩︎

  2. To those who argue that the number of atoms doubled when I added the 2 pails together: what if the 2 liquids have different densities?↩︎

  3. apfelmus’s fingertree tutorial also ably covers monoids.↩︎

Similar Links

[Similar links by topic]