DrBoolean / freeky

Free monad Collection
MIT License
176 stars 15 forks source link

Dispatches to `ap` method of monad if available #3

Closed rjmk closed 8 years ago

rjmk commented 8 years ago

I don't know if you would prefer to also have chain rewritten to dispatch when available?

paparga commented 8 years ago

I test it, but it doesn't seem to work (fixing a small typo).

return this.x.ap ? this.x.ap(a) : this.chain(f => a.map(f))

And changing package.json to: "data.task": "safareli/data.task.git#patch-1"

My code:

const {Free, liftF} = require("./free")
const Task = require("data.task")
const daggy = require("daggy")

const Shout = daggy.tagged("text", "ms")

const shout = (text, ms) => liftF(Shout(text, ms))

const par3 = x => y => z => [x, y, z]

const app = shout("Last", 1000).map(par3).ap(shout("Second", 500)).ap(shout("First", 100))

const shoutToTask = ({text, ms}) => new Task((rej, res) => {
  setTimeout(()=>{
    console.log(text + "!!!!")
    res("ok")
  },ms)
})

console.log("----- Using Free -----");

app.foldMap(shoutToTask, Task.of).fork(console.log,console.log)

// Now using Task directly

const shout2 = (text, ms) => new Task((rej, res) => {
  setTimeout(()=>{
    console.log(text + "!!!!")
    res("ok")
  },ms)
})

const app2 = shout2("Last", 1000).map(par3).ap(shout2("Second", 500)).ap(shout2("First", 100))

setTimeout(()=>{
  console.log("")
  console.log("----- Using Task directly-----")
  app2.fork(console.log,console.log)
}, 2500)

And this is the output: image

DrBoolean commented 8 years ago

Shoot yeah, I wasn't thinking earlier. this in the context of that method was Free itself - not the containing value.

I think the implementation is just:

Free.prototype.ap = function(a) {
  return this.cata({
    Impure: (x, g) => Impure(x, y => g(y).ap(a)),
    Pure: f => a.map(f)
  })
}

However, this doesn't quite work.

I think the order we're witnessing is due to the nature of Free Monads being run all the way through first, then interpreted later. We might have to use Free Applicatives here...I have to research a bit.

DrBoolean commented 8 years ago

I should say, it does "work", but the order is backwards as you've noticed.

rjmk commented 8 years ago

I think this is the specific monad. But yeah, the issue (I think) is here, where when foldMapping chain is called, so in the interpreting. I don't know whether it would also be possible to expose an interface for interpreting with aps

safareli commented 8 years ago

Here is Free Applicative from fantasy-free if that's helpfull.

safareli commented 8 years ago

@DrBoolean if you have some good resources about this topic it will be nice if you add it to README

rjmk commented 8 years ago

Superceded by #5

safareli commented 8 years ago

Hi guys I have ported free-concurrent written by @srijs which is combination of free applicative functor and free monad. with this implementation test case provided by @paparga works properly.

DrBoolean commented 8 years ago

Perfect!

paparga commented 8 years ago

Great!

safareli commented 8 years ago

Could you guys check if my test case for checking concurrency is correct?

rjmk commented 8 years ago

Looks good to me, @safareli

safareli commented 8 years ago

Thanks!

safareli commented 8 years ago

As it turns out when structure is monad applicative instance should behave as if it's derived from monad, so making free concurrent when ap is used is not lawful.

I was thinking on that issue and camte to this and I would love to hear your thoughts.