Lingua::Conjunction
WorksTurn a list into a natural-language phrase — a, b, and c — with control over the conjunction, the Oxford comma, the separator and the language.
- Version
1.3zef:raku-community-modules- Depends
none beyond the core- License
- Artistic-2.0
- Its own test suite
- 1 file, green
- Checked
- 2026-09-15 against Raku++ 3.28.0 and Rakudo 2026.08
Install it #
$ rakupp install Lingua::Conjunctionzef install Lingua::Conjunction writes the same store; either installer leaves the module usable by both engines.
What it is for #
@items.join(', ') gives you apples, oranges, pears, which is not what a person writes. What a person writes is apples, oranges, and pears — with no comma at all when there are two items, and no conjunction when there is one.
Getting that right is four special cases, and every program that reports to a human needs it.
Building a phrase #
use Lingua::Conjunction;
for ('apples',), <apples oranges>, <apples oranges pears>, <a b c d> -> @l {
say sprintf('%-34s => %s', @l.raku, conjunction(|@l));
}
say '';
say 'type => or : ', conjunction(<a b c>, :type<or>);
say 'type => and : ', conjunction(<a b c>, :type<and>);("apples",) => apples
("apples", "oranges") => apples and oranges
("apples", "oranges", "pears") => apples, oranges, and pears
("a", "b", "c", "d") => a, b, c, and d
type => or : a, b, or c
type => and : a, b, and cOne item comes back unchanged, two get a bare conjunction with no comma, three or more get the Oxford comma. That is the English convention, and it is four branches you no longer have to write.
The switches #
use Lingua::Conjunction;
say 'default : ', conjunction(<a b c>);
say ':last (Oxford) : ', conjunction(<a b c>, :last);
say ':!last (no comma): ', conjunction(<a b c>, :!last);
say '';
say 'a template : ', conjunction(<a b c>, :str('I want |list| today'));
say '';
say 'empty list : ', conjunction().raku;
say 'one item : ', conjunction('solo').raku;default : a, b, and c
:last (Oxford) : a, b, and c
:!last (no comma): a, b and c
a template : I want a, b, and c today
empty list : ""
one item : "solo":last controls the serial comma. The :str template drops the phrase into a sentence, which saves an interpolation.
The empty list returns "" and a single item returns itself — neither is an error, which is worth knowing if you expect the conjunction word to always be there.
Other languages #
use Lingua::Conjunction;
for <en fr es de> -> $lang {
say sprintf('%-4s => %s', $lang, conjunction(<a b c>, :$lang));
}en => a, b, and c
fr => a, b et c
es => a, b, y c
de => a, b, und cFrench drops the serial comma, Spanish and German keep it. The language table is small; ja is present and produces a doubled space where the conjunction should be, so treat anything beyond these four as untested.
The one thing to know #
An item that already contains the separator silently changes the separator for the whole list.
use Lingua::Conjunction;
say 'ordinary items : ', conjunction(<toast jam tea>);
say 'one item has a comma in it:';
say ' ', conjunction('eggs, bacon', 'toast', 'jam');
say '';
say 'the alternate separator is ; by default, and :alt changes it:';
say ' ', conjunction('eggs, bacon', 'toast', 'jam', :alt(' / '));ordinary items : toast, jam, and tea
one item has a comma in it:
eggs, bacon; toast; and jam
the alternate separator is ; by default, and :alt changes it:
eggs, bacon / toast / and jamLinguistically this is the right call — a comma-separated list of items that themselves contain commas is unreadable — and it is clearly deliberate. What it means in practice is that the shape of the output depends on the content of the data: the same call site produces a, b, and c for one dataset and a; b; and c for another.
Anything that parses, splits or tests the result against a fixed separator works until a user types a comma.
Where the two engines differ #
Only on stderr, and only for some inputs: Rakudo emits Use of Nil in string context from line 38 of the module where Raku++ is silent. Every phrase in this page was byte-identical.
The switch worth knowing about and not using: :lang<ja> emits an empty conjunction word, so conjunction(<a b c>, :lang<ja>) comes back as a, b c with a doubled space. The four European languages above are the ones that work.