Как разобрать список слов по упрощенной грамматике? - PullRequest
8 голосов
/ 18 октября 2011

Просто чтобы уточнить, это не домашняя работа.Меня попросили о помощи по этому вопросу, и я не могу это сделать, поэтому это превратилось в личный поиск, чтобы решить ее.

Представьте, что у вас есть грамматика для предложения на английском языке, подобная этой:

S => NP VP | VP
NP => N | Det N | Det Adj N
VB => V | V NP
N => i you bus cake bear
V => hug love destroy am
Det => a the
Adj => pink stylish

Я искал несколько часов, и у меня действительно нет идей.Я нашел статьи, рассказывающие о мелком разборе, возврате в глубину и связанных с этим вещах, и хотя я знаком с большинством из них, я все еще не могу применить их к этой проблеме.Я пометил Lisp и Haskell, потому что это те языки, на которых я планирую это реализовать, но я не против, если вы будете использовать другие языки в своих ответах.

Буду признателен за подсказки, хорошие статьи и все в целом.

Ответы [ 5 ]

4 голосов
/ 18 октября 2011

Вот рабочий пример на Haskell.Оказывается, есть несколько уловок, которые нужно выучить, прежде чем вы сможете заставить его работать!Нулевая вещь, которую нужно сделать, это шаблон: отключить страшное ограничение мономорфизма, импортировать некоторые библиотеки и определить некоторые функции, которых нет в библиотеках (но они должны быть):

{-# LANGUAGE NoMonomorphismRestriction #-}
import Control.Applicative ((<*))
import Control.Monad
import Text.ParserCombinators.Parsec

ensure p x = guard (p x) >> return x
singleToken t = tokenPrim id (\pos _ _ -> incSourceColumn pos 1) (ensure (==t))
anyOf xs = choice (map singleToken xs)

Теперь, когда ноль вещьсделано ... во-первых, мы определяем тип данных для наших абстрактных синтаксических деревьев.Мы можем просто следовать форме грамматики здесь.Однако, чтобы сделать его более удобным, я учел несколько правил грамматики;в частности, два правила

NP => N | Det N | Det Adj N
VB => V | V NP

более удобно писать таким образом, когда речь идет о написании синтаксического анализатора:

NP => N | Det (Adj | empty) N
VB => V (NP | empty)

В любой хорошей книге по синтаксическому анализу будет глава о том, почемуэтот вид факторинга - хорошая идея.Итак, тип AST:

data Sentence
    = Complex NounPhrase VerbPhrase
    | Simple VerbPhrase
data NounPhrase
    = Short Noun
    | Long Article (Maybe Adjective) Noun
data VerbPhrase
    = VerbPhrase Verb (Maybe NounPhrase)
type Noun      = String
type Verb      = String
type Article   = String
type Adjective = String

Тогда мы можем сделать наш парсер.Это следует за (факторизованной) грамматикой еще ближе!Единственный недостаток в том, что мы всегда хотим, чтобы наш синтаксический анализатор занимал целое предложение, поэтому мы должны явно попросить его сделать это, требуя «eof» - или конец «file».

s   = (liftM2 Complex np vp <|> liftM Simple vp) <* eof
np  = liftM Short n <|> liftM3 Long det (optionMaybe adj) n
vp  = liftM2 VerbPhrase v (optionMaybe np)
n   = anyOf ["i", "you", "bus", "cake", "bear"]
v   = anyOf ["hug", "love", "destroy", "am"]
det = anyOf ["a", "the"]
adj = anyOf ["pink", "stylish"]

Последний кусок - токенизатор.Для этого простого приложения мы просто токенизируем на основе пробелов, поэтому встроенная функция words прекрасно работает.Давайте попробуем это!Загрузите весь файл в ghci:

*Main> parse s "stdin" (words "i love the pink cake")
Right (Complex (Short "i") (VerbPhrase "love" (Just (Long "the" (Just "pink") "cake"))))
*Main> parse s "stdin" (words "i love pink cake")
Left "stdin" (line 1, column 3):
unexpected "pink"
expecting end of input

Здесь Right указывает на успешный анализ, а Left указывает на ошибку.Номер «столбца», указанный в ошибке, на самом деле является номером слова, в котором произошла ошибка, из-за того, как мы вычисляем исходные позиции в singleToken.

4 голосов
/ 18 октября 2011

Существует несколько различных подходов к синтаксическому синтаксическому анализу с использованием контекстно-свободной грамматики.

Если вы хотите реализовать это самостоятельно, вы можете начать с ознакомления с алгоритмами синтаксического анализа: вы можете посмотреть здесь и здесь , или, если вы предпочитаете что-то на бумаге, глава о синтаксическом разборе в Jurafsky & Martin может быть хорошим началом.

Я знаю, что это не такслишком сложно реализовать простой синтаксический парсер на языке программирования Prolog.Просто поищите в Google «анализатор сдвига пролога» или «анализатор прогнозирования сканирования пролога».Я не знаю Haskell или Lisp, но может быть сходство с прологом, так что, может быть, вы можете получить некоторые идеи оттуда.

Если вам не нужно реализовывать полный анализатор самостоятельно, я бывзгляните на Python NLTK, который предлагает инструменты для синтаксического анализа CFG.Об этом есть глава в книге NLTK .

1 голос
/ 18 октября 2011

Хорошо, есть ряд алгоритмов, которые вы можете использовать. Ниже приведены некоторые популярные алгоритмы динамического программирования: 1) алгоритм CKY: грамматика должна быть в форме CNF 2) алгоритм Эрли 3) Разбор диаграммы.

Пожалуйста, Google, чтобы найти реализацию этих. По сути, с учетом предложения эти алгоритмы позволяют назначать ему контекстно-свободное дерево.

0 голосов
/ 19 октября 2011

Я думаю, что проблема для вас может заключаться в том, что способ синтаксического анализа компьютерного языка сильно отличается от способа синтаксического анализа естественного языка.

Компьютерные языки разработаны так, чтобы быть однозначными и относительно легко получить точное значение от компьютера.

Естественные языки стали компактными, выразительными и обычно понятными для людей. Возможно, вам удастся заставить детерминистический анализ использовать компиляторы для некоторого очень простого подмножества грамматики английского языка, но это совсем не то, что используется для анализа реального естественного языка.

0 голосов
/ 18 октября 2011

Вы привели пример непропабалистической грамматики. Таким образом, вы можете использовать инструменты ANTLR, JFlex, Scala Parser Combinators, Python-библиотеку Parsers для реализации синтаксического анализатора по этой грамматике в очень похожем коде, как вы предоставили.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...