Sunday, December 11, 2011

sthAne antaratamaH

A Functional Approach

It is very interesting to observe that Panini's approach to sandhi-s is thoroughly function oriented and very algebraic in execution. Sandhi-s in Samskritam are profound sophistications. We shall see how functional programming naturally fits into Panini's approach. Once again I'm not describing theories, but real testable executable code and assertable outputs.

For the samskritam-dsl project, I was trying to come up with a simplistic representation of sandhi-s. The famous iko yan aci sandhi belongs to the purva rupa sandhi (the first word gets modified) and Panini's general technique can be functionally written as:

f = sandhi(sthana, adesha, vidhi, purva, para)

This is understood as:  "The adesha (substitute) replaces the sthana (substituted) of the purva shabda when vidhi is true on the para shabda"

Panini uses natural linguistic approach and places sthana in 6th vibhakti, adesha in 1st vibhakti and vidhi in 7th vibhakti.

So lets rewrite this in functional programming notation -

  //purva rupa sandhi sutra - closure
  def purvaRupaSandhi = {sthana, adesha, condition, words ->
    def (purva, para) = words.tokenize()
    if (condition(para)) {
      def k = sthana.substitute(adesha, purva.lastVarna())
      purva + para
    } else {

Here sthana is the list of substituted varnas (eg ik), adesha is the substitute varna (yaN). Condition is not a list but something that evaluates to true or false based on the para shabda. So its a closure again.

  def aci = { word -> word.varnas()[0].svara() }
  def jshi = { word -> word.varnas()[0] in sivaSutra.jsh }

Basically the above closure evaluates to true if the first varna of the shabda is a svara.

Remember we defined the purvaRupaSandhi as a completely generic closure. It will take any sthana, adesha and condition. How do we apply this to iko yaN aci or say, jhalaam jash jhashi?

Groovy provides the "currying" feature --

  def iko_yaN_aci = purvaRupaSandhi.curry(sivaSutra.ik, sivaSutra.yN, aci)
  def JalAm_jash_Jashi = purvaRupaSandhi.curry(sivaSutra.Jl, sivaSutra.js, jshi)

Real functional programming stuff here. aci and jshi are closures/functions which are passed to purvaRupaSandhiwhich evaluates it based on the para shabda.

Now for some more beauty. How do we substitute sthana with adesha? Panini defines a really brilliant sutra 'sthAne antaratamaH' - the closest phoneme of the adesha to the sthana, must substitute the sthana. Now how do we find the closest ? When pronouncing it is easy to realize that i is close to y or u is close to v. But how does that translate to programming terms? This is when it dawns upon us that Panini's approach is extremely methodical.

Recall the definitions of phoneme-sets?

akUhavisarjaniyanaam kanTaH | icuyashaanaam taalu | RturaShaaNaam mUrhda | Ltulasaanaam danta | upUpadhmaanIyaanaam oshta |

So if a varna from sthAna exists in one of the above sets of phonemes, then the common varna between that phoneme-set and the adesha will substitute the sthana !!!

Illustration: jhalaam_jas_jashi

example: ap + dhi

purva shabda - ap (varna is p), para shabda - dhi, satisifies condition jashi (dha). Good.

sthAna - p, adesha will be one of jash = [j, b, g, d, dh] -- now which to pick?

p exists in oshta phoneme-set; so we have to pick one from pu = [p, ph, b, bh, m] - but which one?

Remember jash adesha is [j, b, g, d, dh]. So intersect oshta with adesha, which will result in b -> that substitutes 'p' - resulting in abdhi !

Can you now appreciate the functional beauty of maheshvara sutra?

So the formula is
  def ku = [k, kh, g, gh, ~n]
  def kanta = ['a', 'A'] + ku + ['h'] + [':']
    Closure sthaneAntaratamaH = { x, adesha ->
    for (def phonemeSet : [kanta, taalu, murdha, danta, oshta, dantoshtam]) {
      if (x in phonemeSet) return phonemeSet.intersect(adesha)

That's it!! The 2 closures basically take care of any purva rupa sandhi rule! Only the additional conditional closures (aci, jashi etc.) must be provided as required.

Finally we verify

assert iko_yan_aci("iti api") == "ityapi"
assert jhalaam_jash_jashi("ap dhi") == "abdhi"

As usual the code can be found at

PS: Post this blog, I tried to verify purvaRupaSandhi closure by adding another rule "stoH shcuna shcu:" and it worked just fine. But there is a catch. The shcuna in the rule is not in 7th vibhakti, but is in instrumental case. And there is a reason why Panini uses 3rd vibhakti. The 7th vibhakti indicates the rule to be applied with respect to what follows, while the 3rd vibhakti implies just the contact of two varna-s are sufficient to produce the sandhi. The closure does not take care of that yet.

The functional programming approach of Panini makes me believe that universities should include ashTAdhyAyI as a course in Computer Science, instead of just being a research subject to elite academicians.


vishvAs vAsuki said...

एतत् व्याकरणविषये अपि मे ज्ञानदमस्ति। कार्तज्ञं अर्पये।

PS: The following terminology seems more natural and friendlier to a lay audience : meta-functions (in place of closure) and partially applied functions (in place of currying). The concepts themselves are fairly natural.

Vasu Srinivasan said...

@vishvas mahodaya - satyam eva | bhavataa uktaani padaani sulabhaaya | kadaacit technical words yojane sati sulabha viShayaaH manasi na utpadyante | blog madhye spaShTI kariShyaami ||