ГРЕШКА: Недефинирана процедура: (+)/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,... в Prolog се казва: 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. Целочисленото деление използва оператор //. Но проверете prolog SWI функциите rem и mod.

Също така бихте искали да имате изрязване след първата дефиниция на check, в противен случай prolog ще изследва втората дефиниция, която ще върне 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 в Prolog, за да принудите оценката на аритметични изрази. Опитайте да напишете "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