An Introduction to Language Processing with Perl and Prolog is mainly designed to be used as a textbook in computational linguistics (CL) and natural language processing (NLP) courses. The book is comprehensive and covers all the required material for a one semester NLP course. In addition to major NLP concepts such as morphology, part-of-speech tagging, parsing, semantics and discourse, the book also covers miscellaneous statistical language processing concepts. However areas related to speech processing are not discussed in the book; an NLP course planning to cover aspects of speech related material in depth should consider another NLP text that covers those subjects, such as Jurafsky and Martin (Reference Jurafsky and Martin2008), and Coleman (Reference Coleman2005).
This is a well-written and easy-to-read textbook. The coverage and order of the presentation are suitable for an introductory course.
After giving a gentle overview of language processing in Chapter 1, the book covers most of the techniques related to processing a corpus of text in Chapters 2 to 4. These chapters discuss simple algorithms such as string matching, and tokenization as well as the important statistical concepts such as n-grams and language models. Chapter 2 introduces finite state automata and regular expressions, and their applications in corpus processing. These are accompanied with code examples: for example, the author presents Perl and Prolog programs that find concordances and edit distances. Chapter 3 introduces various character encoding schemes and the usage of XML in corpus annotation, and then introduces statistical concepts of entropy and perplexity. In chapter 4, after explaining simple tokenization with Perl and Prolog programs, the author goes deeper into statistical language processing and discusses estimation, smoothing and collocations. However, the coverage of statistical language processing concepts are not at the same level as in Manning and Schütze (Reference Manning and Schütze1999).
In Chapter 5, the author introduces morphology and morphological parsing by giving a simple Prolog implementation of finite state transducers (FST). He also discusses two-level morphology and the relation between two-level morphological rules and finite state transducers. He shows that a single FST representing a morphological processor can be created by intersections and compositions of the finite state transducers representing the parts of the morphological analyzer, but without presenting the details of the algorithms.
In Chapters 6 to 7, the author covers both rule-based and stochastic part-of-speech tagging techniques. He discusses Brill's tagger by giving its partial Prolog implementation in Chapter 6, and then goes on to the noisy channel model, Hidden Markov Models and the Viterbi algorithm in Chapter 7.
The author reserves Chapters 8 to 11 for syntactic formalisms and parsing techniques. He covers not only phrase-structure grammars and the well-known parsing techniques, but also partial parsing techniques and methods for dependency parsing. In fact, this seems to be the first book that reserves a separate chapter for partial parsing methods. The author also devotes special attention to dependency parsing and the implementations of various recent dependency parsing techniques, for example, by Nivre (Reference Nivre2006).
The author starts the discussion of parsing with phrase-structure grammars in Chapter 8. He discusses the use of the Definite Clause Grammar notation of Prolog to map phrase-structure rules into Prolog programs. However, he directly jumps into parsing without giving a formal definition of context free grammars and explaining the concept of parsing. In my opinion, it would have been much better if concepts such as context free grammars, derivations, and parse trees were discussed in depth before the exposition of parsing.
Chapter 9 presents a detailed discussion on partial parsing, a topic not covered by most of the textbooks on NLP. It is nice to see that topics such as shallow parsing and chunk parsing are covered as they have been recently gaining importance in many application areas such as information extraction.
Chapter 10 presents two syntactic formalisms: constituent-based and dependency based. After the discussion of Chomsky's constituent-based grammars, unification-based grammars are introduced. The author also discusses dependency grammars as an alternative to constituent-based formalisms.
Chapter 11 covers most of the efficient parsing algorithms. The author starts with a basic shift-reduce parsing algorithm and then introduces the Earley parser, an efficient bottom-up chart parsing algorithm, and the details of the Cocke-Younger-Kasami (CYK) algorithm, another efficient bottom-up chart parser. He also discusses dependency parsing by giving a Prolog implementation of Nivre's dependency parsing technique (Nivre Reference Nivre2006).
Chapter 12 starts the part of the book on semantics and introduces the use of predicate logic in the representation of meanings of sentences. The author explains how phrases are mapped into the corresponding logic formulas in first order predicate calculus (FOPC). However, there is no formal introduction of FOPC which would have been useful for students who are unfamiliar with it. Also, for some examples, only the Prolog representations of logical formulas are given and this makes it difficult to see the corresponding logical formulas for those phrases.
Chapter 13 discusses lexical semantics and word sense disambiguation. However, the coverage of popular resources such as WordNet is rather cursory. Case grammars are also discussed in this chapter.
The last two chapters introduce discourse and dialogue related concepts. Chapter 13 starts with an introduction to discourse, and continues with a discussion of anaphora resolution followed by rhetoric structure. In Chapter 14, the author presents issues in dialogue modeling. The speech act theory and its application to human-machine dialogue are also discussed.
The book ends with a comprehensive appendix that covers an introduction to the Prolog programming language. The appendix should be a starting point for readers who do not know Prolog, as most of the algorithms are given as Prolog programs.
Throughout the book, the author presents algorithms using Prolog or Perl instead of pseudo-code. Most of the algorithms are given as Prolog programs; Perl is only used in Chapters 2 and 4 in the implementation of simple corpus processing algorithms such as string matching. Since Prolog is the dominant language used in the book, the title of the book is a little misleading. In addition, although there is a long appendix for introduction to Prolog, there is no counterpart for readers who have not been exposed to Perl. In my opinion, there was no need to use a second programming language in order to present various algorithms.
Giving algorithms as Prolog programs makes it easy to understand for the readers who know Prolog or willing to learn Prolog. On the other hand, the readers who do not know Prolog very well will have difficulty in understanding the algorithms unless they are willing to learn Prolog in order to comprehend the language processing techniques.
Also the author presents the examples in three different languages: English, French and German. Although this exposes the reader to language phenomena in different languages, they are obviously not the languages of choice to appeal to a wider audience. In many cases, giving examples in three languages does not present any advantage or provide additional insight.
In conclusion, despite various problems, this is a well-written textbook and covers all the required concepts for an NLP course, provided the students are willing to learn Prolog.