jdonaldson / promhx

A promise and functional reactive programming library for Haxe
MIT License
145 stars 24 forks source link

error with mdo.StreamM #55

Closed francescoagati closed 9 years ago

francescoagati commented 9 years ago

Hi,

with this code

   import promhx.mdo.StreamM;
   var s1 = new Stream<Int>();
   var s2 = new Stream<Int>();
   var s3 = StreamM.dO({
         val1 <= s1;
         val2 <= s2;
         ret({val1: val1, val2: val2});
   });
   s3.then(function(x){
      trace(x.val1);
      trace(x.val2);
   });

i get this error

Unknown identifier : ret
jdonaldson commented 9 years ago

Thanks for this, I've fixed it on git and haxelib.

francescoagati commented 9 years ago

Thanks. works now. :-)

francescoagati commented 9 years ago

I have see that the monad stream is updated only when all the streams are resolved. In bacon.js exists combineTemplate that work also only one stream is updated.

This is an example

https://github.com/baconjs/bacon.js#bacon-combinetemplate

var password, username, firstname, lastname; // <- properties or streams
var loginInfo = Bacon.combineTemplate({
    magicNumber: 3,
    userid: username,
    passwd: password,
    name: { first: firstname, last: lastname }})

can be possible implement this with Stream Monads?

jdonaldson commented 9 years ago

You can get close with promhx mdo, I think it should be a nice way of achieving this.

 import promhx.mdo.StreamM;
   var userid = new Stream<Int>();
   var password = new Stream<Int>();
   var firstname = new Stream<String>();
  //[....]
   var s3 = StreamM.dO({
         useridv <= userid;
         passwordv <= password;
         //[...]
         ret({ userid:useridv, passwd:passwordv, name : {first:firstname, [...]})
   });

Note that you'll have to explicitly bind the streams into variables that you can reference in ret. I don't have an autobinding feature right now. It's tricky to know that it's always ok to bind a stream when it is used within the template. I would probably have to use special syntax + parsing. I wouldn't want to do this the way bacon.js does it (runtime variable inspection). That can make things pretty slow, and makes it difficult to extend nicely with other asynchronous approaches.

Another simpler macro method would be to use Stream.whenever:

Stream.whenever(username, password, ...).then(function(user,pass,...){
   return {  user:user, pass:pass, name : {first:fname, last:lname...});
});

That's the technique that I use most often.

francescoagati commented 9 years ago

Thanks @jdonaldson i have try stream.mdo but is triggered when all the streams are executed. I nerd that the trigger is executed also only one of the streams are executed. Whenever can cover this particular use case?

francescoagati commented 9 years ago

@jdonaldson i have some tests with whenever and resolve my problem. Thanks for the support.

jdonaldson commented 9 years ago

Ah, I see what you mean. Does the bacon template approach work like that? I would be surprised.

In the case you give, you want to wait on a number of streams, and trigger when the first stream resolves. I odn't have a great way of dealing with this at present, mainly because of the question of the unresolved streams. Are they null in that case? What happens if you want to resolve a null value? How would you tell the difference?

One alternative would be to do a wait on a large number of streams, and then when any of them resolve trigger a special method that returns the promise instance, as well as the promised value. That way you could check which one actually was resolved. If that sounds useful to you, I'll look into it.

francescoagati commented 9 years ago

bacon template wait until all the streams are resolved the first time. But after that also if only one of the streams is resolved, the stream template trigger a new event.

you can see an example here. http://jsbin.com/nuyazu/1/edit?js,console,output

I have convert stream in property beacuse with property is possible to give an initial value.

jdonaldson commented 9 years ago

It looks like the example treats unresolved instances as empty strings. I think this is problematic for a low level implementation.

There may be an opportunity to extend the notion of a stream with a default value... a value that is defined even before the actual value returns. It would be nice to distinguish between the two in that case though. I'll have to think about it.