Я просмотрел миллионы других подобных вопросов, но не нашел рабочего решения, поэтому задаю следующее:
У меня есть правило:
check_prime(X) :-
X > 0,
X0 is X - 1,
(X =:= 1 -> true; X =:= 2 -> true; foreach(between(2, X0, T), X mod T =\= 0) -> true; false).
тогда я хочу запустить:
B is [0],
foreach(between(1, 50, T), (check_prime(T) -> B2 = [B, T], write(B2); !)).
Это успешно позволяет записать на консоль пары [0, primeNumber]. Альтернативно я могу сделать это:
B is [0], foreach(between(1, 50, T), (check_prime(T) -> (write(T), write(", ")); !)).
который на самом деле печатает все красиво, за исключением отсутствия списка и лишней запятой в конце.
Эта функция записи работает с решениями check_prime(T) рекурсивно, по одному решению за раз. Я хочу составить список всех этих решений, но, что бы я ни пытался, я либо не могу добиться постоянства объекта (записанный атом — это что-то вроде _31415926), либо сталкиваюсь с множеством ошибок.
Как динамически создать список простых чисел, поскольку каждое из них находится рекурсивно?
Редактировать:
Да, это весь код, который я использую:
Я пробовал изменить ветку «если правда», но у нее продолжают возникать проблемы:
Пожалуйста, укажите код, с помощью которого вы действительно пытались решить эту проблему.
«foreach(between(1, 50, T)...)» устанавливает T равным 1 и продолжает выполнение команды foreach. если ваш истинный или ложный оператор содержит !, он проигнорирует это значение (при условии, что вы выполнили условие !) и продолжит работу. Что касается «фактического кода», я добавил для справки две картинки.
Это не рекурсия.
Код, создающий список, не обязательно использовать write
.
Это не имеет смысла, потому что если я выполню «B is [0], foreach(between(1, 50, T), (check_prime(T) -> B2 is [T], write(B2); !)) .», на выходе будет «1, ложь», и он остановится. Если это не рекурсия, почему я должен получить только частичный ответ? Была также версия кода (не совсем помню), где мне давали по одному простому числу за раз.
Я пытаюсь подтвердить, что составляю список, записывая его.
Рекурсия — это когда функция/предикат вызывает саму себя.
У нас есть 3 варианта: (1) foreach создает список от 1 до 50, а T — весь список. (2) foreach перебирает значения от 1 до 50, и каждый раз T становится новым значением. (3) foreach присваивает T, запускает тест, выполняет условие, затем отменяет то, что он сделал, переназначает T с новым значением и повторяет. Я называю эту рекурсию, потому что мы отменяем то, что сделали, возвращаемся к точке выбора (выбору того, что присвоить T) и выбираем новое значение, в отличие от цикла, который просто переназначает T и повторно выполняет процедуру. .
Таким образом, номер 3 будет рекурсией в том смысле, что действие повторяется с новым значением T в точке выбора.
Повторный вызов одной и той же функции — это не то же самое, что функция, вызывающая сама себя.
Хорошо, справедливо, хотя, на мой взгляд, в обычном примере факториала факториал(X) затем вызывает факториал(X-1), и X-1 становится новым X... но, возможно, есть небольшая разница, конечно. Как теперь составить список?
Это будет создание списка с использованием рекурсии: primes_between(A,B) = если A > B, то [] elif A является простым, то [A] + primes_between(A+1,B) else primes_between(A+1,B)
Можем ли мы вернуться к теме, как составить список?
Этот код составляет список.
Тогда почему я не могу записать список в консоль?
для простоты сравните код: >> B равно [0], foreach(between(1, 50, T), (check_prime(T) -> (write(T), write(", ")); !)) . << который записывает каждое простое число T по мере его обнаружения, по сравнению с этим кодом: >> B равно [0], foreach(between(1, 50, T), (check_prime(T) -> B2 = [B, T]) ; !), напишите(B2). << который должен записать список, как только мы прошли весь диапазон для T. Однако второй код пишет B2 = [0, T], что неверно, поскольку T — это каждое число от 1 до 50.
Несколько хороших примеров есть на сайте rosettacode.org/wiki/Sieve_of_Eratosthenes#Prolog
«Если это не рекурсия, почему я должен получить только частичный ответ?» - потому что твой разрез !
убивает возврат назад. «(3) foreach присваивает T, запускает тест, выполняет условие, затем отменяет то, что он сделал, переназначает T с новым значением и повторяет. Я называю эту рекурсию, потому что мы отменяем то, что сделали, возвращаясь вверх. до точки выбора» — вы вызываете рекурсию с возвратом; рекурсия так себя не ведет, так что это бесполезно. «Тогда почему я не могу записать список в консоль?» - поскольку отмена возврата отменяет построение списка, она должна находиться за пределами возврата.
TessellatingHeckler - спасибо за объяснение! Думаю, я путаю возврат с возвратом и рекурсию. brebs - спасибо за пример, я изучу его, чтобы лучше понять, как составить список без возврата.
Как динамически создать список простых чисел?
Сделайте check_prime проверку, является ли число простым (и ничего больше):
check_prime(1).
check_prime(2).
check_prime(X1) :-
X1 > 2,
succ(X0, X1),
forall(between(2, X0, N), \+ (0 is X1 mod N)).
Затем используйте его, чтобы составить список простых чисел, например:
?- findall(X, (between(1, 50, X), check_prime(X)), Primes).
Primes = [1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
или
primes_to(X, Primes) :-
numlist(1, X, Nums),
include(check_prime, Nums, Primes).
?- primes_to(50, Primes).
Primes = [1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
если вы действительно хотите сделать это рекурсивно, а не удобно, построитель, который добавляет счетчик в список простых чисел, если счетчик является простым, и не добавляет, если это не так:
primes_to(0, []).
primes_to(Counter, [Counter|Primes]) :-
check_prime(Counter),
Counter0 is Counter - 1,
primes_to(Counter0, Primes).
primes_to(Counter, Primes) :-
\+ check_prime(Counter),
Counter0 is Counter - 1,
primes_to(Counter0, Primes).
?- primes_to(50, Primes).
Primes = [47, 43, 41, 37, 31, 29, 23, 19, 17, 13, 11, 7, 5, 3, 2, 1]
Ах, это выглядит хорошо. Я, вероятно, реализую первые два примера. Моя цель состояла в том, чтобы сделать то же, что и ваш второй набор кода: использовать check_prime, чтобы просто проверить, является ли число простым, а затем использовать primes_to, чтобы пользователь мог получить все простые числа от 1 до заданного ввода в виде списка. Мне нужно будет изучить синтаксис для дальнейшего использования (у вас нет единого «если-то-иначе»), но в остальном он выглядит чистым, и я могу следить за тем, что он делает.
Как вы думаете, где в этом коде рекурсия?