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”