I'm trying to come to an understand of ap, but having trouble.
In fantasyland, James Forbes says:
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)
apcallsmapon 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)
}
So this looks like ap only works if the value in our container is a function. This already feels weird to me because I thought the the whole point of The Perfect API was that these functions work on everything every time.
I also want to take note than because of the line square.ap(Type.of(3) ), it looks to me like ap takes any functor (implementer of map).
Now if I jump over to the javascript fantasy-land spec, which I assume is based on the James Forbes link, the 1.i definition of the ap signature (a.ap(b)) states
If
bdoes not represent a function, the behaviour ofapis unspecified.
So it sounds like this spec is expecting ap to take a function unlike The Perfect API.
In summary, I guess I don't understand specifications for ap or what implementing it would look like. When I try googling this, it seems like most people just want to talk about map, which is easy for me to understand already.
                        
The FantasyLand spec pre-dates James Forbes' article by three years, and was created by Brian McKenna, so it would seem that James Forbes' article is based on the spec, not the other way around.
To answer your question,
aandbmust both be the same kind of "container". Ifais a Maybe, then b must also be a Maybe. Ifais a Task, thenbmust also be a Task.This is indicated here in the FantasyLand spec:
Additionally, one of them must contain a function as its inner value. Which one needs to contain a function depends on the API. In the FantasyLand spec, it's
bthat would contain the function:In James Forbes' article, it's the opposite. I suspect this is because he's basing his article around Ramda, which takes arguments in the opposite order of what you would typically see elsewhere in JavaScript.
In any case, the result of
apis a value with the same type of container asaandb:and the result contains the result of applying the contained function to the other contained value.
So if
awere some value T[x] andbwere some value T[f], thena.ap(b)would beT[f(x)].Hopefully that makes some sense.