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) { Listnumbers = 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”