Как динамически создать список в Прологе?

Я просмотрел миллионы других подобных вопросов, но не нашел рабочего решения, поэтому задаю следующее:

У меня есть правило:

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), либо сталкиваюсь с множеством ошибок.

Как динамически создать список простых чисел, поскольку каждое из них находится рекурсивно?

Редактировать:

Да, это весь код, который я использую:

Я пробовал изменить ветку «если правда», но у нее продолжают возникать проблемы:

Как вы думаете, где в этом коде рекурсия?

Scott Hunter 07.08.2024 19:34

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

Scott Hunter 07.08.2024 19:47

«foreach(between(1, 50, T)...)» устанавливает T равным 1 и продолжает выполнение команды foreach. если ваш истинный или ложный оператор содержит !, он проигнорирует это значение (при условии, что вы выполнили условие !) и продолжит работу. Что касается «фактического кода», я добавил для справки две картинки.

Hayato 07.08.2024 20:04

Это не рекурсия.

Scott Hunter 07.08.2024 20:07

Код, создающий список, не обязательно использовать write.

Scott Hunter 07.08.2024 20:17

Это не имеет смысла, потому что если я выполню «B is [0], foreach(between(1, 50, T), (check_prime(T) -> B2 is [T], write(B2); !)) .», на выходе будет «1, ложь», и он остановится. Если это не рекурсия, почему я должен получить только частичный ответ? Была также версия кода (не совсем помню), где мне давали по одному простому числу за раз.

Hayato 07.08.2024 20:21

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

Hayato 07.08.2024 20:22

Рекурсия — это когда функция/предикат вызывает саму себя.

Scott Hunter 07.08.2024 20:23

У нас есть 3 варианта: (1) foreach создает список от 1 до 50, а T — весь список. (2) foreach перебирает значения от 1 до 50, и каждый раз T становится новым значением. (3) foreach присваивает T, запускает тест, выполняет условие, затем отменяет то, что он сделал, переназначает T с новым значением и повторяет. Я называю эту рекурсию, потому что мы отменяем то, что сделали, возвращаемся к точке выбора (выбору того, что присвоить T) и выбираем новое значение, в отличие от цикла, который просто переназначает T и повторно выполняет процедуру. .

Hayato 07.08.2024 20:26

Таким образом, номер 3 будет рекурсией в том смысле, что действие повторяется с новым значением T в точке выбора.

Hayato 07.08.2024 20:30

Повторный вызов одной и той же функции — это не то же самое, что функция, вызывающая сама себя.

Scott Hunter 07.08.2024 20:32

Хорошо, справедливо, хотя, на мой взгляд, в обычном примере факториала факториал(X) затем вызывает факториал(X-1), и X-1 становится новым X... но, возможно, есть небольшая разница, конечно. Как теперь составить список?

Hayato 07.08.2024 20:32

Это будет создание списка с использованием рекурсии: primes_between(A,B) = если A > B, то [] elif A является простым, то [A] + primes_between(A+1,B) else primes_between(A+1,B)

Scott Hunter 07.08.2024 20:34

Можем ли мы вернуться к теме, как составить список?

Hayato 07.08.2024 20:37

Этот код составляет список.

Scott Hunter 07.08.2024 20:41

Тогда почему я не могу записать список в консоль?

Hayato 07.08.2024 20:53

для простоты сравните код: >> 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.

Hayato 07.08.2024 21:01

Несколько хороших примеров есть на сайте rosettacode.org/wiki/Sieve_of_Eratosthenes#Prolog

brebs 07.08.2024 21:50

«Если это не рекурсия, почему я должен получить только частичный ответ?» - потому что твой разрез ! убивает возврат назад. «(3) foreach присваивает T, запускает тест, выполняет условие, затем отменяет то, что он сделал, переназначает T с новым значением и повторяет. Я называю эту рекурсию, потому что мы отменяем то, что сделали, возвращаясь вверх. до точки выбора» — вы вызываете рекурсию с возвратом; рекурсия так себя не ведет, так что это бесполезно. «Тогда почему я не могу записать список в консоль?» - поскольку отмена возврата отменяет построение списка, она должна находиться за пределами возврата.

TessellatingHeckler 08.08.2024 01:19

TessellatingHeckler - спасибо за объяснение! Думаю, я путаю возврат с возвратом и рекурсию. brebs - спасибо за пример, я изучу его, чтобы лучше понять, как составить список без возврата.

Hayato 08.08.2024 16:30
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
20
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как динамически создать список простых чисел?

Сделайте 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 до заданного ввода в виде списка. Мне нужно будет изучить синтаксис для дальнейшего использования (у вас нет единого «если-то-иначе»), но в остальном он выглядит чистым, и я могу следить за тем, что он делает.

Hayato 08.08.2024 16:36

Другие вопросы по теме