Подтвердить что ты не робот

Есть ли имя для функции, которая берет кусок данных и список функций и применяет каждую функцию к результату последнего?

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

Мне это очень нравится, потому что вместо того, чтобы писать функции назад из того порядка, в котором они применяются, вот так: (псевдокод следует)

floor (square.root (x))

вы можете записать их в том порядке, в котором данные проходят через них:

-> x (square.root, floor)

Мой вопрос в том, есть ли стандартное имя для этой функции в функциональных языках, так как у карт, сокращений и фильтрации есть стандартные имена? В документах Clojure описывается это как "потоковая передача данных через функции", но я не мог найти что-либо в googling слово thread. Я написал простую версию в Haskell:

thread :: a -> [(a -> a)] -> a
thread x []     = x
thread x (f:fs) = thread (f x) fs

и искал a -> [(a -> a)] -> a в Hoogle, но ничего не придумал.

Во время исследования этого вопроса я также понял, что вы можете сделать очень похожее действие с помощью операторов композиции функций из Control.Arrow в Haskell, например:

($2) (sin >>> cos >>> tan)

тогда как используя выделенную функцию thread более высокого порядка, вы должны написать:

thread 2 [sin, cos, tan]

Возможно ли, что первая формулировка достаточно для практического использования?

4b9b3361

Ответ 1

Имя, которое вы ищете, составная функция.

Разница между макросом нарезания резьбы и comp исходит из прежней используемой гомоциконности Clojure, а последняя ближе к математическому определению композиции.

В действительности вы можете преобразовать макрокоманду потокового вызова в вызов comp, если вы создаете одну функцию из одного аргумента на каждый шаг и отменяете порядок функций:

(defn sin [n] (Math/sin n))
(defn cos [n] (Math/cos n))

(-> 1 sin cos sin cos cos) ; 0.6858966217219662
((comp cos cos sin cos sin) 1) ; 0.6858966217219662

Ответ 2

Я думаю, вы можете использовать foldl для этого, используя соответствующие аргументы:

-- functions for testing
f1 x = x+1
f2 x = x*2
f3 x = x*x
-- here comes the line you're interested in
foldl (\x y -> y x) 2 [f1, f2, f3]

Аргументы следующие:

  • (\x y -> y x) - это функция, выполняющая функцию y и применяющая ее к аргументу x. y будет заменяться каждой функцией из списка.
  • 2 - это начальный аргумент, который вы хотите передать функциям.
  • [f1, f2, f3] - список функций.

Используя эти аргументы, foldl вычисляет следующее: f3(f2(f1(2))).

Ответ 3

Учитывая, что >>> похож на bash оператор конвейера оболочки внедренный из Unix, я бы назвал его комбинатором последовательности конвейеров.

Ответ 4

Это не совсем то, что вы ищете, но для этой функции существует "идиоматическое имя":

foldr (.) id

Опытный Хаскеллер даже не должен думать о том, что это значит; это достаточно распространено, чтобы быть одним словом.

foldr (.) id :: [a -> a] -> a -> a
foldr (.) id [abs, succ, negate] 42
    = (abs . succ . negate . id) 42
    = abs (succ (negate 42))

Функция, которую вы запросили, каждой функцией, получающей вывод предыдущего, а не следующего, будет

foldr (.) id . reverse

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

Ответ 5

Вы не можете иметь такую ​​функцию в haskell, потому что она будет ограничена только функциями, которые принимают и возвращают один и тот же тип. И это не очень полезно.

Но вы можете использовать

состав функции:

floor . sqrt 

или стрелки:

sqrt >>> floor

Ответ 6

Оливер Стил называет его sequence в своей функциональной библиотеке Javascript. pipe может быть хорошим именем.