2013-09-06 3 views
3

Этот ответ: Very basic dcg prolog syntax помог мне немного, но [X] получил только следующего персонажа, я хочу, чтобы вся энчилада, читайте дальше!DCG: Назначение остатка переменной в DCG {} код

Я использую GNU Prolog для написания парсера параметров команды, и я застрял в точке DCG. У меня есть это правило грамматики, которая выглядит для «Foo --as = JSON», например, и я просто не могу работать, как получить мои руки на результат «ничего», код:

as_opt --> "--as=", anything, { c(as_opt)}, !. 
anything --> [], {c(anything_match)}. 

И gprolog расширение именно:

as_opt([45, 45, 97, 115, 61|A], B) :- 
     anything(A, C), 
     c(as_opt), !, 
     C = B. 

anything(A, B) :- 
     c(anything_match), !, 
     A = B. 

Буква «с()» предикат является простым и используется только для отслеживания, что правило выполняется с форматом() на стандартный вывод, так что я мог видеть, что происходит, как это работает. Если бы я написал код вручную, я хотел бы сделать:

%% for completeness here! 
c(Msg) :- format("Processed ~w~n", [Msg]). 

as_opt([45, 45, 97, 115, 61|A], B) :- 
     anything(A, C), 
     c(as_opt), !, 
     C = B, 
     { g_assign(gvValue, B)}. %% just for example 

Возвращаясь к первоначальному ВСО:

as_opt --> "--as=", anything, { c(as_opt), gassign(gvValue, ???)}, !. 

Итак, что происходит, когда «???» является. Возможно ли это ... должно быть. Я собираюсь перечитать правила gprolog о том, как он снова расширяет правила DCG в случае, если я собираюсь (facepalm) сам, но тем временем любая помощь будет наиболее желанной.

Thanks, Шон.

ответ

3

Вы просите одного из простейших DCG нетерминалов, который описывает любой список:

list --> []. 
list --> [_], list. 

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

list([]) --> []. 
list([L|Ls) --> [L], list(Ls) 

Вы можете использовать его как это:

as_opt(Option) --> "--as=", list(Option). 
+0

коврик, хороший ответ. Я предполагаю, что я ноб с правилами Prolog и DCG, мне еще предстоит оценить нюансы! Я буду работать с этим, и, без сомнения, его отслеживание поможет мне в этом разобраться. Благодарю. Хороший краткий ответ. –

+0

Bummer. Должен был пробовать код, слишком волновался! Это пока не работает для меня. Он выводит «[]» в качестве значения параметра. Я постараюсь усерднее ... Вскоре я думаю ... –

+0

коврик, я думаю, что порядок правил неверен. Если я поместил пустой случай в список, все выглядит намного лучше! Вы думаете, это надзор с вашей стороны? –

1

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

anything([C|Cs]) --> [C], anything(Cs). 
anything([]) --> []. 

иначе, остальная часть доступна в качестве последнего аргумента фразы/3, после того, как правила преуспели, «потребляя» матч заголовка.

+0

Я относительно новый для Пролога. Я должен прочитать руководство по фразе/3, я предполагаю, что я вызываю правило запуска «вручную» в итеративном цикле над аргументами командной строки. Я использовал глобальные переменные, потому что я пишу довольно большое приложение с gprolog. Разбор параметров командной строки - это лишь одна из вещей, которые мне нужно сделать. Это делает другие биты кода легкими, и мои глобальные таблицы строго читаются только после того, как они установлены в модуле командной строки. Однако я полностью понимаю ваши оговорки. –

3

Там лучшее решение, чем один по алфавиту ребристый по коврику, который быстрее и избегает ложных точек выбора, но для этого требуется поддержка встроенного не-терминала call//1, как найдено напр. SWI-Prolog, GNU Prolog и другие компиляторы Prolog. Также на Logtalk. Рассмотрим:

as_opt(Option) --> "--as=", list(Option). 

list([L|Ls]) --> [L], list(Ls). 
list([]) --> []. 

as_opt2(Option) --> "--as=", call(rest(Option)). 

rest(Rest, Rest, _). 

Использование SWI-Пролог, чтобы лучше проиллюстрировать разницу:

?- phrase(as_opt(Option), "--as=json"). 
Option = [106, 115, 111, 110] ; 
false. 

?- phrase(as_opt2(Option), "--as=json"). 
Option = [106, 115, 111, 110]. 

?- time(phrase(as_opt(Option), "--as=json")). 
% 9 inferences, 0.000 CPU in 0.000 seconds (57% CPU, 562500 Lips) 
Option = [106, 115, 111, 110] ; 
% 2 inferences, 0.000 CPU in 0.000 seconds (63% CPU, 133333 Lips) 
false. 

?- time(phrase(as_opt2(Option), "--as=json")). 
% 6 inferences, 0.000 CPU in 0.000 seconds (51% CPU, 285714 Lips) 
Option = [106, 115, 111, 110]. 

Ложный выбор точки исходит из определения list//1 нетерминал. Разница в производительности заключается в том, что, в то время как call//1 позволяет нам просто получить доступ к аргументу неявного списка, то non-terminal list//1 выполняет элемент копирования списка по элементу этого неявного аргумента.Как следствие, производительность list//1 версии является линейный по символам после префикса --as= в то время как call//1 производительности постоянна, не зависит от количества символов после префикса:

?- time(phrase(as_opt(Option), "--as=jsonjsonjsonjsonjsonjsonjsonjsonjsonjsonjsonjson")). 
% 54 inferences, 0.000 CPU in 0.000 seconds (83% CPU, 2700000 Lips) 
Option = [106, 115, 111, 110, 106, 115, 111, 110, 106|...] ; 
% 4 inferences, 0.000 CPU in 0.000 seconds (69% CPU, 137931 Lips) 
false. 

?- time(phrase(as_opt2(Option), "--as=jsonjsonjsonjsonjsonjsonjsonjsonjsonjsonjsonjson")). 
% 6 inferences, 0.000 CPU in 0.000 seconds (79% CPU, 333333 Lips) 
Option = [106, 115, 111, 110, 106, 115, 111, 110, 106|...]. 
+0

Whooooosh! Пауло, это очень хороший ответ, но прямо над моей головой с точки зрения понимания! Я использовал Пролог только месяц или три. Я вижу, что вы имеете в виду точки выбора aobut, но это действительно хороший момент, и мне все равно нужно полностью опустить голову. Реальность такова, что мой DCG выполнит один раз, чтобы разобрать, вероятно, не более четырех или пяти аргументов командной строки; он просто должен работать. Спасибо хоть. :) –

+0

Бесконтактный вызов 'call // 1' переводится в встроенный предикатный вызов' call/3', где первый аргумент (закрытие 'rest (Rest)') является общим и два дополнительных аргумента (в вызове 'call/3') являются двумя неявными аргументами правила DCG. Определение предиката 'rest/3' просто объединяет аргумент замыкания с первым (так называемым« входным ») неявным аргументом. Существует также альтернативное решение, использующее встроенный не-терминал 'call // 1' с выражением лямбда в качестве аргумента, который не требует вспомогательного предиката (например,' rest/3'), но это неприятный трюк, и я буду не публикуйте его. –

+0

Пауло, мы никогда не должны вскакивать в реальной жизни. Если бы ваш мозг и мой анти-мозг сотрудничали, взрыв мог быть смертельным ... спасибо! :) –