Негласное программирование
Неявное программирование , также называемое бесточечным стилем , представляет собой парадигму программирования , в которой определения функций не идентифицируют аргументы (или «точки»), над которыми они работают. Вместо этого определения просто составляют другие функции, среди которых есть комбинаторы , манипулирующие аргументами. Неявное программирование представляет теоретический интерес, поскольку строгое использование композиции приводит к созданию программ, которые хорошо адаптированы для уравнений . [1] Это также естественный стиль некоторых языков программирования , включая APL и его производные. [2] и конкатенативные языки, такие как Форт . Отсутствие именования аргументов дает бесточечному стилю репутацию излишне неясного, отсюда и прозвище «бессмысленный стиль». [1]
Unix Сценарии используют парадигму с каналами .
Примеры
[ редактировать ]Питон
[ редактировать ]Неявное программирование можно проиллюстрировать с помощью следующего кода Python . Последовательность операций, например, следующая:
def example(x):
return baz(bar(foo(x)))
... можно записать в бесточечном стиле как композицию последовательности функций без параметров: [3]
from functools import partial, reduce
def compose(*fns):
return partial(reduce, lambda v, fn: fn(v), fns)
example = compose(foo, bar, baz)
Более сложный пример: код Haskell. p = ((.) f) . g
можно перевести как:
p = partial(compose, partial(compose, f), g)
Функциональное программирование
[ редактировать ]Простым примером (на Haskell ) является программа, которая вычисляет сумму списка чисел. Мы можем определить функцию суммы рекурсивно, используя заостренный стиль (см. значений программирование на уровне ) следующим образом:
sum (x:xs) = x + sum xs
sum [] = 0
Однако, используя складку, мы можем заменить это на:
sum xs = foldr (+) 0 xs
И тогда аргумент не нужен, так что это упрощает
sum = foldr (+) 0
который является бесточечным.
В другом примере используется композиция функций :
p x y z = f (g x y) z
Следующий псевдокод в стиле Haskell показывает, как свести определение функции к ее бесточечному эквиваленту:
p = \x -> \y -> \z -> f (g x y) z
= \x -> \y -> f (g x y)
= \x -> \y -> (f . (g x)) y
= \x -> f . (g x)
(* Here the infix compose operator "." is used as a curried function. *)
= \x -> ((.) f) (g x)
= \x -> (((.) f) . g) x
p = ((.) f) . g
Наконец, чтобы увидеть сложный пример, представьте себе программу фильтра карты, которая берет список, применяет к нему функцию, а затем фильтрует элементы на основе критерия.
mf criteria operator list = filter criteria (map operator list)
Его можно выразить без точек [4] как
mf = (. map) . (.) . filter
Обратите внимание, что, как указывалось ранее, точки в слове «без точек» относятся к аргументам, а не к использованию точек; распространенное заблуждение. [5]
Было написано несколько программ для автоматического преобразования выражения Haskell в бесточечную форму.
Семья АПЛ
[ редактировать ]В J такой же бесточечный код встречается в функции, предназначенной для вычисления среднего значения списка (массива) чисел:
avg=: +/ % #
+/
суммирует элементы массива путем сопоставления ( /
) суммирование ( +
) в массив. %
делит сумму на количество элементов ( #
) в массиве.
Формула Эйлера выразил молчаливо:
cos =: 2 o. ]
sin =: 1 o. ]
Euler =: ^@j. = cos j. sin
( j.
— это примитивная функция, монадическое определение которой есть 0j1
раз x и чье двоичное определение x+0j1×y
.) Те же неявные вычисления, выраженные в Dyalog APL :
avg ← +⌿ ÷ ≢
cos ← 2 ○ ⊢
sin ← 1 ○ ⊢
EulerCalc← cos + 0j1 × sin ⍝ 0j1 is what's usually written as i
EulerDirect← *0J1×⊢ ⍝ Same as ¯12○⊢
⍝ Do the 2 methods produce the same result?
EulerCheck← EulerDirect=EulerCalc
EulerCheck ¯1 1 2 3
1 1 1 1
⍝ Yes, so far so good!
На основе стека
[ редактировать ]В языках программирования, ориентированных на стек (и конкатенативных языках , большинство из которых основаны на стеке). [ нужна ссылка ] ), обычно используются бесточечные методы. Например, процедура вычисления чисел Фибоначчи может выглядеть следующим образом в PostScript :
/fib
{
dup dup 1 eq exch 0 eq or not
{
dup 1 sub fib
exch 2 sub fib
add
} if
} def
Трубопроводы
[ редактировать ]Конвейер Unix
[ редактировать ]В сценариях Unix функции представляют собой компьютерные программы, которые получают данные со стандартного ввода и отправляют результаты на стандартный вывод . Например,
sort | uniq -c | sort -rn
представляет собой неявную или бесточечную композицию, которая возвращает количество своих аргументов и аргументов в порядке убывания количества. 'sort' и 'uniq' являются функциями, '-c' и '-rn' управляют функциями, но аргументы не упоминаются. Труба '|' является оператором композиции.
Из-за особенностей работы конвейеров обычно можно передавать только один «аргумент» за раз в виде пары стандартных потоков ввода/вывода. Хотя дополнительные дескрипторы файлов могут быть открыты из именованных каналов , это больше не является бесточечным стилем.
jq
[ редактировать ]jq — это язык программирования, ориентированный на JSON, в котором '|' символ используется для соединения фильтров в конвейер знакомым способом. Например:
[1,2] | add
оценивается как 3. (Да, массив JSON — это фильтр jq, который оценивается как массив.)
Хотя конвейеры jq похожи на конвейеры Unix, они позволяют входящие данные должны быть отправлены более чем одному получателю на Правая часть знака '|' как бы параллельно. Например, программа `add/length` вычислит среднее значение чисел в массиве, так что:
[1,2] | add/length
оценивается в 1,5
Сходным образом:
[1,2] | [length, add, add/length]
оценивается как [2,3,1.5]
Точку ('.') можно использовать для определения точки присоединения к правой части, например:
1 | [., .]
оценивается как [1,1]
и аналогично:
2 | pow(.; .)
оценивается как 4, поскольку pow(x;y) равен x в степени y.
Последовательность Фибоначчи
[ редактировать ]Неявная программа jq для генерации последовательности Фибоначчи будет такой:
[0,1] | recurse( [last, add] ) | first
Здесь [0,1] — исходная пара, которую следует принять в качестве первых двух элементов. в последовательности Фибоначчи. (Пара [1,1] также может быть использована для вариант определения.)
Алфавитные токены представляют собой встроенные фильтры: «первый» и «последний». выдать первый и последний элементы своих входных массивов соответственно; и `recurse(f)` рекурсивно применяет фильтр f к своим входным данным.
jq также позволяет определять новые фильтры в неявном стиле, например:
def fib: [0,1] | recurse( [last, add] ) | first;
Состав унарных функций
[ редактировать ]В разделе Python этой статьи рассматривается следующее определение Python:
def example(x):
return baz(bar(foo(x)))
В бесточечном стиле это можно было бы записать на Python так:
example = compose(foo, bar, baz)
В jq эквивалентное бесточечное определение будет таким:
def example: foo | bar | baz;
См. также
[ редактировать ]- Комбинаторная логика
- Конкатенативный язык программирования
- Программирование на функциональном уровне
- Joy (язык программирования) , современный высокомолчаливый язык.
Ссылки
[ редактировать ]- ^ Jump up to: а б Мануэль Алсино Перейра да Кунья (2005) Расчет программы без очков
- ^ В. Невилл Холмс, изд. (2006) Компьютеры и люди
- ^ «Код имени, а не значения» . Concatenative.org . Проверено 13 сентября 2013 г.
- ^ пипермейл
- ^ «Pointfree — HaskellWiki» . wiki.haskell.org . Проверено 5 июня 2016 г.
Внешние ссылки
[ редактировать ]- От программирования на функциональном уровне к бесточечному стилю
- Чистые функции в APL и J. Как использовать неявное программирование на любом APL-подобном языке.
- Закрытые аппликативные языки 1971–1976 и далее , у Джона В. Бэкуса (Публикации)