Язык Prolog урок 6. Ввод значений и их проверка

Цель урока: рассмотреть решение логических задач на языке пролог с использованием ввода значений и проверки введенных данных

Вычисления в Прологе

Рассмотрим пример:

Пример:
Написать программу, предназначенную для выполнения суммы двух определенных чисел: сначала целых, затем вещественных.

✍ Решение:
 

predicates
    add(integer,integer).
    radd(real,real).
clauses
   add(X,Y):-Z = X + Y, write("Sum = ",Z), nl.
   radd(X,Y):-Z = X + Y, write("Sum = ",Z), nl.
goal
    add(44,23),radd(44.5,23.5).
Для того, чтобы выполнить сумму вещественных чисел, пришлось создать новое правило для работы с вещественным типомreal.
Задание 6_1:
Написать программу-калькулятор, предназначенную для выполнения основных арифметических действий над двумя числами.
Реализовать правила:

add(integer,integer).
substruct(integer,integer). /* - */
multiply(integer,integer). /* * */
divide(integer,integer). /* / */
radd(real,real).
rsubstruct(real,real).
rmultiply(real,real).
rdivide(real,real).

Вычисления в прологе можно выполнять прямо в разделе GOAL:

goal
    X=5, Y=2, Z=X+Y, write("сумма =", Z), nl.

При этом НЕЛЬЗЯ в операторе write выводить выражение:

goal
    X=5, Y=2, write("сумма =", X+Y), nl.  - нельзя!
Задание 6_2:
Вычислить Z = (x + k) * n, при x=2, k=5, n=3,4.

