我同意您的观点,有一个列出F#中使用的所有隐式运算符约定的地方会很好。
<*>
运算符来自 Haskell,它是应用函子的运算符,其一般签名为:Applicative'<('A -> 'B)> -> Applicative'<'A> -> Applicative'<'B>
,这在 .NET 中是非法的,因为高阶类型不受支持。
无论如何,没有什么可以阻止您为特定的应用函子定义运算符,以下是选项类型的典型定义:
let (<*>) f x =
match (f, x) with
| Some f, Some x -> Some (f x)
| _ -> None
这里类型被推断为:
val ( <*> ) : f:('a -> 'b) option -> x:'a option -> 'b option
这相当于:
val ( <*> ) : f: option<('a -> 'b)> -> x: option<'a> -> option<'b>
直观的解释是它需要一个上下文中的函数和该函数在上下文中的参数,然后在上下文中执行该函数。
在我们的选项类型示例中,它可用于将函数应用于可能返回
None
值的操作的结果值:
let tryParse x =
match System.Int32.TryParse "100" with
| (true, x) -> Some x
| _ -> None
Some ((+) 10) <*> tryParse "100"
您可以利用柯里化并编写以下代码:
Some (+) <*> tryParse "100" <*> Some 10
这代表类似于:
(+) (System.Int32.Parse "100") 10
但是不会抛出异常,这就是为什么被称为Applicatives用于模拟副作用,特别是在像Haskell这样的纯函数式语言中。这里是另一个选项应用的示例。
但对于不同类型,它具有不同的用途,例如对于列表,它可以用来将它们合并,如此帖子所示。
在F#中没有定义它,因为.NET类型系统无法以通用方式定义它,但可以使用重载和静态成员约束,如FsControl中所示,否则您将不得不手动选择不同的实例,这是FSharpx中使用的方法。