Зачем использовать оператор обратной трубы вместо цепочки функций?

Зачем использовать оператор обратной трубы вместо цепочки функций?

let distanceFromOrigin aPoint =
    let square x = x * x
    sqrt (square aPoint.x + square aPoint.y)

против

let distanceFromOrigin aPoint =
    let square x = x * x
    sqrt <| square aPoint.x + square aPoint.y

3 ответа

Из-за левой ассоциативности (f <| g <| x анализируется как (f <| g) <| x и, к сожалению, не так f <| (g <| x) что эквивалентно x |> g |> f), Я нашел это полезным только тогда, когда вы хотите удалить скобки (вместо f (long expression), ты пишешь f <| long expression).

Выбор между f x, x |> f а также f <| x это в основном вопрос стиля. Там нет абсолютного правила для выбора одного вместо другого. |> Оператор очень популярен, и его стоит использовать.

<| встречается реже, но если вы заглянете в исходники компилятора, вы найдете несколько вариантов использования. Например:

raise <| System.InvalidOperationException (SR.GetString(SR.QillFormedAppOrLet))

if info.precision then
  failwithf "%s" <| FSComp.SR.forFormatDoesntSupportPrecision(ch.ToString())

<| используется для удаления скобок, и я думаю, что это делает код более читабельным при аккуратном использовании. Когда вы видите это, вы знаете, что следующее выражение является аргументом вашей функции. Вам не нужно искать закрывающую скобку. Я предлагаю вам использовать его экономно, и вы должны вообще избегать смешивания <| а также |> в том же выражении, поскольку это может быть очень запутанным.

Мне иногда нравится использовать этот оператор для создания "блока", сfun или же lazy ключевое слово.

let f (l: Lazy<_>) = ()
let g (f: _ -> _ -> _) = ()

f <| lazy
    let x = 1 + 1
    x * x

g <| fun x y ->
    let sqr n = n * n
    sqr x + sqr y

Блок основан на отступе, поэтому он хорошо вписывается в код F#. Благодаря <| Оператор, вам не нужны завершающие скобки.

Как указал здесь Скотт Влашин, оператор обратного канала полезен, если вам нужно передать данные в качестве первого параметра (а не последнего) где-то вдоль цепочки каналов. Учтите следующее:

let replace (replaceThis: string) (withThis: string) (input: string) =
    input.Replace(replaceThis, withThis)

let joinWith (input1: string) (input2: string) =
    input1 + " " + input2

let testString = "Happy"

let amendedString = testString
                    |> replace "H" "Cr"
                    |> joinWith "birthday"

amendedString это "день рождения дерьмовый". Допустим, я хочу, чтобы это был "Сумасшедший день рождения". Я могу добиться этого с помощью оператора обратной трубы:

let amendedString = testString
                    |> replace "H" "Cr"
                    |> joinWith <| "birthday"

Сейчас amendedString это "дерьмовый день рождения", что я и хочу.

Другие вопросы по тегам