सादृश्यम्

The Code Behind the Language

Side-by-side: Sanskrit grammar concepts mapped to their programming equivalents

The parallels between Panini's Sanskrit grammar and modern programming are not vague analogies. They are structural equivalences — the same computational patterns, discovered independently, 2,400 years apart. Here they are, side by side.

1. Dhatu → Functions धातु

Sanskrit has approximately 2,000 verbal roots called dhatu (धातु). Each dhatu is a pure semantic kernel — the abstract idea of an action. By applying different affixes (pratyaya), you derive an entire family of related words. This is function application.

Sanskrit — Root: √gam (to go)

√gam + tip → gacchati
  "he goes" (present, 3rd person)

√gam + lyap → gatvā
  "having gone" (absolutive)

√gam + tavya → gantavya
  "should be gone to" (gerundive)

√gam + ana → gamanam
  "the act of going" (noun)

√gam + tṛ → gantā
  "one who goes" (agent noun)

Programming — Function composition

function go(subject, tense, mood) {
  // The root function — pure action
  return apply(root, subject, tense, mood);
}

go(he, present, indicative)
  // → "gacchati" / he goes

go.past().then(nextAction)
  // → "gatvā" / having gone, then...

go.shouldBe(destination)
  // → "gantavya" / should be gone to

const going = go.nominalize()
  // → "gamanam" / the act of going

const goer = go.agentOf()
  // → "gantā" / one who goes

The key insight: a dhatu is not a word. It's a function — a pure operation that takes arguments (affixes) and returns derived forms. The same root √gam generates verbs, nouns, adjectives, and adverbs, all semantically connected to "going." This is exactly how functional programming works: a core function composed with different transformers to produce different output types.

2. Sandhi → Compilation & Linking सन्धि

Sandhi (सन्धि, "joining") refers to the systematic sound changes that occur when morphemes or words combine. Sanskrit has roughly 400 sandhi rules. They are deterministic: given two adjacent sounds, the output is always predictable. This is the compilation phase — where abstract tokens get linked into a concrete output.

Sanskrit — Sandhi rules

// Vowel sandhi (svara-sandhi)
iti + uktam → ityuktam
  i + u → yu (semivowel insertion)

mahā + īśvara → maheśvara
  ā + ī → e (vowel fusion)

na + asti → nāsti
  a + a → ā (lengthening)

// Consonant sandhi (hal-sandhi)
sat + cit → saccit
  t + c → cc (assimilation)

vāk + maya → vāṅmaya
  k + m → ṅm (nasal assimilation)

Programming — Linking & optimization

// Compilation: abstract → concrete
source_tokens = ["iti", "uktam"]
linked_output = link(source_tokens)
// → "ityuktam" (boundary resolved)

// Like compiler optimizations:
// Dead code elimination → vowel elision
// Constant folding → vowel fusion
// Register allocation → sound assimilation

// Both processes:
// 1. Take well-formed abstract units
// 2. Apply deterministic rules at boundaries
// 3. Produce a different but equivalent output
// 4. The output is "runnable" (speakable/executable)

When a C compiler links object files, it resolves symbol references at boundaries. When Sanskrit applies sandhi, it resolves phonetic references at word boundaries. In both cases: the semantics don't change, but the surface form transforms according to systematic rules. The compiled output is equivalent to the source — just optimized for execution (pronunciation).

3. Vibhakti → Type System विभक्ति

Sanskrit nouns carry vibhakti (विभक्ति) — grammatical case endings that mark how the noun relates to the verb. There are 8 cases (7 oblique + vocative). This IS a type system: the case ending tells you what operations are valid on this noun in this context.

Case Sanskrit Function Programming Equivalent
Nominative प्रथमा (prathamā) Subject — who does it this / self — the caller
Accusative द्वितीया (dvitīyā) Object — what is acted upon The first argument — fn(target)
Instrumental तृतीया (tṛtīyā) By means of — the tool Method / interface — using(tool)
Dative चतुर्थी (caturthī) For whom — the beneficiary Callback / destination — for(recipient)
Ablative पञ्चमी (pañcamī) From where — the source Origin / source — from(source)
Genitive षष्ठी (ṣaṣṭhī) Of / belonging to Property access — object.property
Locative सप्तमी (saptamī) In / at / on — the context Scope / context — within(context)
Vocative सम्बोधन (sambodhana) Direct address Event trigger — @notify(listener)

In Sanskrit, the same word rāma becomes rāmaḥ (nominative — he acts), rāmam (accusative — acted upon), rāmeṇa (instrumental — by means of him), rāmāya (dative — for him), and so on. The case ending is the type annotation — it tells the "parser" (the listener) exactly how this entity participates in the sentence.

This is why Sanskrit word order is free: the types are embedded IN the words themselves, not encoded by position. Just as a strongly-typed language lets you rearrange function arguments (via named parameters) without ambiguity, Sanskrit lets you rearrange words without changing meaning — because the vibhakti carries the type information.

4. Karaka → Dependency Injection कारक

Panini's karaka (कारक) theory defines 6 semantic roles that participants play in relation to a verb. These are NOT surface-level grammar labels — they're deep semantic relationships, independent of how they're expressed syntactically.

Sanskrit — Karaka roles

// The 6 karaka relations
apādāna  — source (where action originates)
sampradāna — recipient (who benefits)
karaṇa   — instrument (means of action)
adhikaraṇa — locus (where/when)
karman    — patient (what is affected)
kartṛ     — agent (who does it)

