Почему унарные функции нельзя использовать в постфиксной нотации? - PullRequest
0 голосов
/ 28 февраля 2020

Я вижу два основных преимущества постфикса перед префиксными нотациями для унарных функций:

  • хорошее форматирование, нет вложенности
  • отображает лучше Input -> Function -> Ouput способ мышления при обработке данных ,

Вот пример:

def plus2(v: Int) = v + 2
def double(v: Int) = v * 2
def square(v: Int) = v * v

// prefix
square(
  double(
    plus2(1)
  )
)

// postfix
1.plus2
 .double
 .square

Это можно эмулировать, как в Java API-интерфейсе потока с цепочкой методов или другими пользовательскими методами. Но я не знаком ни с одним языком программирования, который предлагает первоклассную поддержку приложения с постфиксной функцией.

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

1 Ответ

1 голос
/ 28 февраля 2020

Я не знаком ни с одним языком программирования, который позволяет это.

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

class Example {
    final int x;
    Example(int x) { this.x = x; }

    Example add2() { return new Example(x + 2); }
    Example mult2() { return new Example(x * 2); }
    Example square() { return new Example(x * x); }

    public static void main(String[] args) {
        Example result =
            new Example(1)
            .add2()
            .mult2()
            .square();
    }
}

Вам нужны скобки (), чтобы вызвать их, конечно, но это все же порядок постфикса. К сожалению, вы не можете адаптировать это, чтобы использовать методы stati c вместо методов экземпляра, по крайней мере, без злоупотребления Optional или Stream, например:

Optional.of(1)
    .map(StaticExample::add2)
    .map(StaticExample::mult2)
    .map(StaticExample::square)
    .get()

Я думаю, причина OOP языки не облегчают использование методов stati c таким образом, потому что было бы странно иметь специальный синтаксис, который дает привилегию stati c методам по сравнению с методами экземпляра. Смысл OOP заключается в том, чтобы делать вещи с экземплярами и полиморфизмом.


Это также возможно в функциональных языках, используя функции вместо методов: здесь F #:

let add2 x = x * 2
let double x = x * 2
let square x = x * x

let result =
    1
    |> add2
    |> double
    |> square

Здесь оператор прямого канала |> выполняет роль semanti c, отличную от . в Java, но эффект тот же: функции записываются в постфиксном порядке.

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

nums
|> List.filter isEven
|> List.map square

Здесь List.filter и List.map принимают два аргумента, но если вы вызываете их с одним аргументом, они возвращают унарную функцию. Нефункциональные языки, как правило, не имеют частичного применения (по крайней мере, не так легко), поэтому оператор прямого канала будет менее полезен.


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

(2 +) >!add2
(2 *) >!double
(@ *) >!square

1 add2 double square >result

Здесь даже такие задания, как >result, выполняются в порядке постфикса.

...