Как я могу написать f (g (h (x))) в Scala с меньшим количеством скобок? - PullRequest
6 голосов
/ 29 августа 2011

Выражения типа

ls map (_ + 1) sum

прекрасны, потому что они слева направо и не вложены. Но если рассматриваемые функции определены вне класса, это менее красиво.

После пример Я пытался

final class DoublePlus(val self: Double) {
    def hypot(x: Double) = sqrt(self*self + x*x)
}

implicit def doubleToDoublePlus(x: Double) =
    new DoublePlus(x)

, насколько я могу судить, отлично работает, кроме

  1. Много печатать для одного метода

  2. Вы должны заранее знать, что хотите использовать его таким образом

Есть ли хитрость, которая решит эти две проблемы?

Ответы [ 5 ]

13 голосов
/ 29 августа 2011

Вы можете вызвать andThen для объекта функции:

(h andThen g andThen f)(x)

Вы не можете вызывать его непосредственно для методов, хотя, возможно, ваш h должен стать (h _) для преобразования методав частично примененную функцию.Компилятор автоматически преобразует последующие имена методов в функции, потому что метод andThen принимает параметр Function.

Вы также можете использовать оператор pipe |>, чтобы написать что-то подобное:

x |> h |> g |> f
2 голосов
/ 29 августа 2011
def fgh (n: N) = f(g(h(n))) 
val m = fgh (n) 
2 голосов
/ 29 августа 2011

Обогащение существующего класса / интерфейса неявным преобразованием (что вы и сделали с doubleToDoublePlus) - это все о разработке API, когда некоторые классы не находятся под вашим контролем. Я не рекомендую делать это слегка, чтобы сохранить несколько нажатий клавиш или иметь несколько меньших скобок. Поэтому, если важно иметь возможность набирать val h = d hypot x, дополнительные нажатия клавиш не должны вызывать беспокойства. (могут быть проблемы с распределением объектов, но это не так).

Название и ваш пример также не совпадают:

f(g(h(x))) можно переписать как f _ compose g _ compose h _ apply x, если вас беспокоит скобка, или f compose g compose h apply x, если f, g, h функциональные объекты , а не def .

Но ls map (_ + 1) sum не являются вложенными вызовами, как вы говорите, поэтому я не уверен, как это относится к названию. И хотя это прекрасно в использовании, разработчики библиотек / языков приложили немало усилий, чтобы упростить его использование, а под капотом это не просто (гораздо сложнее, чем ваша гипотеза пример).

0 голосов
/ 04 октября 2018

Начиная с Scala 2.13, стандартная библиотека обеспечивает операцию связывания pipe, которую можно использовать для преобразования / передачи значения с интересующей функцией.

Используя несколько pipe с, мы можем построить pipeline, который, как указано в заголовке вашего вопроса, минимизирует количество скобок:

import scala.util.chaining._

x pipe h pipe g pipe f
0 голосов
/ 30 августа 2011

Может быть, посмотрите, как предоставляется:

def compose [A, B, C] (f: B => C, g: A => B): A => C = (a: A) => f (g (a))

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

...