// Example:
// "The boy cuts the tree
//  with an axe in the garden"
bālakaḥ (kartṛ — agent)
vṛkṣam  (karman — patient)
kuṭhāreṇa (karaṇa — instrument)
udyāne  (adhikaraṇa — locus)
chinatti (the verb — kriyā)

Programming — Dependency injection

// The semantic roles as injected dependencies
class CutAction {
  execute({
    agent,      // kartṛ — who does it
    patient,    // karman — what is affected
    instrument, // karaṇa — by what means
    locus,      // adhikaraṇa — where/when
    source,     // apādāna — from where
    recipient   // sampradāna — for whom
  }) {
    // The verb (kriyā) doesn't know its
    // arguments at compile time — they're
    // injected at runtime by the sentence
  }
}

cut({
  agent: boy,
  patient: tree,
  instrument: axe,
  locus: garden
});

In modern NLP, these are called "semantic role labels" (SRL) — and they're one of the hardest problems in natural language processing. Panini solved it 2,400 years ago by making the roles explicit in the grammar itself. The verb doesn't need to know its arguments in advance — they're injected by the sentence context. That's dependency injection at the language level.

5. The Sivasutras → Data Compression माहेश्वर सूत्राणि

Before Panini could write his grammar, he needed a way to refer to groups of phonemes efficiently. His solution: the 14 Maheshvara Sutras (also called Shiva Sutras) — a sequence of 43 phonemes arranged so that any natural class of sounds can be referenced by a two-letter abbreviation.

अ इ उ ण् | ऋ ऌ क् | ए ओ ङ् | ऐ औ च् | ह य व र ट् | ल ण् | ञ म ङ ण न म् | झ भ ञ् | घ ढ ध ष् | ज ब ग ड द श् | ख फ छ ठ थ च ट त व् | क प य् | श ष स र् | ह ल्

To refer to "all vowels," Panini writes aC — take from a to the marker C (च्). To refer to "all consonants," he writes haL — from h to marker L (ल्). Any contiguous subsequence between a phoneme and a marker letter defines a pratyahara (abbreviation) — a natural class.

Sanskrit — Pratyahara system

aC = a, i, u, ṛ, ḷ, e, o, ai, au
  → all vowels

haL = h, y, v, r, l, ñ, m, ṅ, ṇ, n,
       jh, bh, gh, ḍh, dh, j, b, g, ḍ, d,
       kh, ph, ch, ṭh, th, k, p, ś, ṣ, s
  → all consonants

yaṆ = y, v, r, l
  → semivowels only

jhaŚ = jh, bh, gh, ḍh, dh, j, b, g, ḍ, d
  → voiced stops

Programming — Equivalent patterns

// Like regex character classes,
// but more efficiently encoded

const vowels = /[aeiouṛḷ]/
  // Panini: "aC" (2 characters)

const consonants = /[^aeiou]/
  // Panini: "haL" (3 characters)

// Or like bitfield ranges:
// Panini's sutras are a lookup table
// where ranges are defined by start+marker
// 42 phonemes → 300+ natural classes
// using only 2-3 character abbreviations

// This is BETTER than regex.
// It's a purpose-built compression scheme.

The arrangement of phonemes in the Sivasutras is not alphabetical. It's optimized — phonemes that Panini needs to group together in his rules are placed so they can be captured by a single pratyahara. This is the same design principle as CPU instruction encoding: arrange the bits so that common operations can be expressed compactly. Panini's 14 sutras encode 300+ natural phoneme classes in a system that never needs more than 3 characters per reference. Try doing that with regex.

6. Rule Ordering → Specificity & Precedence परिभाषा

The Ashtadhyayi's 3,959 rules can conflict — multiple rules may apply to the same input. Panini solves this with meta-rules (paribhasha) that define which rule wins. The most famous: vipratiṣedhe paraṃ kāryam — "in a conflict, the later rule prevails."

But there's a deeper principle: apavāda (exception) overrides utsarga (general rule). A specific rule always beats a general one. This is exactly CSS specificity — an inline style overrides a class selector, which overrides an element selector. It's also exception handling in programming: catch(SpecificError) takes precedence over catch(Error).

Sanskrit — Rule precedence

// General rule (utsarga):
6.1.77 — iko yaṇ aci
  "Before a vowel, i/u/ṛ/ḷ become
   y/v/r/l" (semivowel substitution)

// Exception (apavāda):
6.1.101 — akaḥ savarṇe dīrghaḥ
  "a/i/u/ṛ followed by a similar vowel
   become long" (a+a→ā, i+i→ī)

// Exception beats general:
a + a → ā  (rule 6.1.101 wins)
a + i → e  (different rule applies)
i + a → ya (rule 6.1.77 wins)

Programming — CSS specificity

/* General rule (low specificity) */
p { color: black; }

/* More specific (class) */
.highlight { color: blue; }

/* Most specific (id) */
#title { color: red; }

/* Exception handling: */
try {
  process(input);
} catch (SpecificError e) {
  // This catches first (apavāda)
} catch (Error e) {
  // General fallback (utsarga)
}

// Same principle: specific beats general

The Pattern

These aren't six isolated coincidences. They point to a deeper truth: language IS computation. Whether you're processing Sanskrit morphemes or JavaScript tokens, the fundamental operations are the same — composition, transformation, pattern matching, type checking, scoping, and conflict resolution.

Panini didn't invent these patterns. He discovered them — in the structure of language itself. And when computer scientists needed to build systems that manipulate symbols according to rules, they rediscovered the same patterns. Because there's only one mathematics underlying both.

The gap between 400 BCE and 1959 CE isn't a gap in intelligence. It's a gap in documentation.