Ввод значений в Прологе

  • Предикат readln(Переменная) считывает строку с клавиатуры и помещает ее в Переменную.
  • Для считывания целочисленного значения используется предикат readint().
  • Для считывания вещественного значения используется предикат readreal().
  • Рассмотрим пример ввода значений:

    Пример:
    Написать правило «Эхо», которое после ввода строки, выводит ее в консоль.

    ✍ Решение:
     

    predicates
       echo
    clauses
       echo:-readln(X), write(X).
    goal
       echo.

    Проверка введенного значения

    Для проверки значения можно использовать правило. Рассмотрим пример:

    Пример:
    Запрашивать строку и выводить введенную строку на экран. Если введено слово «stop», — выводить — «OK, bye!».

    ✍ Решение:
     

    domains
    	a=symbol
    predicates
       echo
       check(a)
    clauses
       echo:-readln(X), write(X),nl, check(X),!.
       check(stop):- nl, write(" - OK, bye!").
    goal
       echo.
    Задание 6_3:
    Изменить задание 6_1: Написать программу-калькулятор, предназначенную для выполнения основных арифметических действий над двумя введенными числами. В зависимости от введенной переменной выполнить то или иное действие.

    ... 
    clausee
      calculator(X,Y,Znak):- считать число, считать второе число, считать знак, check(X,Y,Znak).
      check(X,Y,?):-  /* для суммы */, write(Z).
      check(X,Y,?):-  /* для разности */, write(Z).
    goal
       calculator(_,_,_).
    
    

    Задание 6_4:
    Вычислить выражение: Z = (esin(x))+sqrt(k+x2)

    Пояснение:

  • Задания выполнить без использования правила (в разделе GOAL).
  • Для вычисления использовать функции Пролога: exp(), sin(), sqrt().
  • Ответ: при x=5, k=16, Z=6,7864292326

    Рекурсия

    Пример:
    Разработать программу, выводящую на экран список целых чисел от 1 до 7.

    ✍ Решение:
     

    domains
      число=integer
    predicates
      вывод_чисел(число)
    clauses
      вывод_чисел(8).  /* выход из рекурсии */
      вывод_чисел(Число):- Число<8, /* рекурсивное правило */
        write("   ",Число),nl,
        Следующее_Число = Число+1,
        вывод_чисел(Следующее_Число).
    goal
      write("Вывод чисел:"), nl, вывод_чисел(1), nl.

    Объяснение:

    • Сначала программа пытается сопоставить подцель вывод_чисел(1) с подправилом вывод_чисел(8).
    • Сопоставление неудачно.
    • Затем она пытается сопоставить подцель с правилом вывод_чисел(Число). Сопоставление завершается успешно с присвоением переменной Число значения 1.
    • Затем программа сравнивает значение Число, которое равно 1, с числом 8, т.е. проверяется условие выхода.
    • Так как 1 меньше 8, то сопоставление успешно, программа переходит к следующему действию Следующее_Число = Число+1. В результате этого действия Следующее_Число = 2.
    • Далее выполняется подправило вывод_чисел(Следующее_Число), условие выхода «не срабатывает», программа продолжается дальше.
    • Программа остановится, когда Следующее_Число станет равным 8. Условие выхода из рекурсии выполнится.
    Задание 6_5:
    В окно диалога вывести числа, кратные 3 из диапазона [21;35]. После вывода последнего числа должно следовать сообщение об окончании вывода (слово «end»).
    Пример:
    Вычислить сумму ряда: 1 + 2 + 3 + … + 9 + 10

    ✍ Решение:
     

    domains
     number, sum =integer
    predicates
     sum(number,sum)
    clauses
     sum(11,0). /* выход из рекурсии */
     sum(Number,Sum):- New_number=Number+1, 
                       sum(New_number, Partial_Sum), 
                  	   Sum=Number+Partial_Sum.
    goal
     write("Сумма ряда: "),
     sum(1,Sum), write(Sum).

    Рассмотрим рекурсию пошагово:

    1 шаг: 
    сопоставление sum(1, Sum) с sum(11, 0) - не выполнимо.
    сопоставление sum(1, Sum) с sum(Number, Sum) - выполнимо: 
    Number = 1, New_number = 2, вызов sum(2, Partial_Sum). ↓ на след. шаг
    Sum=1+Partial_Sum.
    2 шаг:
    сопоставление sum(2, Sum) с sum(11, 0) - не выполнимо.
    сопоставление sum(2, Sum) с sum(Number, Sum) - выполнимо: 
    Number = 2, New_number = 3, вызов sum(3, Partial_Sum). ↓ на след. шаг
    Sum=2+Partial_Sum.
    3 шаг:
    сопоставление sum(3, Sum) с sum(11, 0) - не выполнимо.
    сопоставление sum(3, Sum) с sum(Number, Sum) - выполнимо: 
    Number = 3, New_number = 4, вызов sum(4, Partial_Sum). ↓ на след. шаг 
    Sum=3+Partial_Sum.
    ...
    11 шаг:
    сопоставление sum(11, Sum) с sum(11, 0) - выполнимо: Sum = 0, продолжение текущей итерации:
       Sum=11+Partial_Sum => Sum= 11+0 = 11 => Sum=11 переход на предыдущий шаг 10: 
         Sum=10+Partial_Sum => Sum= 10+11 = 21, переход на предыдущий шаг 9:
           Sum=9+Partial_Sum => Sum= 9+21 = 30, переход на предыдущий шаг 8:
             Sum=8+Partial_Sum => Sum= 8+30 = 38, переход на предыдущий шаг 7:
               Sum=7+Partial_Sum => Sum= 7+38 = 45, переход на предыдущий шаг 6:
    ...
    и так далее до первого шага.
    
    Задание 6_6:
    Модифицируйте предыдущую программу так, чтобы она вычисляла сумму следующего ряда целых четных чисел:

    1 + 3 + 5 + 7 + 9
    
    Задание 6_7:
    Разработайте программу вычисления факториала числа.

    Пояснение:
    Факториал:

    N! = N * (N-1) * (N-2) * ... 2 * 1
    

    Примеры:

    1! = 1
    2! = 2 * 1 = 2
    3! = 3 * 2 * 1 = 6
    4! = 4 * 3 * 2 * 1 = 24
    5! = 5 * 4 * 3 * 2 * 1 = 120
    

    Случайные числа в Прологе

    Для задания случайного числа в диапазоне от 0 до N, используется:

    random(N,X)
    где X - переменная для хранения сгенерированного числа
    
    Пример:
    Получить случайные целые числа в диапазоне от 0 до 10.

    ✍ Решение:
     

    goal
    random(10,X),
    Z=X,
    write("Случайное целое число от 0 до 10: ",Z), nl.

    Задать диапазон сгенерированных чисел из промежутка:

    Пример:
    Получить случайные целые числа в диапазоне от 10 до 35.

    ✍ Решение:
     

    goal
    random(25,X),
    Z=X+10,
    write("Случайное целое число от 10 до 35: ",Z), nl.
    Задание 6_8:
    Получить 10 случайных целых чисел в диапазоне от 5 до 25.
    Задание 6_9:
    Найти корни квадратного уравнения ax2+bx+c=0.
    Выводить x1 и x2 или пояснения: «два действительных совпадающих корня», «нет действительных корней».

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    Predicates
         уравнение(real,real,real).
         ответ(real,real,real)
    Clauses
         уравнение(A,B,C):- D=B*B-4*A*C, ответ(A,B,D).
         ответ(?,?,?):- ?,
         write("нет действительных корней").
         ответ(?,?,?):- ?, X=?, write("два действительных совпадающих корня").
         ответ(A,B,D):- W=sqrt(D), X1=?, X2=?, write("X1=",X1,"; X2=",X2).
    goal
      уравнение(1,-15,50).     /* Ответ. Х1=10 Х2=5 */