Что эти функции F # должны делать? - PullRequest
1 голос
/ 31 мая 2019

Изучая F # в эти дни, я заметил, что в некоторых библиотеках, таких как эта или , что одна , есть некоторые похожие функции, которые кажутся распространенными в F #, но не могутдействительно расшифровать их, что они делают, для чего они?

let ap x f =
    match f, x with
    | Ok f        , Ok x    -> Ok (f x)
    | Error e     , _       -> Error e
    | _           , Error e -> Error e
let inline (<*>) f x = ap x f
let inline (<!>) f x = Result.map f x
let inline lift2 f a b = f <!> a <*> b

Даже агрегирование комментариев с ними не очень помогает в моем понимании:

/// Sequential application
/// If the wrapped function is a success and the given result is a success the function is applied on the value. 
/// Otherwise the exisiting error messages are propagated.
let ap x f =
match f,x with
    | Ok f        , Ok x    -> Ok (f x)
    | Error e     , _       -> Error e
    | _           , Error e -> Error e

/// Sequential application
/// If the wrapped function is a success and the given result is a success the function is applied on the value. 
/// Otherwise the exisiting error messages are propagated.
let inline (<*>) f x = ap x f

/// Infix map, lifts a function into a Result and applies it on the given result.
let inline (<!>) f x = Result.map f x

/// Promote a function to a monad/applicative, scanning the monadic/applicative arguments from left to right.
let inline lift2 f a b = f <!> a <*> b

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

Если есть кто-то, кто мог бы намекнуть о том, насколько полезны эти функции, я был бы очень признателен.

Ответы [ 2 ]

5 голосов
/ 31 мая 2019

Они называются «аппликативными функторами» (иногда просто «аппликативными»). Их цель - объединить данные из нескольких Something<'T> с помощью функции. По сути, «поднятие» функции типа 'Arg1 -> 'Arg2 -> ... -> 'Result в функцию типа Something<'Arg1> -> Something<'Arg2> -> ... -> Something<'Result>.

Например, учитывая стандартный тип результата:

type Result<'T, 'Err> = Ok of 'T | Error of 'Err

у вас может быть несколько значений Result, которые вы хотите объединить вместе. Например, скажем, у вас есть форма с вводами firstName, lastName и age. У вас также есть тип результата Person:

type Person = { firstName: string; lastName: string; age: int }

// string -> string -> int -> Person
let makePerson firstName lastName age =
    { firstName = firstName; lastName = lastName; age = age }

Значения, приходящие из вашей фактической формы, могут иметь тип Result<string, InputError> или Result<int, InputError>, который может быть Error, например, если. пользователь не ввел значение.

type InputError =
    | FieldMissing of fieldName: string
    // Other error cases...

Вы хотите объединить их в Result<Person, InputError>, что равно Ok, если все входные данные Ok, или Error, если какой-либо вход Error. Используя аппликатив, вы можете сделать это так:

// Result<string, InputError> -> Result<string, InputError> -> Result<int, InputError> -> Result<Person, InputError>
let makePersonResult firstName lastName age =
    makePerson <!> firstName <*> lastName <*> age

// Example uses:

makePersonResult (Ok "John") (Ok "Doe") (Ok 42)
// --> Ok { firstName = "John"; lastName = "Doe"; age = 42 }
makePersonResult (Error (FieldMissing "firstName")) (Ok "Doe") (Ok 42)
// --> Error (FieldMissing "firstName")

Подобная концепция может быть применена ко многим другим типам, кроме Result, поэтому ей было дано имя. Например, аппликатив в Async<'T> может запустить все асинхронные аргументы параллельно, а когда они будут закончены, объединить их результаты в Async<'Result>. Другой пример, аппликатив для 'T list будет эквивалентен стандартной библиотеке List.map2 или List.map3, но может быть обобщен на любое количество списков аргументов.

Примечание: если вы ищите «аппликативный функтор», большинство результатов, которые вы найдете, будет в Haskell, где вместо оператора оператора карты, обычно пишется <!> в F #, <$>.

5 голосов
/ 31 мая 2019

Скотта Влашина F # для развлечения и прибыли (https://fsharpforfunandprofit.com) имеет серию Карта и привязка и применение, о мой! (https://fsharpforfunandprofit.com/posts/elevated-world-7), который долженбыть в состоянии пролить свет на этот вопрос. Относительно вашего конкретного вопроса:

  • <!> - это оператор map, который применяет функцию f и параметр x к элементам данных.структура, которую вы отображаете, или, другими словами, поднимает функцию в область структуры данных, в данном случае тип Result.
  • <*> - это оператор ap (применить), которыйраспаковывает функцию, заключенную в повышенное значение, в поднятую функцию.
  • lift2 - это в основном оператор map для двухпараметрической функции.

Пожалуйста, посмотрите наблог, это действительно помогает!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...