了解幻想世界`ap`

Understanding Fantasyland `ap`

我正在努力理解 ap,但遇到了麻烦。

fantasyland 中,James Forbes 说:

First we teach a function how to interact with our type, by storing that function in a container just like any other value. ( Functions are values too ya know! )

var square = Type.of(
    a => a * a
)

//=> Type (number -> number)

Then we can apply that contained function to a contained value.

square.ap( Type.of(3) )

//=> Type(9)

ap calls map on a received type, with itself as the transform function.

function ap(type){
  // recall our value
  // is a function
  // Type ( a -> a )
  var transformer = this.__value

  return type.map(transformer)
}

所以这看起来像 ap 只有当我们容器中的值是一个函数时才有效。这对我来说已经感觉很奇怪了,因为我认为 The Perfect API 的全部意义在于这些功能每次都适用于所有内容。

我还想注意,因为行 square.ap(Type.of(3) ),在我看来 ap 接受任何仿函数(map 的实现者)。

现在,如果我跳转到 javascript fantasy-land spec,我假设它基于 James Forbes link,ap 签名的 1.i 定义(a.ap(b)) 状态

If b does not represent a function, the behaviour of ap is unspecified.

所以听起来这个规范期望 ap 采取不同于完美 API 的功能。

总而言之,我想我不了解 ap 的规范或实现它的样子。当我尝试用谷歌搜索这个时,似乎大多数人只想谈论 map,这对我来说已经很容易理解了。

FantasyLand 规范比 James Forbes 的文章早三年,由 Brian McKenna 创建,因此 James Forbes 的文章似乎是基于规范,而不是相反。

要回答您的问题,ab 必须是同一种 "container"。如果 a 是一个 Maybe,那么 b 也必须是一个 Maybe。如果 a 是一个任务,那么 b 也必须是一个任务。

这在 FantasyLand 规范中有说明:

b must be same Apply as a.

此外,其中之一必须包含一个函数作为其内部值。哪一个需要包含函数取决于API。在 FantasyLand 规范中,b 将包含函数:

b must be an Apply of a function

在 James Forbes 的文章中,情况恰恰相反。我怀疑这是因为他的文章是围绕 Ramda 展开的,Ramda 的论证顺序与您通常在 JavaScript.

中看到的顺序相反

在任何情况下,ap 的结果都是与 ab 具有相同容器类型的值:

The Apply returned by ap must be the same as a and b

并且结果包含将包含的函数应用于另一个包含的值的结果。

所以如果 a 是某个值 T[x] 并且 b 是某个值 T[f],那么 a.ap(b) 将是 T[f(x)].

希望这是有道理的。