Идиома функционального программирования для применения серии функций void к одному значению

Учитывая значение foo и Stream из Consumer<Foo> функций void, какой самый краткий способ применить каждую функцию к значению? Прямо сейчас у меня есть

consumers.forEach(c -> c.accept(foo));

что не страшно, но я подозреваю, что есть способ вывернуть это наизнанку и сделать это только с помощью ссылок на методы (без явной лямбды). Возможно что-то с одноэлементным списком и zip()?

Я был бы счастлив получить прямой ответ на Java 8 или Vavr или Scala.

(Обратите внимание, что это не свертка или, по крайней мере, не обычное _6 _ / _ 7_ приложение; если бы были возвращаемые значения, я бы отбросил их, а не повторял их.)


person David Moles    schedule 28.11.2017    source источник
comment
объединяется через _ 1_ допустимый вариант?   -  person Izruo    schedule 29.11.2017
comment
Интересный вопрос, но в Java нет ничего более простого, лаконичного или производительного в типичных виртуальных машинах, чем то, что у вас уже есть.   -  person Lucas Ross    schedule 29.11.2017
comment
forEach и функции void не используются в функциональных идиомах ... вы ищете то, чего не существует   -  person Mulan    schedule 29.11.2017
comment
@naomik Хорошо, притворись, что это functions.map(f -> f.apply(foo)), если ты обнаружишь, что этого не существует.   -  person David Moles    schedule 29.11.2017
comment
@naomik И рассмотрим монаду ввода-вывода.   -  person David Moles    schedule 29.11.2017
comment
@DavidMoles map создаст новую коллекцию, которую можно отправить другой функции; forEach не имеет возвращаемого значения и поэтому не может быть составлен - функции forEach и void не работают   -  person Mulan    schedule 29.11.2017
comment
@naomik Я знаю, что делает map.   -  person David Moles    schedule 29.11.2017
comment
так что вы перестанете сравнивать его с forEach как с чем-то вроде эквивалента?   -  person Mulan    schedule 29.11.2017
comment
@naomik Функциональность map() является строгим расширением forEach(). Я был бы доволен решением, в котором используется map().   -  person David Moles    schedule 29.11.2017


Ответы (3)


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

person throughnothing    schedule 23.04.2018
comment
Сделало бы код более лаконичным? Скажем, я (где-то в другом месте, чтобы это не противоречило краткости) обернул каждый Consumer<Foo> как Function<Foo, Foo>: Stream<Function<Foo, Foo>> functions = consumers.map(c -> (f) -> { c.accept(f); return f; }); - как бы проще было связать их в цепочку? - person David Moles; 01.05.2018

Вы можете уменьшить количество потребителей с помощью метода Consumer.andThen, а затем применить полученного потребителя к аргументу foo:

consumers.reduce(Consumer::andThen).ifPresent(c -> c.accept(foo));

Но нет никакой разницы между этим подходом и вашим, а ваш - короче.

person fps    schedule 28.11.2017

В Scala вы должны уметь

consumers.foreach(_.accept(foo));
person haaawk    schedule 28.11.2017
comment
Это именно то, что сделал OP , это прямо в вопросе. - person jwvh; 29.11.2017
comment
Это не совсем то же самое. Он компилируется в один и тот же байт-код, но использует другой синтаксис. Я не говорю, что это революционно, но Дэвид спросил, как сделать это более кратко, и это короче, не так ли? - person haaawk; 29.11.2017
comment
Достаточно верно, но если вы действительно пытаетесь создать краткую Scala, вы должны использовать foreach (forEach не Scala) и отбросить точку с запятой ; (Scala - это не Java). Даже после этого, если бы мы играли партию в кодовый гольф, вы все равно были бы бить в 2 удара: for(c<-consumers)c.accept(foo) - person jwvh; 29.11.2017
comment
Ага. Я мог бы подойти немного ближе с consumers.foreach(_ accept foo). Еще один персонаж позади :). consumers foreach _ accept foo наверное не сработает :). - person haaawk; 29.11.2017
comment
Причина, по которой я предложил использовать решение Scala, заключается в том, что обычно его просто переводить со Scala на Vavr, и, вероятно, здесь больше программистов Scala, чем (хороших) функциональных программистов Java. Этот ответ более лаконичен, но только потому, что Scala более лаконична. - person David Moles; 29.11.2017