Copyright © 2025 Jan Moringen

spell User's Manual
*******************

This manual is for spell version 0.0.3.

1 Introduction
**************

The spell library provides protocols and implementations of those
protocols for automatic spell-checking and suggestion of likely
corrections.  In addition to the spelling of words, dictionary entries
contain information about word types and properties of the words such as
case, gender and number.  At the moment, English is the only supported
language.

2 External Protocols
********************

This chapter describes the external protocols provided by the spell
library.

2.1 English Protocol
====================

This protocol provides the highest level of abstraction within the spell
library.  The protocol consists of a few functions that perform the most
common operations with minimal setup effort.

 -- Function: spell:english-lookup string

     Return a (possibly empty) list of entries in the English dictionary
     the spelling of which matches STRING.

     The returned entries are instances of word.
     More than one entry in the dictionary can match
     STRING due to different word types or multiple combinations of
     properties within a word type that share a common spelling.

     Note that clients which are interested only in the validity of
     STRING and not in the matching dictionary entries can treat the
     return value as a generalized Boolean.

     Examples:
          (spell:english-lookup "lithp")
          ⇒ NIL

          (spell:english-lookup "lisp")
          ⇒ (#<EXPLICIT-BASE-VERB "lisp" person:ANY number:ANY ... infinitive:SELF {1004ED5993}>
             #<EXPLICIT-BASE-NOUN "lisp" number:SINGULAR case:NIL gender:NIL {1004ED3533}>)

 -- Function: spell:english-check-paragraph string

     Check the paragraph of English text STRING for spelling errors and
     return a list of detected errors.

     The return value of this function is a possibly empty list of
     entries of the form (START-INDEX . END-INDEX).  The START-INDEX and
     END-INDEX within each entry designate a sub-string of STRING that
     corresponds to a misspelled word.

     Example:
          (spell:english-check-paragraph "In Polish, a horse is koń, and in German, it's
          das Pferd.")
          ⇒ ((22 . 25) (47 . 50) (51 . 56))

     The three pairs in the result correspond to sub-strings that are
     not valid English words:

          (loop :with string = "In Polish, a horse is koń, and in German, it's
          das Pferd."
                :for (start . end) :in (spell:english-check-paragraph string)
                :collect (subseq string start end))
          ⇒ ("koń" "das" "Pferd")

 -- Function: spell:english-corrections string &key threshold variants
          group-by count

     Return entries from the English dictionary that are at most
     THRESHOLD removed from STRING in terms of edit-distance.  Return
     two values: a list of entries and a Boolean which indicates whether
     STRING is spelled correctly according to the English dictionary.
     By default, the elements of the list that is the first return value
     are unique strings that correspond to the spellings of matching
     dictionary entries.  The caller can use the GROUP-BY parameter (see
     below) to make the function return pairs of word
     instances and spellings instead.

     If supplied, THRESHOLD has to be a non-negative integer that
     controls the maximum edit-distance of returned corrections from
     STRING.  Note that the value 0 for THRESHOLD is not very useful
     since english-lookup is a
     simpler way to perform that operation.

     If supplied, VARIANTS has to be a function that accepts as its
     arguments a string and another function which it must call once for
     each case variant of the string that should be considered.  The
     default value is a more complete and sophisticated version of the
     following:
          (lambda (continuation string)
            (funcall continuation string)
            (when ‘certain-conditions’
              (funcall continuation (string-decapitalized string)))
            (when ‘certain-conditions’)
              (funcall continuation (string-downcase string)))

     If supplied, GROUP-BY has to be either :spelling or :entry.  It
     controls whether word objects are included in elements of the
     returned list.  If GROUP-BY is :entry, elements are of the form
     (WORD . SPELLING).  If GROUP-BY is :spelling, elements are strings
     and each string is one spelling.  The default is :spelling.  Note
     that the value of GROUP-BY influences the number returned elements
     since a spelling that corresponds to multiple entries will be
     reported once for :spelling but multiple times for :entry.

     If supplied, COUNT controls the maximum number of entries that are
     returned as the first value.

     Examples:
          (spell:english-corrections "lisp" :threshold 1)
          ⇒ ("lisp" "lisps" "list" "lip" "limp" "wisp") T

          (spell:english-corrections "lifp" :threshold 1)
          ⇒ ("lift" "life" "lip" "lisp" "limp") NIL

          (spell:english-corrections
           "abc" :threshold 1
                 :variants (lambda (continuation string)
                             (funcall continuation (string-upcase string))))
          ⇒ ("ABC" "ABCs") T

          (spell:english-corrections
           "abc" :threshold 1
                 :variants (lambda (continuation string)
                             (funcall continuation (string-upcase string)))
                 :group-by :entry)
          ⇒ ((#<EXPLICIT-BASE-NOUN "ABC" number:SINGULAR ...> . "ABC")
             (#<EXPLICIT-BASE-NOUN "ABC" number:PLURAL ... > . "ABCs"))
            T

2.2 Word Protocols
==================

Entries in spell dictionaries are conceptually pair: an (implicit)
string that is the spelling and a word object that characterizes the
word type and the type-specific properties of the word.  Word objects
are instance of subclasses of word.  spell
defines the following sub-classes of word and
associated readers:

     word.
     +-see adjective.
     +-see adverb.
     +-see conjunction.
     | `-see subordinate.
     +-see determiner.
     | +-see article.
     | +-see demonstrative-adjective.
     | +-see interrogative-adjective.
     | +-see possessive-adjective.
     | `-see quantifier.
     +-see interjection.
     +-see noun.
     | +-see noun-verb-contraction.
     | `-see proper-noun.
     +-see preposition.
     +-see pronoun.
     | +-see demonstrative-pronoun.
     | +-see personal-pronoun.
     | +-see possessive-pronoun.
     | `-see reflexive-pronoun.
     `-see verb.
       +-see noun-verb-contraction.
       `-see verb-verb-contraction.

Word Class word
---------------

 -- Class: spell:word ()
     Superclass for all word classes.

 -- Generic Function: spell:base word
     Return the base word of WORD.

     For words of type noun, the base word is usually the nominative,
     singular variant of the word.

     For words of type verb, the base word is usually the infinitive
     variant of the word.

Word Class adjective
--------------------

 -- Class: spell:adjective (see word)
     Instances represent adjectives, that is a property of a noun
     together with the degree of that property.

 -- Generic Function: spell:degree word
     Return a keyword which indicates the degree for WORD.

     Possible values are :positive, :comparative and :superlative.

Examples
zinkier        #<EXPLICIT-BASE-ADJECTIVE "zincy"
               degree:COMPARATIVE {100CEA1883}>

wroughter      #<EXPLICIT-BASE-ADJECTIVE "wrought"
               degree:COMPARATIVE {100CE576D3}>

well-wornest   #<EXPLICIT-BASE-ADJECTIVE "well-worn"
               degree:SUPERLATIVE {100CD45EF3}>

Word Class adverb
-----------------

 -- Class: spell:adverb (see word)
     Instances represent adverb, that is a property of a verb.

Examples
unstoppably    #<EXPLICIT-BASE-ADVERB "unstoppably"
               {100CB2E753}>

twistingly     #<EXPLICIT-BASE-ADVERB "twistingly"
               {100CA301F3}>

together       #<EXPLICIT-BASE-ADVERB "together" {100C86C173}>

Word Class conjunction
----------------------

 -- Class: spell:conjunction (see word)
     Direct instances represent conjunctions, that is words which
     connect sentences or clauses.

Examples
seeing         #<EXPLICIT-BASE-CONJUNCTION "seeing"
               {100B542143}>

providing      #<EXPLICIT-BASE-CONJUNCTION "provided"
               {100AE1B513}>

either         #<EXPLICIT-BASE-CONJUNCTION "either"
               {100E468F43}>

Word Class subordinate
----------------------

 -- Class: spell:subordinate (see word,
          conjunction)
     Instances represent subordinates, that is conjunctions which
     connect a dependent and an independent clause.

Examples
whether        #<EXPLICIT-BASE-SUBORDINATE "whether"
               {100CD84A83}>

that           #<EXPLICIT-BASE-SUBORDINATE "that" {100C77D873}>

if             #<EXPLICIT-BASE-SUBORDINATE "if" {1001A7DFB3}>

Word Class determiner
---------------------

 -- Class: spell:determiner (see word)
     Instances are determiners, that is words which determine one or
     more aspect, such as the grammatical number, of a noun.  Also a
     superclass for several more specific determiner classes.

 -- Generic Function: spell:number word
     Return a keyword which indicates the number for entities related to
     WORD.

     If WORD is a verb, the keyword indicates the number of agents who
     perform the action.

     If WORD is a noun, the keyword indicates the number of objects or
     people the noun refers to.  Similarly for pronouns.

     If WORD is a determiner (or a more specific word sub type), the
     number refers to the associated noun.

     Possible values are :any, :singular and :plural.

Word Class article
------------------

 -- Class: spell:article (see word,
          determiner)
     Instances are articles, that is determiners which specify whether a
     noun refers to a particular or an arbitrary entity.

 -- Generic Function: spell:determinate word
     Return a Boolean which indicates whether the noun associated with
     WORD refers to particular or an arbitrary entity.

Examples
the            #<EXPLICIT-BASE-ARTICLE "the" number:SINGULAR
               determinate:T {100C7C2133}>

a              #<EXPLICIT-BASE-ARTICLE "a" number:SINGULAR
               determinate:NIL {100E468F83}>

an             #<EXPLICIT-BASE-ARTICLE "an" number:SINGULAR
               determinate:NIL {100E468F93}>

Word Class demonstrative-adjective
----------------------------------

 -- Class: spell:demonstrative-adjective (see word,
          determiner)
     Instances represent demonstrative adjectives, that is determiners
     which highlight the fact that an associated noun is identifiable
     from the context.

Examples
this           #<EXPLICIT-BASE-DEMONSTRATIVE-ADJECTIVE "this"
               number:SINGULAR {100C7DA0E3}>

these          #<EXPLICIT-BASE-DEMONSTRATIVE-ADJECTIVE "these"
               number:PLURAL {100C7C0D23}>

that           #<EXPLICIT-BASE-DEMONSTRATIVE-ADJECTIVE "that"
               number:SINGULAR {100C7935C3}>

Word Class interrogative-adjective
----------------------------------

 -- Class: spell:interrogative-adjective (see word,
          determiner)
     Instances represent interrogative adjectives, that is adjectives

Examples
which          #<EXPLICIT-BASE-INTERROGATIVE-ADJECTIVE "which"
               number:ANY {100CD85E23}>

what           #<EXPLICIT-BASE-INTERROGATIVE-ADJECTIVE "what"
               number:ANY {100CD758B3}>

Word Class possessive-adjective
-------------------------------

 -- Class: spell:possessive-adjective (see word,
          determiner)
     Instances represent possessive adjectives, that is determiners
     which mark a noun as being possessed by another entity.

 -- Generic Function: spell:refnumber word
     Return a keyword which indicates the grammatical number of the
     possessing entity referenced by WORD.

     Possible values are :any, :singular and :plural.

 -- Generic Function: spell:person word
     Return a keyword which indicates the grammatical person of entities
     associated with WORD.

     Possible values are :any, :first, :second, :third.

 -- Generic Function: spell:gender word
     Return a keyword which indicates the gender of entities related to
     WORD.

     Possible values are nil, :masculine, :feminine and :neuter.

Examples
its            #<EXPLICIT-BASE-POSSESSIVE-ADJECTIVE "its"
               number:ANY gender:ANY person:THIRD
               refnumber:SINGULAR {100284BA73}>

his            #<EXPLICIT-BASE-POSSESSIVE-ADJECTIVE "his"
               number:ANY gender:MASCULINE person:THIRD
               refnumber:SINGULAR {100191CA63}>

her            #<EXPLICIT-BASE-POSSESSIVE-ADJECTIVE "her"
               number:ANY gender:FEMININE person:THIRD
               refnumber:SINGULAR {10018B6E93}>

Word Class quantifier
---------------------

 -- Class: spell:quantifier (see word,
          determiner)
     Instances are quantifiers, that is determiners which specify count
     or amount of a noun.

Examples
enough         #<EXPLICIT-BASE-QUANTIFIER "enough" number:ANY
               {100E468EA3}>

eleven         #<EXPLICIT-BASE-QUANTIFIER "eleven"
               number:PLURAL {100E468EB3}>

either         #<EXPLICIT-BASE-QUANTIFIER "either"
               number:SINGULAR {100E468EC3}>

Word Class interjection
-----------------------

 -- Class: spell:interjection (see word)
     Instances represent interjections, that is words which interrupt
     the sequence of words within a sentence or the sequence of
     sentences.

Examples
bye-bye        #<EXPLICIT-BASE-INTERJECTION "bye-bye"
               {100E468733}>

blimey         #<EXPLICIT-BASE-INTERJECTION "blimey"
               {100E468743}>

begorra        #<EXPLICIT-BASE-INTERJECTION "begorra"
               {100E468753}>

Word Class noun
---------------

 -- Class: spell:noun (see word)
     Direct instances represent generic nouns.  Also a superclass for
     more specific noun classes.

The generic function gender can be
applied to words of this class.

 -- Generic Function: spell:case word
     Return a keyword which indicates the grammatical case of WORD.

     Possible values are :nominative, :genitive, :accusative and
     :nominative-or-accusative.

The generic function number can be
applied to words of this class.

Examples
yellow-flags   #<EXPLICIT-BASE-NOUN "yellow-flag" number:PLURAL
               case:NIL gender:NIL {100CE77343}>

worrywarts     #<EXPLICIT-BASE-NOUN "worrywart" number:PLURAL
               case:NIL gender:NIL {100CE3AB53}>

woodrushes     #<EXPLICIT-BASE-NOUN "woodrush" number:PLURAL
               case:NIL gender:NIL {100CE1CF13}>

Word Class noun-verb-contraction
--------------------------------

 -- Class: spell:noun-verb-contraction (see word,
          verb, noun)
     Instances are of type noun and also of type verb and are formed as
     a contraction of one noun and one verb.

Examples
'twould        #<EXPLICIT-BASE-NOUN-VERB-CONTRACTION "it would"
               person:THIRD number:SINGULAR
               tense:PRESENT-SIMPLE negative:NIL
               contraction:NIL strength:WEAK infinitive:NIL
               case:NIL gender:NEUTER {100E4687D3}>

'twill         #<EXPLICIT-BASE-NOUN-VERB-CONTRACTION "it will"
               person:THIRD number:SINGULAR
               tense:PRESENT-SIMPLE negative:NIL
               contraction:NIL strength:WEAK infinitive:NIL
               case:NIL gender:NEUTER {100E4687E3}>

'twas          #<EXPLICIT-BASE-NOUN-VERB-CONTRACTION "it was"
               person:THIRD number:SINGULAR tense:PAST
               negative:NIL contraction:NIL strength:STRONG
               infinitive:NIL case:NIL gender:NEUTER
               {100E4687F3}>

Word Class proper-noun
----------------------

 -- Class: spell:proper-noun (see word, noun)
     Instances represent proper nouns, that is generally names.

Examples
Zaragozas      #<EXPLICIT-BASE-PROPER-NOUN "Zaragoza"
               number:PLURAL case:NIL gender:NIL {100E468CD3}>

Trinidad       #<EXPLICIT-BASE-PROPER-NOUN "Trinidad"
               number:SINGULAR case:NIL gender:NIL
               {100E468CE3}>

Sloughs        #<EXPLICIT-BASE-PROPER-NOUN "Slough"
               number:PLURAL case:NIL gender:NIL {100E468CF3}>

Word Class preposition
----------------------

 -- Class: spell:preposition (see word)
     Instances represent prepositions, that is words which indicate the
     spatial, temporal, logical, etc.  relations between other words.

Examples
although       #<EXPLICIT-BASE-PREPOSITION "although"
               {100E468363}>

alongside      #<EXPLICIT-BASE-PREPOSITION "alongside"
               {100E468373}>

albeit         #<EXPLICIT-BASE-PREPOSITION "albeit"
               {100E468383}>

Word Class pronoun
------------------

 -- Class: spell:pronoun (see word)
     Direct instances represent generic pronouns.  Also a superclass for
     several more specific pronoun classes.

 -- Generic Function: spell:negative word
     Return a Boolean which indicates whether the meaning of WORD is in
     some way negative.

     If WORD is a verb, a true value indicates that the absence of the
     action represented by the verb.

     If WORD is a pronoun, a true value indicates the complement of the
     set of entities for which the non negated pronoun would stand in.

The generic function case can be
applied to words of this class.

The generic function gender can be
applied to words of this class.

The generic function number can be
applied to words of this class.

The generic function person can be
applied to words of this class.

Examples
everyone       #<EXPLICIT-BASE-PRONOUN "everyone" person:THIRD
               number:SINGULAR gender:NIL
               case:NOMINATIVE-OR-ACCUSATIVE negative:NIL
               {100E4682C3}>

everybody      #<EXPLICIT-BASE-PRONOUN "everybody" person:THIRD
               number:SINGULAR gender:NIL
               case:NOMINATIVE-OR-ACCUSATIVE negative:NIL
               {100E4682D3}>

either         #<EXPLICIT-BASE-PRONOUN "either" person:THIRD
               number:SINGULAR gender:NIL
               case:NOMINATIVE-OR-ACCUSATIVE negative:NIL
               {100E4682E3}>

Word Class demonstrative-pronoun
--------------------------------

 -- Class: spell:demonstrative-pronoun (see word,
          pronoun)
     Instances represent demonstrative pronouns, that is shorthand
     references which highlight an entity that is identifiable from the
     context.

Examples
there          #<EXPLICIT-BASE-DEMONSTRATIVE-PRONOUN "there"
               person:NIL number:ANY gender:NIL case:NOMINATIVE
               negative:NIL {100C7ABD73}>

that           #<EXPLICIT-BASE-DEMONSTRATIVE-PRONOUN "that"
               person:NIL number:ANY gender:NIL case:NOMINATIVE
               negative:NIL {100C793B83}>

here           #<EXPLICIT-BASE-DEMONSTRATIVE-PRONOUN "here"
               person:NIL number:ANY gender:NIL case:NOMINATIVE
               negative:NIL {10017CCF13}>

Word Class personal-pronoun
---------------------------

 -- Class: spell:personal-pronoun (see word,
          pronoun)
     Instances represent personal pronouns, that is shorthand references
     to a noun which designates a person.

Examples
he             #<EXPLICIT-BASE-PERSONAL-PRONOUN "he"
               person:THIRD number:SINGULAR gender:MASCULINE
               case:NOMINATIVE negative:NIL {10018DE123}>

her            #<EXPLICIT-BASE-PERSONAL-PRONOUN "her"
               person:THIRD number:SINGULAR gender:FEMININE
               case:ACCUSATIVE negative:NIL {10018A1023}>

I              #<EXPLICIT-BASE-PERSONAL-PRONOUN "I"
               person:FIRST number:SINGULAR gender:NIL
               case:NOMINATIVE negative:NIL {100E468E93}>

Word Class possessive-pronoun
-----------------------------

 -- Class: spell:possessive-pronoun (see word,
          pronoun)
     Instances represent possessive pronouns, that is shorthand
     references to an object that is possessed by an entity which is
     identifiable from the context.

The generic function refnumber.
can be applied to words of this class.

Examples
theirs         #<EXPLICIT-BASE-POSSESSIVE-PRONOUN "theirs"
               person:THIRD number:ANY gender:NIL
               case:NOMINATIVE negative:NIL refnumber:PLURAL
               {100C7A00C3}>

its            #<EXPLICIT-BASE-POSSESSIVE-PRONOUN "it"
               person:THIRD number:ANY gender:NIL
               case:NOMINATIVE negative:NIL refnumber:SINGULAR
               {100284BAE3}>

his            #<EXPLICIT-BASE-POSSESSIVE-PRONOUN "his"
               person:THIRD number:ANY gender:MASCULINE
               case:NOMINATIVE negative:NIL refnumber:SINGULAR
               {100191CA13}>

Word Class reflexive-pronoun
----------------------------

 -- Class: spell:reflexive-pronoun (see word,
          pronoun)
     Instances represent possessive pronouns, that is shorthand
     references that link the object back to the subject which is
     identifiable from the context.

Examples
yourselves     #<EXPLICIT-BASE-REFLEXIVE-PRONOUN "yourselves"
               person:SECOND number:PLURAL gender:NIL
               case:NOMINATIVE negative:NIL {100CE88F43}>

yourself       #<EXPLICIT-BASE-REFLEXIVE-PRONOUN "yourself"
               person:SECOND number:SINGULAR gender:NIL
               case:NOMINATIVE negative:NIL {100CE88ED3}>

thyself        #<EXPLICIT-BASE-REFLEXIVE-PRONOUN "thyself"
               person:SECOND number:SINGULAR gender:NIL
               case:NOMINATIVE negative:NIL {100C819263}>

Word Class verb
---------------

 -- Class: spell:verb (see word)
     Direct instances represent generic verbs.  Also a superclass for
     more specific verb classes.

 -- Generic Function: spell:infinitive word
     Return a keyword which indicates whether and which kind of
     infinitive WORD is.

     Possible values are nil, :self and :to.

 -- Generic Function: spell:strength word
     Return a keyword which indicates the grammatical strength of WORD.

     Only verb instances have the strength property which is either weak
     or strong.  Weak means that the past tense of the verb is formed by
     adding a suffix while strong means that the past tense form of the
     verb has a different stem than the infinitive form.

     Possible values are :weak and :strong.

 -- Generic Function: spell:contraction word
     Return a Boolean which indicates whether WORD is a contraction of
     two words.

     For instances of the verb class a true value of the contraction
     property always goes together with a true value of the negative
     property.  In other words these contractions consist of the base
     verb and the word not as in won t.

The generic function negative.
can be applied to words of this class.

 -- Generic Function: spell:tense word
     Return a keyword which indicates the time of the action for WORD.

     Possible values are nil, :present-simple, :progressive, :past,
     :perfect-participle, :passive-perfect-participle.

The generic function number can be
applied to words of this class.

The generic function person can be
applied to words of this class.

Examples
wannaed        #<EXPLICIT-BASE-VERB "wanna" person:ANY
               number:ANY tense:PERFECT-PARTICIPLE negative:NIL
               contraction:NIL strength:WEAK infinitive:NIL
               {100CCC6423}>

visaing        #<EXPLICIT-BASE-VERB "visa" person:ANY
               number:ANY tense:PROGRESSIVE negative:NIL
               contraction:NIL strength:WEAK infinitive:NIL
               {100CC4B743}>

validating     #<EXPLICIT-BASE-VERB "validate" person:ANY
               number:ANY tense:PROGRESSIVE negative:NIL
               contraction:NIL strength:WEAK infinitive:NIL
               {100CB97F03}>

Word Class verb-verb-contraction
--------------------------------

 -- Class: spell:verb-verb-contraction (see word,
          verb)
     Instances are verbs that are formed as a contraction of two verbs.

Examples
might've       #<EXPLICIT-BASE-VERB-VERB-CONTRACTION "might
               have" person:ANY number:ANY tense:PRESENT-SIMPLE
               negative:NIL contraction:NIL strength:WEAK
               infinitive:SELF {1002FC7EE3}>

may've         #<EXPLICIT-BASE-VERB-VERB-CONTRACTION "may have"
               person:ANY number:ANY tense:PRESENT-SIMPLE
               negative:NIL contraction:NIL strength:WEAK
               infinitive:SELF {1002CEDB93}>

could've       #<EXPLICIT-BASE-VERB-VERB-CONTRACTION "could
               have" person:ANY number:ANY tense:PRESENT-SIMPLE
               negative:NIL contraction:NIL strength:WEAK
               infinitive:SELF {100E468FA3}>

2.3 Dictionary Protocol
=======================

 -- Generic Function: spell:entry-count dictionary

     Return the number of entries in DICTIONARY.

     Example:
          (spell:entry-count spell::*english-dictionary*)
          ⇒ 347488

 -- Generic Function: spell:map-entries function dictionary

     Call FUNCTION for each entry in DICTIONARY.

     The lambda-list of FUNCTION has to be compatible with (spelling
     word) where WORD is the word object of the entry and SPELLING is
     the spelling of the entry as a string.

     SPELLING is passed as a separate argument because it cannot be
     obtained from WORD.

     Example:
          (prog ((i 0))
            (spell:map-entries (lambda (spelling word)
                                 (cond ((<= 7000 (incf i) 7005)
                                        (format t "~D ~10A ~A~%" i spelling word))
                                       ((> i 10005)
                                        (return))))
                               spell::*english-dictionary*))
          ⊣ 7000 Highlander #<EXPLICIT-BASE-NOUN "Highlander" number:SINGULAR case:NIL gender:NIL {101ACF7AF3}>
          ⊣ 7001 Highlands' #<EXPLICIT-BASE-PROPER-NOUN "Highland" number:PLURAL case:GENITIVE gender:NIL {101AD086E3}>
          ⊣ 7002 Highlands  #<EXPLICIT-BASE-PROPER-NOUN "Highland" number:PLURAL case:NIL gender:NIL {101AD087C3}>
          ⊣ 7003 Highland   #<EXPLICIT-BASE-PROPER-NOUN "Highland" number:SINGULAR case:NIL gender:NIL {101AD088A3}>
          ⊣ 7004 Hilary's   #<EXPLICIT-BASE-PROPER-NOUN "Hilary" number:SINGULAR case:GENITIVE gender:NIL {101AD08983}>
          ⊣ 7005 Hilarys'   #<EXPLICIT-BASE-PROPER-NOUN "Hilary" number:PLURAL case:GENITIVE gender:NIL {101AD08A63}>

 -- Generic Function: spell:lookup string dictionary

     Return a (possibly empty) list of entries in DICTIONARY the
     spelling of which matches STRING.

     Example:
          (spell:lookup "bright" spell::*english-dictionary*)
          ⇒ (#<EXPLICIT-BASE-ADVERB "bright" {101B1CE6B3}>
             #<EXPLICIT-BASE-ADJECTIVE "bright" degree:POSITIVE {101B1CE663}>
             #<EXPLICIT-BASE-NOUN "bright" number:SINGULAR case:NIL gender:NIL {101B1CE633}>)

 -- Generic Function: spell:map-similar function string dictionary
          threshold &key group-by

     Call FUNCTION for each entry in DICTIONARY for which the
     edit-distance to STRING is below THRESHOLD.  The entries are
     reported in order of increasing edit-distance from STRING.

     The lambda-list of FUNCTION has to be compatible with either
     (spelling word distance) if GROUP-BY is :entry or (spelling
     distance) if GROUP-BY is :spelling.  WORD is the matching
     word object, SPELLING is a string that is the
     spelling of WORD (which is not obtainable from WORD itself) and
     DISTANCE is the edit-distance between SPELLING and STRING.

     STRING is the query string and can be of any subtype of cl:string.
     At the moment, the case of string is left untouched and only
     dictionary entries that match the case are reported.

     DICTIONARY is a dictionary.

     THRESHOLD is a non-negative integer which controls how similar to
     STRING in terms of edit-distance the reported entries have to be.

     GROUP-BY controls whether word objects are included in calls of
     FUNCTION.  If GROUP-BY is :entry, FUNCTION is called with three
     arguments: spelling, word and distance.  If GROUP-BY is :spelling,
     FUNCTION is called with two arguments, spelling and distance.  The
     default is :entry.  Note that the value of GROUP-BYr influences the
     number of times FUNCTION is called since a spelling that
     corresponds to multiple entries will be reported once for :spelling
     but multiple times for :entry.

     Example:
          (spell:map-similar
           (lambda (spelling word distance)
             (format t "~D ~10S ~A~%" distance spelling (class-name (class-of word))))
           "lisp" spell::*english-dictionary* 1)
          ⊣ 0 "lisp"     EXPLICIT-BASE-NOUN
          ⊣ 0 "lisp"     EXPLICIT-BASE-VERB
          ⊣ 1 "limp"     EXPLICIT-BASE-NOUN
          ⊣ 1 "limp"     EXPLICIT-BASE-ADJECTIVE
          ⊣ 1 "limp"     EXPLICIT-BASE-VERB
          ⊣ 1 "lip"      EXPLICIT-BASE-NOUN
          ⊣ 1 "lip"      EXPLICIT-BASE-VERB
          ⊣ 1 "lisps"    EXPLICIT-BASE-NOUN
          ⊣ 1 "lisps"    EXPLICIT-BASE-VERB
          ⊣ 1 "list"     EXPLICIT-BASE-NOUN
          ⊣ 1 "list"     EXPLICIT-BASE-VERB
          ⊣ 1 "wisp"     EXPLICIT-BASE-NOUN
          ⊣ 1 "wisp"     EXPLICIT-BASE-VERB
          ⇒ NIL

     With :group-by :spelling
          (spell:map-similar
           (lambda (spelling distance)
             (format t "~D ~S~%" distance spelling))
           "lisp" spell::*english-dictionary* 1 :group-by :spelling)
          ⊣ 0 "lisp"
          ⊣ 1 "lisps"
          ⊣ 1 "list"
          ⊣ 1 "lip"
          ⊣ 1 "limp"
          ⊣ 1 "wisp"
          ⇒ NIL

 -- Generic Function: spell:map-corrections function string dictionary
          threshold &key variants group-by

     Call FUNCTION for each entry in DICTIONARY for which the
     edit-distance to a _variant_ of STRING is below THRESHOLD.  The
     entries are reported in order of increasing edit-distance from
     variants of STRING.

     The lambda-list of FUNCTION has to be compatible with either
     (spelling word distance) if GROUP-BY is :entry or (spelling
     distance) if GROUP-BY is :spelling.  WORD is the matching
     word object, SPELLING is a string that is the
     spelling of WORD (which is not obtainable from WORD itself) and
     DISTANCE is the edit-distance between SPELLING and one variant of
     STRING.

     STRING is the query string and can be of any subtype of cl:string.

     DICTIONARY is a dictionary.

     THRESHOLD is a non-negative integer which controls how similar to a
     variant of STRING in terms of edit-distance the reported entries
     have to be.

     VARIANTS controls which variants in terms of capitalization and
     case of STRING should be considered.  If supplied, the value of
     VARIANTS has to be a function the lambda-list of which has to
     compatible with (continuation string) where STRING is the STRING
     mentioned above and CONTINUATION is a function that should be
     called once for each case-modified variant of STRING.  Note that
     capitalization and case information should ideally be contained in
     dictionary entries.  The implementation of that improvement would
     make this parameter unnecessary.

     GROUP-BY controls whether word objects are included in calls of
     FUNCTION.  If GROUP-BY is :entry, FUNCTION is called with three
     arguments, spelling, word and distance.  If GROUP-BY is :spelling,
     FUNCTION is called with two arguments, spelling and distance.  The
     default is :entry.  Note that the value of GROUP-BY influences the
     number of times FUNCTION is called since a spelling that
     corresponds to multiple entries will be reported once for :spelling
     but multiple times for :entry.

     Examples:
          (spell:map-corrections
           (lambda (spelling word distance)
             (format t "~D ~10S ~A~%" distance spelling (class-name (class-of word))))
           "lisp" spell::*english-dictionary* 1)
          ⊣ 0 "lisp"     EXPLICIT-BASE-NOUN
          ⊣ 0 "lisp"     EXPLICIT-BASE-VERB
          ⊣ 1 "lisps"    EXPLICIT-BASE-NOUN
          ⊣ 1 "lisps"    EXPLICIT-BASE-VERB
          ⊣ 1 "list"     EXPLICIT-BASE-NOUN
          ⊣ 1 "list"     EXPLICIT-BASE-VERB
          ⊣ 1 "lip"      EXPLICIT-BASE-NOUN
          ⊣ 1 "lip"      EXPLICIT-BASE-VERB
          ⊣ 1 "limp"     EXPLICIT-BASE-NOUN
          ⊣ 1 "limp"     EXPLICIT-BASE-ADJECTIVE
          ⊣ 1 "limp"     EXPLICIT-BASE-VERB
          ⊣ 1 "wisp"     EXPLICIT-BASE-NOUN
          ⊣ 1 "wisp"     EXPLICIT-BASE-VERB
          ⇒ NIL

          (spell:map-corrections
           (lambda (spelling word distance)
             (format t "~D ~10S ~A~%" distance spelling (class-name (class-of word))))
           "lifp" spell::*english-dictionary* 1)
          ⊣ 1 "lift"     EXPLICIT-BASE-NOUN
          ⊣ 1 "lift"     EXPLICIT-BASE-VERB
          ⊣ 1 "life"     EXPLICIT-BASE-NOUN
          ⊣ 1 "lip"      EXPLICIT-BASE-NOUN
          ⊣ 1 "lip"      EXPLICIT-BASE-VERB
          ⊣ 1 "lisp"     EXPLICIT-BASE-NOUN
          ⊣ 1 "lisp"     EXPLICIT-BASE-VERB
          ⊣ 1 "limp"     EXPLICIT-BASE-NOUN
          ⊣ 1 "limp"     EXPLICIT-BASE-ADJECTIVE
          ⊣ 1 "limp"     EXPLICIT-BASE-VERB
          ⇒ NIL

 -- Generic Function: spell:corrections string dictionary threshold &key
          variants group-by count

     Return corrections from DICTIONARY that are within THRESHOLD of the
     misspelled word STRING.  Return two values: a list of corrections
     and a Boolean which indicates whether STRING is spelled correctly
     according to DICTIONARY.

     The list of entries which is returned as the first value is ordered
     according to increasing edit-distance between STRING and the
     respective entry.  Depending on GROUP-BY (see below), entries in
     the list are either strings that are spellings of entries in
     DICTIONARY or pairs of the form (WORD . SPELLING).  If the second
     return value is true, which indicates that STRING is spelled
     correctly, the first return value includes one or more entries
     which correspond to STRING.

     DICTIONARY is a dictionary.

     THRESHOLD is a non-negative integer which controls how similar to a
     variant of STRING in terms of edit-distance the reported entries
     have to be.

     VARIANTS controls which variants in terms of capitalization and
     case of STRING should be considered.  If supplied, the value of
     VARIANTS has to be a function the lambda-list of which has to
     compatible with (continuation string) where STRING is the STRING
     mentioned above and CONTINUATION is a function that should be
     called once for each case-modified variant of STRING.  Note that
     capitalization and case information should ideally be contained in
     dictionary entries.  The implementation of that improvement would
     make this parameter unnecessary.

     GROUP-BY controls whether word objects are included in elements of
     the returned list.  If GROUP-BY is :entry, elements are of the form
     (WORD . SPELLING).  If GROUP-BY is :spelling, elements are strings
     and each string is one spelling.  The default is :entry.  Note that
     the value of GROUP-BY influences the number returned elements since
     a spelling that corresponds to multiple entries will be reported
     once for :spelling but multiple times for :entry.

     If supplied, COUNT limits the maximum number of entries that are
     returned as the first value.

     Examples:
          (spell:corrections "lisp" spell::*english-dictionary* 0 :group-by :spelling)
          ⇒ ("lisp") T

          (spell:corrections "lifp" spell::*english-dictionary* 1 :group-by :spelling)
          ⇒ ("lift" "life" "lip" "lisp" "limp") NIL

          (spell:corrections "lisp" spell::*english-dictionary* 2 :group-by :spelling :count 3)
          ⇒ ("lisp" "lisps" "list") T

 -- Generic Function: spell:insert word string dictionary

     Insert WORD into DICTIONARY as an entry for STRING.

     WORD must be an instance of word.

     DICTIONARY must be a mutable dictionary.  A "raw" dictionary is
     mutable, a "compacted" dictionary is not mutable.

 -- Generic Function: spell:load-dictionary source &key into

     Turn the word information in SOURCE into INTO or a new dictionary
     and return that dictionary.

     SOURCE can be a stream, a string or pathname or some other
     sequence.  If SOURCE is a stream, it must be an open character
     input stream.  The word information is read from the stream.  If
     SOURCE is a string a pathname it is a designator for a file that
     should be opened and read.  If SOURCE is some other sequence, the
     sequence elements must be of the types discussed above.  The word
     information from all source is combined into one dictionary in that
     case.

     If supplied, INTO must be a mutable dictionary into which the word
     information should be loaded.  The function returns INTO in that
     case.  Otherwise the function creates a new dictionary, loads the
     word information into it and returns it.

Concept index
*************

Changelog
*********

Release 0.3 (not yet released)

        •
          A new protocol enables clients to find dictionary entries that
          are similar to a given string or corrections for a given
          misspelled word.

          The following new functions provide increasingly abstract
          functionality for enumerating similar words and corrections:
          spell:map-similar, spell:map-corrections and
          spell:corrections.

          For convenience, the function spell:english-corrections
          automatically uses the English dictionary and considers the
          appropriate case variants of the supplied string.

        •
          Documentation is now available in the documentation directory.

        •
          The new function map-entries calls a supplied function for
          each entry in a given dictionary.

Release 0.2 (2025-01-05)

        •
          The README.org file now uses the org-mode format.  The
          examples have been updated.

        •
          The spell/simple system is now an alias for the spell system
          since the improved memory footprint makes the former
          unnecessary.

        •
          Compilation and loading times as well as memory footprint have
          been significantly reduced.

        •
          Dictionaries can now be built from multiple source files.
          Additional words are now loaded from
          data/english-additions.txt.

Release 0.1 (2024-12-20)

        •
          Initial release with basic lookup for the English dictionary
          but slow compilation and loading and a big memory footprint.