

Anyone using a functional programming style in their Javascript? - robin_bb


======
nostrademons
Depends which parts of functional programming you mean. I use $.each (JQuery),
closures, let-bindings, and anonymous functions all the time. Not so much on
the statelessness, because:

a.) JavaScript makes it a bit of a pain to deep-copy objects; you can rig up
something with $.extend and $.map, but it's not in the standard language the
way Python's .copy() and [:] are

b.) Most of the time when you're doing JavaScript, the point is to change the
state of the UI. Hard to write stateless code where the intended effect is to
change state...

~~~
robin_bb
Let bindings? Huh?

~~~
nostrademons
Usually done using:

    
    
      (function(var1, var2) {
         // var1 and var2 are now bound within this block
      })(val1, val2);
    

Why use this instead of...

    
    
       var var1 = val1;
       var var2 = val2;
       // do stuff with var1 & var2
    

It's because if you have any closures within the block, they'll capture the
_bindings_ of var1 and var2 instead of their _values_. That means that if
you're inside a loop, your bindings will be overwritten each time through, so
you could end up creating a dozen closures that all do the same thing.

Here's an example from a JQuery patch I did a couple weeks ago:

<http://dev.jquery.com/attachment/ticket/1737/bug1737.patch>

Before it used an eval statement to directly write the value into the source
code of the closure. After, it captures the value with a let-binding and then
returns a closure over the current _value_ instead of the current _binding_.

~~~
robin_bb
Thanks. I thought that someone was suggesting that they were using let = ...
syntax. Now, I understand that the idiom you showed is "let binding" in the
Javascript world.

------
lsb
I came to Javascript from Ruby/Scheme/Haskell, so when I had to call the Yahoo
Search API with a callback, sometimes with two or more searches concurrently,
I thought, oh, I'll store the continuation, because they only allow
/[A-Za-z0-9.]+/ as characters in the callback.

var fns = [];

function gensym() { return $R(0,20).toArray().map(function(){return
String.fromCharCode(Math.random()*26+65)}).join('') }

function storefunc(f) { var g = gensym(); fns[g] = f; return 'fns.'+g }

function jsonk(url,hash,k) { var s = document.createElement('script');

    
    
      s.src = url+'?'+$H(hash).merge({'callback': storefunc(k)}).toQueryString();
    
      document.body.appendChild(s);
    
      return s.src

}

I learned gensym and web-read-k in Scheme at Brown (thanks, Shriram!), and
jsonk turned out to be pretty useful, because the same comtinuation-passing
style that's available when you do XHRs now becomes available when you do json
requests from a different domain, if they have a callback parameter. (I
brought this code to Songkick, and we shortened callback to k.)

~~~
neilk
What's $R and $H doing? I know Javascript, but I don't know all the cool
frameworks very well.

Otherwise, this is mad cool.

~~~
lsb
it's a little kludgy, but here's how it goes:

fns stores continuations. gensym: make an array of 20 random characters (make
an array of 20 #s, map each to a random character). storefunc: continuation ->
string, and store the continuation in fns, such that
eval(string)==continuation jsonk: make a query string from the url, the
parameters supplied, and the continuation (change 'callback' to whatever the
api calls it), and then add that script to the page, returning the url for
debugging purposes.

you could also have a timeout after 30 seconds to say "something went wrong",
and that might not be much more code, just set a timeout, and wrap k in jsonk
to a function that first stops the delayed error message and then calls k, but
that's an exercise for the reader.

but yeah, so

jsonk("<http://api.search.yahoo.com/WebSearchService/V1/webSearch>",{output:'json',appid:'YahooDemo',query:'britney'},function(r){alert(r.ResultSet.totalResultsAvailable)})

will pop up an alertbox that shows how many hits 'britney' gets on yahoo.

------
altay
anyone have any suggestions as to how i can make this a little more
functional? it's the code for the score ticker on my site,
<http://www.qtoro.com>. (uses the prototype js framework.) it was feeling
pretty good til i had to put in those 'if' statements...

    
    
     Urtog.score = new function() {
      this.init = function() {
        this.upmod; // boolean.  if increasing score, it's true; if decreasing, false.
        this.unit = 34;  // the pixel height of one digit
        this.digits = $$('div#scoredigits img.digit');  // array of all the digit images
      }
    
      /* change the score.  
       * first arg is the # of points to add or subtract (if negative).  
       * second arg is optional, specifies which digit img element to mod.  the default is the "1's" digit.
       */
      this.mod = function( points, digit ) {
        this.upmod = (points > 0);
        digit = digit || this.digits.last();
        var di = this.digits.indexOf(digit);
        var dy = (this.upmod ? 0-this.unit : this.unit);
        (Math.abs(points)).times(function(i) {
          new Effect.MoveBy(digit, dy, 0, {
            queue: {position:"end", scope:"d"+di},
            duration: 0.075,
            transition: Effect.Transitions.linear,
            beforeSetup: preroll.bind(Urtog.score)
          });
        })
      }
    
      /* the callback that's run before the digit is modded.  
       * does two things:
       * 1. resets the image strip to the top/bottom if necessary 
       * 2. checks if we should simultaneously mod the 10x digit (e.g. going from 09=>10 or 10=>09)
       */
      function preroll(effect) {
        var d = effect.element;
        var di = this.digits.indexOf(d);
        var offset = d.style.top;
        if (this.upmod) { // adding points
          if (offset=="-340px") { // at the bottom of the strip, so reset to the top
            d.style.top=offset="0px";
          }
          if (offset=="-306px") { // transitioning from 9=>0, so mod the 10x digit, too
            this.mod( 1, this.digits[di-1] );
          }
        }
        else { // subtracting points
          if (this.digits.all(function(d) { return is_zero(d.style.top); })) { // we've hit zero!
            Effect.Queues.instances.keys().each(function(k) {
              if (k.match(/d[0-9]*$/)) { // cancel all pending digit mods -- digit effect queue names are like d3,d2,d1
                Effect.Queues.instances[k].each(function(e) { 
                  e.cancel() 
                }); 
              }
            });
            new Effect.UrtogShuffle('scoredigits');  // :)
            return false;
          }
          if (is_zero(offset)) { // at the top of the strip, so reset to the bottom
            d.style.top=offset="-340px";
          }
          if (offset=="-340px") { // transitioning from 0=>9, so mod the 10x digit, too
            this.mod( -1, this.digits[di-1] );
          }
        }
      }
    
      // account for bizarre safari behavior... wtf is "-0px"??
      function is_zero(offset) {
        return (offset=="0px" || offset=="-0px");  
      }
     } // end Urtog.score

------
gregwebs
I am toying around with flapjax at the moment.

www.flapjax-lang.org/

It uses the functional reactive pardigm where state can be implicitly updated
without callbacks. Flapjax is compiled down to javascript, which makes a lot
more sense than the functional javascript library which tries to make
javascript into something it isn't.

osteele.com/sources/javascript/functional/

