Перебирая список, который является подмассивом - PullRequest
1 голос
/ 27 апреля 2019

Я использую ECLiPSe 6.1. У меня есть массив переменных размерности N x N, назовем его Vars. Теперь я вызываю процедуру, скажем, my_procedure(Vars[1..N,1..2]).

Внутри процедуры (my_procedure(List) :- ...) используется что-то вроде (foreach(X, List) do ...). Это не работает Я должен написать что-то вроде L is List внутри процедуры, прежде чем перейти к L (вместо List), чтобы она заработала.

Почему это? И как я могу решить это? Потому что позже я пытаюсь вызвать процедуру с flatten(Vars[1..N,1..2]), и тогда она становится еще хуже.

Я начал использовать collection_to_list/2flatten) для решения проблемы, но мне было интересно, есть ли элегантный способ ее решения.

1 Ответ

2 голосов
/ 28 апреля 2019

Позвольте мне остановиться подробнее, потому что в вашем вопросе подчеркивается особенность Prolog / ECLiPSe, которая регулярно удивляет пользователей, приходящих с других языков программирования:

  • Каждый термин / выражение по умолчанию является просто символической структурой без присущего ей значения
  • Любая интерпретация / оценка такой символической структуры происходит только в определенных контекстах или при явном запросе

Возможно, самый вопиющий пример с тем, что выглядит как "арифметическое выражение":

?- writeln(3+4).
3 + 4

Пролог принимает аргумент 3+4 просто как символический термин +(3,4) и передает его в writeln / 1, не интерпретируя. Передача термина в качестве аргумента пользовательскому предикату не меняет этого, не существует неявной оценки во время вызова:

p(X) :- writeln(received(X)).

?- p(3+4).
received(3 + 4)

Если мы хотим интерпретировать аргумент как арифметическое выражение и оценить его, мы должны запросить это явно:

parith(Expr) :- Num is Expr, writeln(evaluated_to(Num)).

?- parith(3 + 4).
evaluated_to(7)

Выражения доступа к массиву в ECLiPSe ведут себя одинаково. Они являются просто символическими выражениями, пока не будут явно оценены предикатом, который их понимает:

?- Array = [](11,22,33), p(Array[2]).
received([](11,22,33)[2])

?- Array = [](11,22,33), parith(Array[2]).
evaluated_to(22)

Итак, чтобы наконец вернуться к исходной проблеме: когда вы вызываете my_procedure(Vars[1..N,1..2]), передаваемый аргумент является символическим выражением Vars[1..N,1..2], и это то, что получает my_procedure/1. Чтобы превратить это в плоский список, который вы хотите, его нужно интерпретировать как выражение, которое приводит к списку, и collection_to_list / 2 (или, начиная с ECLiPSe 7.0, eval_to_list / 2 ) делают именно это:

plist(Expr) :- eval_to_list(Expr, List), writeln(evaluated_to(List)).

?- A = [](11, 22, 33), p(A[2 .. 3]).
received([](11, 22, 33)[2 .. 3])

?- A = [](11, 22, 33), plist(A[2 .. 3]).
evaluated_to([22, 33])
...