Рубрики
Без рубрики

Предикат (логика программирования)

Несколько слов о булевых функциях. Помечено учебником, javascript, ruby, java.

dj-еженедельник (Серия из 4 частей)

Первоначально опубликовано по адресу derk-jan.com . Недавно я снова взялся за написание и пытаюсь публиковать хотя бы один полезный пост каждую неделю в течение следующих 49 недель.

В университете я должен был учиться Пролог при использовании Цели , чтобы создать агента (искусственный интеллект) для игры и победы захвата флага в турнире Unreal. Эта статья не о Прологе или цели, но она помогает мне мысленно смоделировать, что такое предикаты .

Предикаты в английском языке

В английском языке предикат – это шаблон глагольной фразы, который описывает свойство или связь, представленную переменными в этом шаблоне. Например, фразы “Джессика работает” , “Программа запущена” и “Машина, которая собирает детали автомобиля, работает” все взяты из одного и того же шаблона “x работает”, где x заменяется соответствующим существительным или именной фразой. Фраза “работает” является предикатом, и она описывает свойство “находиться в запущенном состоянии”.

Это не ограничивается свойствами, так как “Функция выдает ошибку при запуске” , “Операция создает значение при компиляции” и “API создает новую модель при ее развертывании” все создаются путем замены a , b и c в шаблоне “a порождает b, когда c” . Последнее является предикатом и описывает связь между двумя объектами и состоянием. Это может быть представлено как Производит(A, B, C) или даже P(a, b, c) .

Предикаты в программировании

Теперь, в математической логике, предикаты обычно представляют собой функции с логическим значением , которые не намного больше, чем функция, которая принимает набор входных данных и выводит только логическое значение.

Например:

number = 2

isEven(number)
// => true

Функция четна принимает набор входных данных (все натуральные числа) и возвращает истину или ложь , на основе предиката. Более конкретно, он возвращает true если оно удовлетворяет предикату, и ложно в противном случае. Функция четна поэтому является предикатом.

Помимо конкретно создания функций, возвращающих верно или ложь , предикаты используются повсюду. Например, во многих языках существует функция filter() для чего-то перечислимого, например, для структуры данных, подобной списку.

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class JavaExample {

    public static void main(String[] args) {
        List numbers = Arrays.asList(1, 2, 3, 5, 8, 13, 21, 34);
        Predicate isEven = n -> n % 2 == 0;

        numbers.stream()
               .filter(isEven)
               .forEach(System.out::println);
  }
}

// 2
// 8
// 34

В этом примере Java лямбда (анонимная функция, которую мы назвали четной ) имеет тип Предикат<Целое число> , представляющий собой функцию , которая принимает Целое число и возвращает истину или ложь . Функция является предикатом . Предикат | передается в функцию .filter() , которая будет выполнять предикат для каждого элемента в списке.

isEven(1)
// => false

isEven(2)
// => true

isEven(5)
// => false

isEven(8)
// => true

isEven(13)
// => false

isEven(21)
// => false

isEven(34)
// => false

Окончательный “список” элементов, который попадает в .forEach это те, которые оцениваются как true , потому что это то, что делает .filter() : сохраняет элементы, для которых предикат возвращает true .

Язык не нужно вводить для поддержки предикатов. Вот эквивалентный пример в JavaScript:

const numbers = [
  1, 2, 3, 5, 8, 13, 21, 34
]

const isEven = (n) => n % 2 === 0

numbers
  .filter(isEven)
  .forEach((i) => console.log(i))

// 2
// 8
// 34

Опять же, каждое значение в массиве numbers присваивается предикату seven() , а те, которые оценивают предикат до true , будут сохранены (и затем регистрируются в .forEach ). На самом деле не имеет значения, назовете ли вы предикат, использование встроенной анонимной функции не меняет того факта, что это предикат:

const numbers = [
  1, 2, 3, 5, 8, 13, 21, 34
]

numbers
  .filter((n) => n % 2 === 0)
  .forEach((i) => console.log(i))

// 2
// 8
// 34

В Ruby есть языковая функция встроенная для поддержки предикатов! Методы предикатов в Ruby – это те методы, которые заканчиваются знаком вопроса ? ; они возвращают либо истину или ложь . Тот же пример в Ruby выглядит примерно так:

NUMBERS = [1, 2, 3, 5, 8, 13, 21, 34]

NUMBERS.select { |i| i.even? }
       .each { |i| p i }

# Or alternatively
NUMBERS.select(&:even?)
       .each { |i| p i }

# 2
# 8
# 34
# => [2, 8, 34]

Вывод

Предикаты используются повсюду, и теперь вы можете называть их таковыми. Каждый раз, когда функция (например, .filter() ) принимает аргумент – аргумент, который должен быть самой функцией ; функция, которая возвращает верно или ложь на основе некоторых входных данных (например, семь ) – вы знаете, что имеете дело с предикатом .

О, а в Прологе? В прологе определите предикат событие следующим образом:

even(X) :- 0 is mod(X, 2).

? even(1)
false

? even(2)
true

А затем отфильтруйте список на основе четных элементов:

/** Predicates */

even(X) :- 0 is mod(X, 2).
odd(X)  :- 1 is mod(X, 2).

/**
 * Filter the list on even elements only
 * 1. true when empty
 * 2. otherwise, there are two options
 *    - if Element (first item) is odd, the Next list does not get Element
 *    - if Element is even, the Next list gets Element
 */
filter([], []).
filter([Element|Tail],        Next) :-  odd(Element), filter(Tail, Next).
filter([Element|Tail], [Element|T]) :- even(Element), filter(Tail, T).

/**
 * Prints a list by iteration through each element
 * 1. true when empty
 * 2. separate Element (first item) and the Tail (...rest)
 *    - write the element + new line
 *    - continue printlist with the tail of the list
 */
printlist([]).
printlist([Element|Tail]) :-
    write(Element),nl,
    printlist(Tail).


?- filter([1, 2, 3, 5, 8, 13, 21, 34], NewList), printlist(NewList).

2
8
34

Хотите, чтобы эти короткие статьи были в вашем электронном письме? 📧 Подпишитесь на мою рассылку новостей .

dj-еженедельник (Серия из 4 частей)

Оригинал: “https://dev.to/sleeplessbyte/predicate-programming-logic-7f3”