学习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
Run Code Online (Sandbox Code Playgroud)
即使与他们汇总评论对我的理解也无济于事:
/// 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
Run Code Online (Sandbox Code Playgroud)
我什至没有看到如何使用它们的示例,也不确定为什么inline使用它们。
如果有人可以暗示这些功能的实用性,我将不胜感激。
斯科特·沃斯钦(Scott Wlaschin)的F#(寓教于乐)(https://fsharpforfunandprofit.com)提供了一系列地图和绑定并应用,噢,我的天!(https://fsharpforfunandprofit.com/posts/elevated-world-7),它应该能够对此有所启发。关于您的特定问题:
<!>是将map函数f和参数应用于x要映射的数据结构的元素的运算符,换句话说,就是将函数提升到数据结构的领域(在这种情况下为Result类型)。<*>是ap(应用)运算符,用于将包装在升高值内的函数解压缩为提升函数。lift2基本上map是两参数函数的运算符。请看一下博客,它确实有帮助!
这些被称为“应用函子”(有时也称为“应用函子”)。它们的目的是Something<'T>使用一个函数合并多个数据。基本上,将类型'Arg1 -> 'Arg2 -> ... -> 'Result的功能“提升”为类型的功能Something<'Arg1> -> Something<'Arg2> -> ... -> Something<'Result>。
例如,给定标准的Result类型:
type Result<'T, 'Err> = Ok of 'T | Error of 'Err
Run Code Online (Sandbox Code Playgroud)
您可能有几个要组合在一起的结果值。例如,假设您有一个带有输入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 }
Run Code Online (Sandbox Code Playgroud)
来自您实际形式的值可能具有类型Result<string, InputError>或Result<int, InputError>,Error例如。用户尚未输入值。
type InputError =
| FieldMissing of fieldName: string
// Other error cases...
Run Code Online (Sandbox Code Playgroud)
您想将它们组合成一个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")
Run Code Online (Sandbox Code Playgroud)
除了Result之外,类似的概念还可以应用于许多其他类型,这就是为什么要为其指定名称的原因。例如,一个on的应用程序Async<'T>可以并行运行所有参数Asyncs,并在完成后将其结果合并为Async<'Result>。另一个例子是,applicative 'T list等同于标准库List.map2,List.map3但可以泛化为任意数量的参数列表。
旁注:如果您查找“应用函子”,您将找到的大多数结果将在Haskell中,在该处通常<!>使用F#编写的map运算符被<$>代替。
| 归档时间: |
|
| 查看次数: |
114 次 |
| 最近记录: |