这个 F# 运算符 <*> 的典型定义/含义是什么?

3
作为一个相对新手的函数式编程者,我还不熟悉所有标准运算符。许多语言允许它们的定义是任意的,而且这些定义通常无法在附近的源代码中找到,如果有的话,这使得阅读函数式代码变得不必要地具有挑战性。
目前,我不知道在WebSharper.UI.Next文档中出现的<*>是什么意思。
如果有一个地方列出各种函数式语言中各种运算符的传统定义,那就太好了。

在使用 F# Power Tools 的 VS 2015 中,您可以右键单击一个不熟悉的运算符并选择“转到定义”。这可能不会显示源代码,但它将显示类型签名和任何文档注释。以前不能对运算符执行此操作,但我不确定是 VS 2015 还是 F# Power Tools 添加了此功能。 - Joel Mueller
2个回答

7

我同意您的观点,有一个列出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中使用的方法。


1

刚刚在文档的其他部分发现了以下内容...

    let ( <*> ) f x = View.Apply f x

View.Apply 的类型,因此 ( <*> ) 的类型是:

    View<'A * 'B> -> View<'A> -> View<'B>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接