Skip to content
This repository has been archived by the owner on Mar 28, 2023. It is now read-only.

Seems like the implementation of the ap is incorrect #42

Closed
ivan-demchenko opened this issue Oct 27, 2017 · 3 comments
Closed

Seems like the implementation of the ap is incorrect #42

ivan-demchenko opened this issue Oct 27, 2017 · 3 comments

Comments

@ivan-demchenko
Copy link

Hello!

I was playing around with the Task type and I have discovered that there's something wrong with the implementation of ap. Here is my snippet:

var Task = require('data.task');

var readToTask = (delay, resData) => new Task((rej, res) => isNaN(delay) ? res(resData) : setTimeout(res, delay, resData));

var lift2 = (f, m1, m2) => m1.ap(m2.map(f));

var join = s1 => s2 => s1 + ' : ' + s2;

var program = () =>
    lift2(join, readToTask(1000, 'm1'), readToTask(NaN, 'm2'))

var program2 = () =>
    readToTask(1000, 'm1').chain(p1 =>
        readToTask(NaN, 'm2').map(p2 =>
            join(p1)(p2)
        )
    )

var program3 = () =>
    readToTask(1000, 'm1').ap(readToTask(NaN, 'm2').map(join))

program().fork(console.error, console.log); // func is not a function
program2().fork(console.error, console.log); // works
program3().fork(console.error, console.log); // func is not a function

It could be that I am doing something wrong since there was a major release. I can't check it with 2.x versions as npm can't find any. Unfortunately, I haven't had a chance to dig into the implementation.

@robotlolita
Copy link
Member

Ah, I can see why this would be confusing.

Fantasy Land 0.x had the interface:

interface Applicative<F>
  <A, B> ap(this: F<A => B>, F<A>): F<B>

So you'd write it using:

Task.of(a => b => a + ' : ' + b).ap(Task.of('x')).ap(Task.of('y'));

data.task only implements this interface, which was the only one at the time.

Later in the 0.x branch, Fantasy Land changed the type of the Applicative interface like this:

interface Applicative<F>
  <A, B> ap(this: F<A>, F<A => B>): F<B>  

Which gives you:

Task.of('x').ap(Task.of('y').ap(f))

This was a breaking change, but then Fantasy Land 1.x was released with prefixed names:

interface Applicative<F>
  <A, B> "fantasy-land/ap"(this: F<A>, F<A => B>): F<B>

The new Folktale Task implements both, so you have:

Task.ap :: <A, B>(this: Task<A => B>, Task<A>): Task<B>
Task['fantasy-land/ap'] :: <A, B>(this: Task<A>, Task<A => B>): Task<B>

This article describes how to migrate from data.task to the new folktale library http://folktale.origamitower.com/docs/v2.0.0/migrating/from-data.task/

@ivan-demchenko
Copy link
Author

thank you @robotlolita I'll definitely give it a try!

@ivan-demchenko
Copy link
Author

Well, I ended up using ramda's lift as it uses prefixed names. It works rather good! Thank you!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants