Monads in javascript

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Monads in javascript

Martin Drautzburg
Hello all,

I found some implementations of Monads in javascript, but they all do not
allow capturing the intermediate results. My question is: "what is the
ultimate cause for this"?

In haskell the second argument to (>>=) is a function a->Mb which can be
written as a lambda expression, e.g.
        \x->[x].
In javascript such a function would be written as
        function(x) {return[x]}.

Did I get this right: in haskell the chain of >>= is constructed from the end?
So chaining a->Mb and b->Mc gives you a->Mc, which is again suitable as a
second argument to (>>=), right?

So why can't I do this is javascipt? Or can I?

The reason I am asking this is because I am trying to beautify callbacks. An
asynchronous ajax call needs a function argument, which will be executed once
the call completes. But what if I want to take the results of the first call,
do something with them and pass it to a second ajax call, where I would again
have to pass another function argument. I would end up with a deeply nested
structure of lambdas, something like

f(a,b,...function(...){
        ...
        g(... function(...)

I had some hopes that chaining functions monad-style would ease my pain. I
might be on the wrong track though, feel free to tell me so.

--
Martin

--
Martin


Reply | Threaded
Open this post in threaded view
|

Monads in javascript

Ertugrul Söylemez
Martin Drautzburg <Martin.Drautzburg at web.de> wrote:

> I found some implementations of Monads in javascript, but they all do
> not allow capturing the intermediate results. My question is: "what is
> the ultimate cause for this"?
>
> In haskell the second argument to (>>=) is a function a->Mb which can
> be written as a lambda expression, e.g.
>         \x->[x].
> In javascript such a function would be written as
>         function(x) {return[x]}.
>
> Did I get this right: in haskell the chain of >>= is constructed from
> the end?

Composition by (>>=) is by definition associative, so it really doesn't
matter how you set your parentheses.


> So chaining a->Mb and b->Mc gives you a->Mc, which is again suitable
> as a second argument to (>>=), right?

Yes, but beware that you may be confusing (>>=) with (>=>).


> So why can't I do this is javascipt? Or can I?

I don't see why that should be a problem.  Note that there are many
different ways to represent monads.  Haskell represents them in terms of
'fmap', 'return' and (>>=).


> The reason I am asking this is because I am trying to beautify
> callbacks. An asynchronous ajax call needs a function argument, which
> will be executed once the call completes. But what if I want to take
> the results of the first call, do something with them and pass it to a
> second ajax call, where I would again have to pass another function
> argument. I would end up with a deeply nested structure of lambdas,
> something like
>
> f(a,b,...function(...){
>         ...
>         g(... function(...)
>
> I had some hopes that chaining functions monad-style would ease my
> pain. I might be on the wrong track though, feel free to tell me so.

You probably are, because the usefulness of monads depends a good deal
on syntax.  ECMA-based languages like JavaScript, ActionScript, Haxe,
etc. have a terrible syntax for anonymous functions.

To give you an alternative, this really sounds like you're looking for a
continuation-based solution.  Continuation passing style could really
solve your problem elegantly even in JavaScript.


Greets,
Ertugrul


--
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://ertes.de/




Reply | Threaded
Open this post in threaded view
|

Monads in javascript

Martin Drautzburg
On Wednesday, 13. July 2011 00:03:44 Ertugrul Soeylemez wrote:

> > I had some hopes that chaining functions monad-style would ease my
> > pain. I might be on the wrong track though, feel free to tell me so.
>
> You probably are, because the usefulness of monads depends a good deal
> on syntax.  ECMA-based languages like JavaScript, ActionScript, Haxe,
> etc. have a terrible syntax for anonymous functions.
>
> To give you an alternative, this really sounds like you're looking for a
> continuation-based solution.  Continuation passing style could really
> solve your problem elegantly even in JavaScript.

Right. It did.

It sometimes doens't work to define the callback *after* the function which
needs the callback. It is not always easy to find out *when* things need to be
defined in javascript. Luckily in Haskell there is no "when".

Still in most cases it works and the code looks like regular procedural code,
where control flows from top to bottom. And I could nicely write code where
the callback makes another callback etc.

Thanks.

--
Martin


Reply | Threaded
Open this post in threaded view
|

Monads in javascript

Mats Rauhala
On 23:18 Wed 13 Jul     , Martin Drautzburg wrote:

> Right. It did.
>
> It sometimes doens't work to define the callback *after* the function which
> needs the callback. It is not always easy to find out *when* things need to be
> defined in javascript. Luckily in Haskell there is no "when".
>
> Still in most cases it works and the code looks like regular procedural code,
> where control flows from top to bottom. And I could nicely write code where
> the callback makes another callback etc.
>
> Thanks.

Could you give an example how CPS helped your situation? I'm trying to
grok continuation passing style, but for now it just seems to complicate
and/or slow down code (stack)

--
Mats Rauhala
MasseR
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://www.haskell.org/pipermail/beginners/attachments/20110714/957b771c/attachment.pgp>

Reply | Threaded
Open this post in threaded view
|

Monads in javascript

Thomas Davie

On 14 Jul 2011, at 09:03, Mats Rauhala wrote:
> Could you give an example how CPS helped your situation? I'm trying to
> grok continuation passing style, but for now it just seems to complicate
> and/or slow down code (stack)

This obviously isn't Martin's example, but hopefully this should help.

In a 3D game engine, the norm (in procedural land at least) is to have calls like someInWorldObject.animate(someAnimation).  If you want to run that animation, and then another, the norm is to set a timer to fire when the animation is complete and to call another call like that.  My engine by comparison uses CPS ? whenever you ask the engine to run an animation of some kind you must specify either a) that it repeats indefinitely, or b) has a continuation to deal with what happens after that animation is complete.  The result is that calling code doesn't have random timers floating around, and can define what happens at the completion of an animation in a closure, inline with creating that animation.

Apple's CoreAnimation also uses continuation passing style for a similar purpose.

Both of these examples use CPS because it allows things to happen asynchronously ? an animation can disappear off and run, and then something come back to you once it's finished.  I have also found CPS can clean up synchronous code too.  Take a look at CPBrainfuck on hackage ? I personally think it's one of the cleaner implementations of BF out there, though I will freely admit it's not the fastest.

Thanks

Tom Davie

Reply | Threaded
Open this post in threaded view
|

Monads in javascript

Ertugrul Söylemez
In reply to this post by Mats Rauhala
Mats Rauhala <mats.rauhala at gmail.com> wrote:

> I'm trying to grok continuation passing style, but for now it just
> seems to complicate and/or slow down code (stack)

In general CPS will even improve efficiency, in some cases
asymptotically [1,2,3], but that's not their main point.  Delimited
continuations are the mother of all control constructs, so you can
implement many kinds of control flow like concurrency (coroutines),
resumable exceptions (or basic exceptions for that matter), forks and
reunions, etc.

Many Haskell abstractions make use of them; iteratees to name one, on
which I rely heavily.  Also most of the libraries I upload to Hackage
use continuations a lot.

For a web application continuations help a lot with some of the
difficulties of the stateless HTTP, for example form processing and
session management.  Along with every link goes a continuation, which is
the logical future of the computation.  This enables you to write your
web application almost totally disregarding the statelessness, like your
application would talk to a local user on a terminal.  The user session
becomes a coroutine of the web server.

[1] http://www.iai.uni-bonn.de/~jv/mpc08.pdf
[2] http://hackage.haskell.org/package/monad-ran
[3] http://comonad.com/reader/2011/free-monads-for-less/


Greets,
Ertugrul


--
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://ertes.de/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://www.haskell.org/pipermail/beginners/attachments/20110714/b4333c92/attachment.pgp>

Reply | Threaded
Open this post in threaded view
|

Monads in javascript

Tony Morris-4

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 14/07/11 19:01, Ertugrul Soeylemez wrote:
> Also most of the libraries I upload to Hackage use continuations a
> lot.
Do you have a few examples?

- --
Tony Morris
http://tmorris.net/

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk4etLwACgkQmnpgrYe6r60BfgCeMHNVU+xZfZjqQmmbyFs0Ep0V
0sIAn1ssPQXqeVakyTU3xC2xynuOg9jg
=mLjy
-----END PGP SIGNATURE-----



Reply | Threaded
Open this post in threaded view
|

Monads in javascript

Ertugrul Söylemez
-----BEGIN PGP SIGNED MESSAGE-----
Hash: RIPEMD160

Tony Morris <tonymorris at gmail.com> wrote:

> > Also most of the libraries I upload to Hackage use continuations a
> > lot.
>
> Do you have a few examples?

The contstuff library is probably the most important example here.  It
is an advanced monad transformer library with many features not found in
other libraries like mtl or monadLib.  But it takes some time to get
used to the CPS-iness and the slightly different semantics following it.

Other examples are ihttp, ismtp and netlines, which use contstuff and
the enumerator library, both CPS-heavy libraries.  Unlike other
libraries I regard the iteratee interface as a feature, not as an
implementation detail which should be hidden.

And for the sake of completeness the dnscache library is a caching DNS
resolver library, which also uses contstuff and provides a StateT
interface for those, who don't like IO-global state.


Greets,
Ertugrul


- --
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://ertes.de/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)

iQIcBAEBAwAGBQJOHrweAAoJENVqN/rl3Y0RJakQALVeXbTFBFwp3nUbHVfFM4lb
y0sp8LMoAh/lXz5dziJ1UScLOVorztz0c1ppmMlITDjp3eSkc4RryqKdovhOJJUt
9oGVY/rQklr/sMZlIOGTQIEU2fl0nmZpP3gkKGV4bSBfPozN8F6r5o2OgRW412rq
cHOCTVK+5HxNGtBN46cntV8sByln1xhfAYma3l65FGJlsN9FNBC4vxzJO1nfAHwy
75Ml8XLLD1cqcCr43gP7yJmZ6NZvqKjikzptn8QIxKnXgVqMnL0lKqTKSPMHgZPs
iWVLhj2BEXxqNmxL8Xzqf6XCsBtBrJsQupOdUAUkH630iyMB34zoVosRyIbjBF18
S7gF2QcxiqxDpbpzqjSJcMffcsAGeBPVdymEEtd8dJEMuuW1D7+tsRC3gm/aYZJ1
TV+yAxyok+f0jZ08y9yTjiMatSNXzNON/NQz7ORMX7jmi2UvFrlNB9OffA424g9a
392SNxfhfhBKmdh3J91EK8feXozbtvSP2t+0rt/Ie5Lj6OrgCg4kQ5gu7nGYvlJ7
0h01hKBeBtg1J74RKesR+5EP6rSbqifLPSHXmpT5V5zB5C3++5UyVWKYipCFeNmW
fP+HrdyzmXiRkPWMSdI9GQisYjKbeFBnLgK77n4FOcpyBoJAPp/8iplEj8J1zb6v
K1hYqIelbzwAmy7OrHOf
=A9sn
-----END PGP SIGNATURE-----

Reply | Threaded
Open this post in threaded view
|

Monads in javascript

Martin Drautzburg
In reply to this post by Mats Rauhala
On Thursday, 14. July 2011 10:03:23 Mats Rauhala wrote:
> Could you give an example how CPS helped your situation? I'm trying to
> grok continuation passing style, but for now it just seems to complicate
> and/or slow down code (stack)

Well it turned out my problem was entirely syntax. If had  understood, that an
ajax call basically looks like this:

// make two successive ajax calls
callAsync (remoteFunction1, ["arguments"], function(ret,exc) {
        //do something with ret and exc
        var x = ret[1]
        callAsync(remoteFunction2, [x], function(ret,exc) {
                // do something else
}}

You make a remote call and specify what shall happen when the call returns by
providing an anonymous callback function. The callAsync itself immediately
returns.

My only problem was the ugly nesting when I want to place multiple ajax calls
which need to be executed in a precise order as in the example above. I cannot
simply make the first call and return to make the second call. I would have no
idea where exceution would commence after the return.

That chain of function calls builds its own little world and you never
"return" from this world. This reminded me of haskell Monads which can also
create their own little worlds, where e.g. state is passed around . This is
why I asked here. But it turned out it had little to do with Monads. Still it
is a functional issue.

I believe the code above is already CPS, but very ugly. For some reason I
hadn't seen, that there is no need to define the callbacks inline, but I might
as well assign them to a variables. Then the above code looks like:

callAsync (remoteFunction1, ["arguments"], callback1);

var callback1 = function(ret,exc) {
        //do something with ret and exc
        var x = ret[1]
        callAsync(remoteFunction2, [x], callback2)
}

var callback2 = function(ret,exc) {
                // do something else
}

This is more gentle to my eyes.

The only difficulty is that callback1 and callback2 need to be defined at the
time callAsync is called. Usually this is the case. I could of course reverse
the order, which would make things safer, but then control will flow bottom-
up, whereas all the regular code executes top-down.




--
Martin


Reply | Threaded
Open this post in threaded view
|

Monads in javascript

Martin Drautzburg
Back to the question "why can't I get the intermediate results"

In Haskell I can do things like

f::Int->[Int]
f x = [x+1]

z :: [Int]
z = do
  y1 <- [1,2,3]
  y2 <- f y1
  return (y1*y2)

i.e. I can access an intermediate result y1 and the end of the chain. When I
write this without do notation I get

z' = [1,2,3] >>= \y1->[y1+1] >>= \y2->return (y1*y2)

which of course works just as well. However I must not put parentheses around
the lambdas:

z' = [1,2,3] >>= (\y1->[y1+1]) >>= (\y2->return (y1*y2))
Not in scope: `y1'


However
z' = [1,2,3] >>= (\y1->[y1+1] >>= (\y2->return (y1*y2)))

works again, which misled me to believe that (>>=) associates to the right.

In javascript a lambda would look like this

f = function(y1) {return [y1+1]}

I cannot see how I could possible write a function (>>=) which chains such
lambdas such that I can still access the arguments outside the function
bodies. It is like there are always parentheses around the lambdas. Well there
actually are braces in javascript, but it can't be just the syntax.

So what is javascript missing? Is it because in haskell a lambda is just an
expression wheras in javascript it is something special?




--
Martin


Reply | Threaded
Open this post in threaded view
|

Monads in javascript

Patrick LeBoutillier
Martin,

> z' = [1,2,3] >>= (\y1->[y1+1] >>= (\y2->return (y1*y2)))

I'm not a Haskell expert, but I think the idea here is that the second
lambda is defined *inside* the first one. I think that's the only way
that it can access the first lambda's argument.

I don't know much Javascript, but here is a small Perl snippet that
(kinda) implements the list monad and your example:


use strict ;
use Data::Dumper ;

sub bindM {
        my $xs = shift ;
        my $fx2ys = shift ;

        # maps and concats in one shot
        my @ys = map {@{$fx2ys->($_)}} @{$xs} ;
        return \@ys ;
}

sub returnM {
        my $x = shift ;

        return [$x] ;
}

sub z {
        my $arg = [1,2,3] ;

        bindM($arg, sub {
                my $y1 = shift ;
                bindM([$y1 + 1], sub {
                        my $y2 = shift ;
                        returnM($y1 * $y2) ;
                }) ;
        }) ;
}

print Dumper(z()), "\n" ;


Since $y1 is local to te first lambda, you have to define the second one inside.


Patrick



>
> works again, which misled me to believe that (>>=) associates to the right.
>
> In javascript a lambda would look like this
>
> f = function(y1) {return [y1+1]}
>
> I cannot see how I could possible write a function (>>=) which chains such
> lambdas such that I can still access the arguments outside the function
> bodies. It is like there are always parentheses around the lambdas. Well there
> actually are braces in javascript, but it can't be just the syntax.
>
> So what is javascript missing? Is it because in haskell a lambda is just an
> expression wheras in javascript it is something special?
>
>
>
>
> --
> Martin
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners
>



--
=====================
Patrick LeBoutillier
Rosem?re, Qu?bec, Canada