Поиск…


Как составлять значения и функции с помощью общих операторов

В объектно-ориентированном программировании общей задачей является создание объектов (значений). В функциональном программировании также является общей задачей создавать значения, а также функции.

Мы привыкли составлять ценности из нашего опыта других языков программирования, используя такие операторы, как + , - , * , / и т. Д.

Составляющая стоимости

let x = 1 + 2 + 3 * 2

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

Состав функции

// val f : int -> int
let f v   = v + 1
// val g : int -> int
let g v   = v * 2

// Different ways to compose f and g
// val h : int -> int
let h1 v  = g (f v)
let h2 v  = v |> f |> g   // Forward piping of 'v'
let h3 v  = g <| (f <| v) // Reverse piping of 'v' (because <| has left associcativity we need ())
let h4    = f >> g        // Forward functional composition
let h5    = g << f        // Reverse functional composition (closer to math notation of 'g o f')

В F# прямой трубопровод является предпочтительным по сравнению с обратным трубопроводом, потому что:

  1. Вывод типа (обычно) перемещается слева направо, так что естественно, что значения и функции также текут слева направо
  2. Потому что <| и << должны иметь правую ассоциативность, но в F# они остаются ассоциативными, что заставляет нас вставлять ()
  3. Смешивание прямого и обратного трубопроводов обычно не работает, поскольку они имеют одинаковый приоритет.

Композиция Монады

Поскольку Monads (например, Option<'T> или List<'T> ) обычно используются в функциональном программировании, также существуют обычные, но менее известные операторы для компоновки функций, работающих с Monads, таких как >>= , >=> , <|> и <*> .

let (>>=) t uf  = Option.bind uf t
let (>=>) tf uf = fun v -> tf v >>= uf
// val oinc   : int -> int option
let oinc   v    = Some (v + 1)    // Increment v
// val ofloat : int -> float option
let ofloat v    = Some (float v)  // Map v to float

// Different ways to compose functions working with Option Monad
// val m : int option -> float option
let m1 v  = Option.bind (fun v -> Some (float (v + 1))) v
let m2 v  = v |> Option.bind oinc |> Option.bind ofloat
let m3 v  = v >>= oinc >>= ofloat
let m4    = oinc >=> ofloat

// Other common operators are <|> (orElse) and <*> (andAlso)

// If 't' has Some value then return t otherwise return u
let (<|>) t u =
  match t with
  | Some _  -> t
  | None    -> u

// If 't' and 'u' has Some values then return Some (tv*uv) otherwise return None
let (<*>) t u =
  match t, u with
  | Some tv, Some tu  -> Some (tv, tu)
  | _                 -> None

// val pickOne : 'a option -> 'a option -> 'a option
let pickOne t u v = t <|> u <|> v

// val combine : 'a option -> 'b option  -> 'c option -> (('a*'b)*'c) option
let combine t u v = t <*> u <*> v

Заключение

Для новых функциональных программистов состав функций с использованием операторов может казаться непрозрачным и неясным, но это потому, что смысл этих операторов не так широко известен как операторы, работающие над значениями. Однако при некоторой тренировке с использованием |> , >> , >>= и >=> становится таким же естественным, как использование + , - , * и / .

Latebinding в F # с использованием? оператор

На статически типизированном языке, таком как F# мы работаем с типами, хорошо известными во время компиляции. Мы потребляем внешние источники данных безопасным типом, используя поставщиков типов.

Тем не менее, иногда необходимо использовать позднюю привязку (например, dynamic на C# ). Например, при работе с документами JSON , у которых нет четко определенной схемы.

Чтобы упростить работу с поздним связыванием, F# обеспечивает поддержку операторов динамического поиска ? и ?<- .

Пример:

// (?) allows us to lookup values in a map like this: map?MyKey
let inline (?)   m k   = Map.tryFind k m
// (?<-) allows us to update values in a map like this: map?MyKey <- 123
let inline (?<-) m k v = Map.add k v m

let getAndUpdate (map : Map<string, int>) : int option*Map<string, int> =
  let i = map?Hello       // Equivalent to map |> Map.tryFind "Hello"
  let m = map?Hello <- 3  // Equivalent to map |> Map.add "Hello" 3
  i, m

Оказывается, поддержка F# для позднего связывания проста, но гибкая.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow