Зачем использовать оператор обратной трубы вместо цепочки функций?
Зачем использовать оператор обратной трубы вместо цепочки функций?
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
Ответы
Ответ 1
Из-за левой ассоциативности (f <| g <| x
анализируется как (f <| g) <| x
и, к сожалению, не как f <| (g <| x)
, что эквивалентно x |> g |> f
), я нашел его полезным только тогда, когда вы хотите удалить круглые скобки (вместо f (long expression)
, вы пишете f <| long expression
).
Ответ 2
Выбор между 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 #. благодаря
к оператору <|
, вам не нужна скользящая скобка.
Ответ 3
Как отметил Скотт Влащин, здесь, оператор обратной трубы полезен, если вам нужно передать данные в качестве первого параметра (а не последний) где-то вдоль цепочки труб. Рассмотрим следующее:
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
- это день рождения Crappy. Скажем, я хочу, чтобы это было "Crappy birthday". Я могу добиться этого, используя оператор обратной трубы:
let amendedString = testString
|> replace "H" "Cr"
|> joinWith <| "birthday"
Теперь amendedString
- это "Crappy birthday", который я хочу.