ОШИБКА: Неопределенная процедура: (+)/2

Я новичок в SWI-Prolog и хочу проверить основную функцию в Prolog.

prime(N) :-
    N > 1,
    M is N - 1,
    check(N, M).

check(_, 1).
check(N, M) :-
    M > 1,
    R is N - M * N / M,
    R > 0,
    P is M - 1,
    check(N, P).

но когда я спрашиваю 2 + 2 или другой оператор, такой как (*)/2, (/)/2,... в Прологе он говорит: undefined procedure: (+)/2. Я думаю, что это для see или tell. Я переназначаю see(user) и tell(user), но эта ошибка возникает снова. Почему?


person strawberry    schedule 11.06.2012    source источник
comment
Невозможно воспроизвести на SWI-Prolog 5.10.1. Вы пытались запустить это в новой, чистой среде Prolog?   -  person Fred Foo    schedule 11.06.2012
comment
Ошибка не может возникнуть из кода, который вы показываете, который кажется синтаксически правильным. В «командной строке» (она называется REPL), возможно, вам следует ввести что-то вроде ?- X is 2+2.   -  person CapelliC    schedule 11.06.2012


Ответы (3)


В SWI prolog 6.0.2 деление, как вы использовали, возвращает число с плавающей запятой. Так, например, prime(13) потерпит неудачу, так как остаток равен 0. Целочисленное деление использует оператор //. Но проверьте функции пролога SWI rem и mod.

Также вы хотели бы иметь разрез после первого определения check, иначе пролог будет исследовать второе определение, которое вернет false. Cut гарантирует, что после проверки всех натуральных чисел, меньших N, он остановится с успехом.

Вот исправленный код, который ведет себя так, как хотелось бы, в SWI Prolog 6.0.2.

prime(N) :-
    N > 1,
    M is N - 1,
    check(N, M).

check(_, 1) :- !.
check(N, M) :-
    M > 1,
    R is N mod M,
    R > 0,
    P is M - 1,
    check(N, P).
person BorisM    schedule 11.06.2012

Что касается вашей ошибки, проверьте это:

?- 2+2.
ERROR: Undefined procedure: (+)/2

?- X is 2+2.    
X = 4 

Вы должны использовать is в Прологе для принудительного вычисления арифметических выражений. Попробуйте ввести "help(is)." в приглашении SWI-Prolog.

Но ваш алгоритм крайне неэффективен по двум причинам. Сначала вы проверяете число-кандидат на делимость на все предшествующие ему числа, при этом достаточно только тех, которые не больше его квадратного корня (если a*b=n и a >= sqrt(n), то b =< sqrt(n)).

Затем вы тестируете в обратном порядке. Множественные меньшие факторы встречаются гораздо чаще, чем большие, поэтому тестирование будет прервано гораздо раньше, если оно будет выполняться в порядке возрастания, благодаря чему вся программа будет работать намного намного быстрее. Наконец, нет необходимости проверять любое четное число, кроме 2:

prime(2).
prime(N) :- N > 1,
    N mod 2 > 0,              % is odd
    M is floor(sqrt(N+1)),    % round-off paranoia 
    check(N, M, 3).

check(N, M, F) :- F>M.
check(N, M, F) :- F=<M,
    N mod F > 0,
    F1 is F + 2,              % test by odds only
    check(N, M, F1).

primesFromTo(F,T,X):-
  between(F,T,X), prime(X).
person Will Ness    schedule 13.06.2012

Вы упоминаете see и tell: это очень старомодные встроенные предикаты. Лучше избегать их. Используйте [file], чтобы загрузить файл, и make, чтобы перезагрузить его.

Для лучшей реализации тестирования простых чисел см. этот ответ.

person false    schedule 09.07.2012