Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 9 of 9
  1. #1
    New to the CF scene
    Join Date
    May 2013
    Posts
    8
    Thanks
    2
    Thanked 0 Times in 0 Posts

    Need help learning Chapter 6 - Functional Programming

    I am on this chapter.
    http://eloquentjavascript.net/chapter6.html

    And I'm confused. I understand the forEach function helps abstract the for loop through arrays. I also understand that you can declare anonymous functions inside functions and how scope works, but the code in this chapter confuses me, even after googling some of the code.

    Would anyone happen to know a substitute for this chapter? I do want to come back to this chapter and try to understand it.

  • #2
    Senior Coder xelawho's Avatar
    Join Date
    Nov 2010
    Posts
    2,768
    Thanks
    55
    Thanked 518 Times in 515 Posts
    I guess it might be helpful if you say what it is you're confused by. The MDN docs (like this one) provide some explanation and sample code for the topics you're looking at, but I don't think they go into much more detail.

    The best way I have found to pick up new techniques is to write code using them, and if it works, play around with it 'til it breaks and then have a look why it broke (your error console will give you some good hints). Helps if you have a project to work on - writing abstract assignments has never seemed that interesting to me.

  • #3
    Senior Coder jmrker's Avatar
    Join Date
    Aug 2006
    Location
    FL
    Posts
    3,026
    Thanks
    36
    Thanked 494 Times in 488 Posts
    I'm with 'xelawho'. It would be easier if you specified what it is that you don't understand.
    I would not like to re-write or paraphrase what is already written.

    Give small specific examples of what you have tried and what did not work.
    Also helpful if you can explain what you expected your code to do.

  • #4
    New to the CF scene
    Join Date
    May 2013
    Posts
    8
    Thanks
    2
    Thanked 0 Times in 0 Posts
    I get the feeling if I try asking for help on this code, I won't understand said help, since I already tried googling other people's advice to this code. It just looks profoundly complicated.

    Code:
    function negate(func) {
      return function(x) {
        return !func(x);
      };
    }
    var isNotNaN = negate(isNaN);
    show(isNotNaN(NaN));
    In the second line, he declares an anonymous function asking for x. isNan is supposedly passed through the entire thing and has to go through two functions before it turns into !isNan.

    That's one thing I don't understand. But I just called it quits when Ex 6.1 starts and I'm supposed to use reduce().

    Code:
    function reduce(combine, base, array) {
      forEach(array, function (element) {
        base = combine(base, element);
      });
      return base;
    }
    Code:
    function forEach(array, action) {
      for (var i = 0; i < array.length; i++)
        action(array[i]);
    }

  • #5
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    25,020
    Thanks
    75
    Thanked 4,323 Times in 4,289 Posts
    Ehhh...sometimes people do things just to show they can be done, not for any sensible reason.

    It's pretty silly, in my estimation, to create that negate( ) function when you can so much more easily accomplish the same thing by preceding whatever you want to negate with the ! operator.

    That is, why would you ever code var notFoo = negate(foo); if ( notFoo(x) ) ... when you could so much more easily write if ( ! foo(x) ) ...

    But okay, let's explain it, step by step.
    Code:
    function negate(func) {
      return function(x) {
        return !func(x);
      };
    }
    The function negate takes, as its sole argument, another function.

    The function negate *returns*, when called, *ANOTHER* (anonymous) function.

    So far so good, yes? The "trick" is that the anonymous function that is returned *itself* simply invokes the function that was passed to negate, returning the negation (using the ! operator) of the result.

    So let's do it step by step.

    When you code
    Code:
    var isNotNaN = negate(isNaN);
    you are doing
    Code:
    function negate(isNaN) {
      return function(x) {
        return ! isNaN(x);
      };
    }
    Or, effectively, you are creating the function
    Code:
    function isNotNaN( x ) { return ! isNaN(x); }
    Think of it as a macro substitution (it's not, but think of it that way) where every time you code
    Code:
        isNotNaN( anything )
    you are simply doing
    Code:
       ! isNaN( anything )
    It's an interesting technique that is made much less interesting by creating a pretty useless function to illustrate it.

    The important point here is that you can construct a function that can *return* a function.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #6
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    25,020
    Thanks
    75
    Thanked 4,323 Times in 4,289 Posts
    As for the second example you showed, let's just write it out longhand.
    Code:
    function forEach(array, action) {
      for (var i = 0; i < array.length; i++)
        action(array[i]);
    }
    function reduce(combine, base, array) {
      forEach(array, function (element) {
        base = combine(base, element);
      });
      return base;
    }
    Rewritten:
    Code:
    function reduce(combinerFunction, value, someArray) 
    {
        for ( var a = 0; a < someArray.length; ++a )
        {
            var element = someArray[a];
            value = combinerFunction( value, element );
        }
        return value;
    }
    So now let's decide on a combinerFunction to use.

    Let's make it a dirt simple one:
    Code:
    function add( a, b ) { return a + b; }
    And let's create an array:
    Code:
    var numbers = [ 7, 13, 22, 5 ];
    And then we invoke
    Code:
       alert ( reduce( add, 0, numbers ) );
    And, once again, rewrite our reduce function as inline code, making the substitutions:
    Code:
        function add( a, b ) { return a + b; }
        var value = 0;
        var numbers = [ 7, 13, 22, 5 ];
        for ( var a = 0; a < numbers.length; ++a )
        {
            var element = someArray[a];
            value = add( value, element );
        }
        alert( value );
    Or, making one more substitution:
    Code:
        var value = 0;
        var numbers = [ 7, 13, 22, 5 ];
        for ( var a = 0; a < numbers.length; ++a )
        {
            var element = someArray[a];
            value = value + element;
        }
        alert( value );
    Does that help, at all?
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • Users who have thanked Old Pedant for this post:

    Emwat_Oon (05-31-2013)

  • #7
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,184
    Thanks
    10
    Thanked 569 Times in 550 Posts
    reduce is complicated, but here's how i finally got it to "click" for me:

    let's start with a very simple array: [1,2,3,4,5], and reduce it to find the sum of all it's elements.
    for the sake of learning, we will add a dump routine into every call that reduce() makes, logging the inputs and output that the call performs.


    Code:
    dumps=[];
    
    [1,2,3,4,5].reduce(function(past, now){
     var ret=past + now;
     dumps.push([ret, " from: "+now+" + "+ past])
     return ret;
    }); 
    // === 15

    note there's four total executions or steps, instead of five since reduce() burns through two elements for the first (and only the first) execution.

    now, let's look at what we collected from each step :


    Code:
    dumps.join("\n");
    
    3, from: 2 + 1
    6, from: 3 + 3
    10, from: 4 + 6
    15, from: 5 + 10
    notice the pattern?

    aside from the first step, the number on the very right is the same as the number on the very left of the previous line.

    in this example, the first or "past" argument to the reduce function is a running total.


    long-hand:

    you start by pairing the first two elements (2,1).

    you do the something (+) to the pair (2,1), and then pair the result (3) with the next (third) element whose value is (3).

    you do the same something (+) to the new pair (3,3), and then pair the result (6) with the fourth element (4).

    you do the same something (+) to the new pair (6,4), and then pair the result (10) with the fifth element (5).

    you do the same something (+) to the new pair (10,5), and then return the result (15) since we're out of further elements. like a typewriter going DING, we're at the end of the line.

    the result is 15, as seen by the output of the reduce function against the array.


    it's the same pattern no matter the data type in the array, but to me, numbers just make the most sense.


    for kicks, here's a use of reduce that gave me a headache to think about:
    Code:
    [[1,2,3],[4,5,6],[7,8,9]].reduce( function(a,b){return a.concat(b)}) // ==[1,2,3,4,5,6,7,8,9]
    Last edited by rnd me; 05-31-2013 at 10:40 PM.
    my site (updated 13/9/26)
    BROWSER STATS [% share] (2014/1/19) IE7:0.2, IE8:6.7, IE11:7.4, IE9:3.8, IE10:4.4, FF:18.3, CH:43.6, SF:7.8, MOBILE:27.5

  • #8
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    25,020
    Thanks
    75
    Thanked 4,323 Times in 4,289 Posts
    Please do note that the reduce RndMe is referring to is a method on Array, not a standalone function as is the example in that book.

    The arguments to Array.reduce( ) are somewhat different than those for the standalone function, as given. Just for starters, there is no equivalent to the base (what I called value) argument, at all.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #9
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,184
    Thanks
    10
    Thanked 569 Times in 550 Posts
    Quote Originally Posted by Old Pedant View Post
    The arguments to Array.reduce( ) are somewhat different than those for the standalone function, as given. Just for starters, there is no equivalent to the base (what I called value) argument, at all.
    no diff really; everything under the sun's already been done.

    there is a value arg in the native method, we just didn't need it for the simple example.

    Code:
    [1,2].reduce(function(a,b){return a+b}) // == 3
    compared to

    Code:
    [1,2].reduce(function(a,b){return a+b}, 5 ) // == 8
    it's got to be the same mechanism; the output, given identical inputs and functions, are the same on yours as the native methods...

    to wit, we can rewrite your stand-alone using native methods and a wrapper to re-order the args:

    Code:
    function reduce(combinerFunction, value, someArray) {
       return [].reduce.call(someArray, combinerFunction, value);
    }
    
    function add( a, b ) { return a + b; }
    var numbers = [ 7, 13, 22, 5 ];
    
    alert ( reduce( add, 0, numbers ) ); // shows 47
    if you can show a data set and/or function that gives different output on the above wrapper than on the code in post #6, i'd be keen to see it...
    Last edited by rnd me; 06-01-2013 at 07:20 AM.
    my site (updated 13/9/26)
    BROWSER STATS [% share] (2014/1/19) IE7:0.2, IE8:6.7, IE11:7.4, IE9:3.8, IE10:4.4, FF:18.3, CH:43.6, SF:7.8, MOBILE:27.5


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •