0094 arabic takes snowballstemmer and stands outside the worker base - CyrilB1531/lodestar GitHub Wiki
0094 — Arabic takes snowballstemmer as its oracle, and stands outside SnowballWorkerBase
Status: accepted · Date: 2026-09-10
Context
Two questions had to be settled for Arabic, and
#312 named both in advance:
that normalisation is the first thing to settle, and that this lot should expect
"to justify whatever it adds to SnowballWorkerBase, or to stand apart from it
with a reason".
§1 The oracle
Every Snowball language here replays a corpus frozen from nltk, under the rule
0008 set: parity with the library a
user migrates from, over the published text.
0086 and
0092
bounded that rule — follow nltk where its rule tables differ, the description
where its representation leaks.
0091 was the first to
leave nltk entirely, because its Hungarian omits a letter class.
Arabic falls outside all of it, on a defect neither of those shapes covers:
nltk's Arabic stemmer is not a pure function. It keeps is_verb,
is_noun, is_defined and a dozen *_success flags on the instance, and the
generator holds one stemmer for a whole word list. Measured over this lot's 148
words, stemming them in sequence against stemming each with a fresh instance
differs on two:
| word | fresh instance | after the words before it |
|---|---|---|
كتبوا |
كتب |
كتبو |
كتبتم |
كتب |
تبتم |
A corpus frozen from a shared instance therefore encodes the order of the word
list, not the algorithm, and nothing downstream could see it: the same order
regenerates the same file, so Oracles are reproducible stays green. Worse, no
implementation this package could ship can reproduce it — the other fourteen
stemmers document "Thread-safe", and a stemmer whose answer depends on the words
already stemmed cannot.
nltk's Arabic also carries rules the published description does not, which the
0086/0092 bound would have sent us to nltk for — its Suffix_Noun_Step2b
removes a ست the description gives as ات only, and its Prefix_Step3b removes
a bare leading ك no prefix step lists — while omitting two the description
does state: Arabic-Indic digits folded to ASCII, and alef maksura resolved to yeh.
snowballstemmer 3.1.1 does all four the way the description reads.
§2 The worker base
SnowballWorkerBase exists for R1 and R2 — the regions, and the suffix searches
qualified by them. The published Arabic algorithm uses neither. Its own text
says so, and every guard in it is an explicit character count instead: len > 3,
≥ 4, ≥ 5, > 5. There is no vowel-driven region to compute and nothing for
Region, InR1, InR2, LongestSuffixInR1 or LongestSuffixInR2 to do.
Decision
§1 Arabic's corpus is frozen from snowballstemmer 3.1.1, as Hungarian's is.
docs/equivalence.md's Arabic row names that library, and
tests/oracles/snowball_ar.json's metadata says snowballstemmer, so which
reference a corpus froze stays readable from the corpus.
§2 ArabicSnowballStemmer does not derive from SnowballWorkerBase, and
adds nothing to it. It is the only stemmer in the package that does not.
Options
Follow nltk and document the divergence, the 0008
and 0087 shape. Rejected, and
not on size this time: it is not implementable. Reproducing a residue left by
previously-stemmed words would mean a stemmer that is not a function of its
argument, which no caller could use concurrently and no reader could interpret.
Freeze the corpus from nltk with a fresh instance per word. Rejected,
though it was written and measured first. It removes the order-dependence but
keeps the extra rules and the missing normalisation, so the corpus would still
freeze a transcription's accidents as the contract.
Exclude the affected words from the corpus. Rejected for the reason
0091 gives: a corpus
that pins the part which agrees and stays silent on the part which does not is
the opposite of what a frozen oracle is for.
Bend SnowballWorkerBase to carry length guards as well as regions.
Rejected. It would add a second, unrelated vocabulary to a class fourteen
languages read for one thing, to serve a single caller that needs none of what is
already there.
Consequences
- Arabic is the second corpus frozen from
snowballstemmer, and the reason is recorded on0008's row indocs/decisions/README.mdalongside the others, so a reader arriving at 0008 first learns that its rule now has two exceptions and what separates them. - Two of the length guards in the implementation are fitted to the corpus
rather than read from the description. The published text gives its guards per
step — noun step 1b
> 5, verb step 2a≥ 4— and this implementation merges those steps into one ordered table, where a single number has to serve both. Theنguard sits at 5 and theيguard at 4 because that is what reproduces the 146 cases; neither is a reading of the prose, and a wider corpus could move them. They are named here rather than left to look like transcription. nltk's Arabic remains usable for anyone who wants it — this decision is about what this package guarantees, and a caller comparing againstnltkon a single word in a fresh process will still see the same answers except where the four differences above apply.