#prolog
#пролог
Вопрос:
привет всем, я снова здесь, на этой неделе я получил это домашнее задание:
Я должен найти все числа между 10
и 10000
, которые обладают свойством, подобным следующему примеру:
89 = 8^1 9^2
2427 = 2^1 4^2 2^3 7^4 = 2 16 8 2401
Я реализовал это в Haskell, и это работает просто отлично (я думаю) и возвращает список, подобный этому:
[89,135,175,518,598,1306,1676,2427]
и затем я попытался записать его в Prolog (по мере необходимости тоже) следующим образом:
num(0).
num(1).
num(2).
num(3).
num(4).
num(5).
num(6).
num(7).
num(8).
num(9).
allNarc(X):- num(A),num(B),num(C),num(D),
X = A*1000 B*100 C*10 D,Y = A**1 B**2 C**3 D**4,
X =:= Y,X>10.
allNarc(X):- num(B),num(C),num(D),
X = B*100 C*10 D,Y = B**1 C**2 D**3,
X =:= Y,X>10.
allNarc(X):- num(C),num(D),
X = C*10 D,Y = C**1 D**2,
X =:= Y,X>10.
результат получается примерно таким:
?- allNarc(X).
X = 1*1000 3*100 0*10 6 ;
X = 1*1000 6*100 7*10 6 ;
X = 2*1000 4*100 2*10 7 ;
X = 0*100 4*10 3 ; <- 43
X = 0*100 6*10 3 ; <- 63
X = 1*100 3*10 5 ;
X = 1*100 7*10 5 ;
X = 5*100 1*10 8 ;
X = 5*100 9*10 8 ;
X = 8*10 9 ;
false.
очевидно, что 43
и 64
не должны принадлежать к этой группе, и результат просто уродлив, кто-нибудь может помочь мне получить результат, подобный результату в моей реализации на Haskell?
Ответ №1:
Два очка.
- когда вы говорите,
X =
вы объединяете левую и правую части=
. Если вы хотите, чтобы X было числом, равным вычислению выражения, используйтеX is <expression here>
. - вы хотите предотвратить появление нуля в первой позиции:
num(A), A = 0, num(B), ...
После внесения этих изменений я получаю:
?- allNarc(X).
X = 1306 ? ;
X = 1676 ? ;
X = 2427 ? ;
X = 135 ? ;
X = 175 ? ;
X = 518 ? ;
X = 598 ? ;
X = 89 ? ;
no
Вы также могли бы использовать bagof
для сбора значений. например, bagof(X,allNarc(X),Narcs).
Narcs
тогда это список ваших значений.
Комментарии:
1. эй, большое спасибо, я только что понял это сам. Я бы предпочел использовать
setof
для получения точного списка, подобного моей программе на haskell.
Ответ №2:
Вам нужно:
- Не допускайте, чтобы первые цифры были равны 0.
- Убедитесь, что X вычисляется до нужного вам значения. На данный момент вы используете термин unification, который не подходит, вам нужно использовать
is
ключевое слово.
Смотрите:
num(0).
num(1).
num(2).
num(3).
num(4).
num(5).
num(6).
num(7).
num(8).
num(9).
posnum(A) :- num(A), A = 0.
allNarc(X):- posnum(A),num(B),num(C),num(D),
X is A*1000 B*100 C*10 D,Y is A**1 B**2 C**3 D**4,
X =:= Y,X>10.
allNarc(X):- posnum(B),num(C),num(D),
X is B*100 C*10 D,Y is B**1 C**2 D**3,
X =:= Y,X>10.
allNarc(X):- posnum(C),num(D),
X is C*10 D,Y is C**1 D**2,
X =:= Y,X>10.
Обратите внимание, что затем вы можете найти все числа с помощью setof
:
?- setof(X,allNarc(X),XL).
XL = [89, 135, 175, 518, 598, 1306, 1676, 2427].
Это гораздо удобнее, чем перечислять их по одному.
Комментарии:
1. привет, спасибо 🙂 Я обнаружил, что я должен предотвратить такие вещи, как
43 = 0^1 4^2 3^3
из моего результата, что привело к вашему объяснению,1.
кстати, я бы предпочел использоватьsetof
B)2. Исправлено! Прошло некоторое время с тех пор, как я делал какой-либо пролог, поэтому я забыл о
setof
:).