Giter VIP home page Giter VIP logo

learnrx's Introduction

Functional Programming in Javascript

This is a series of interactive exercises for learning Microsoft's Reactive Extensions (Rx) Library for Javascript. So why is the title "Functional Programming in Javascript"? Well it turns out that the key to learning Rx is training yourself to use functional programming to manipulate collections. Functional programming provides developers with the tools to abstract common collection operations into reusable, composable building blocks. You'll be surprised to learn that most of the operations you perform on collections can be accomplished with five simple functions:

  1. map
  2. filter
  3. concatAll
  4. reduce
  5. zip

Here's my promise to you: if you learn these 5 functions your code will become shorter, more self-descriptive, and more durable. Also, for reasons that might not be obvious right now, you'll learn that these five functions hold the key to simplifying asynchronous programming. Once you've finished this tutorial you'll also have all the tools you need to easily avoid race conditions, propagate and handle asynchronous errors, and sequence events and AJAX requests. In short, these 5 functions will probably be the most powerful, flexible, and useful functions you'll ever learn.

##Try it Online.

learnrx's People

Contributors

abravetti avatar arilfrankel avatar arliang avatar bado22 avatar calyhre avatar chareesa avatar chasingtheflow avatar chrisguttandin avatar danhyun avatar danielmiladinov avatar deepakshrma avatar denmch avatar ethanresnick avatar g-k avatar gabrielkunkel avatar galberola avatar jhusain avatar krivulcik avatar kurzninja avatar mattpodwysocki avatar miqh avatar mjomble avatar morenoh149 avatar moret avatar mralexweber avatar oryxgazella avatar pierri avatar rafaelbiriba avatar seanpoulter avatar tcasparro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

learnrx's Issues

Why using apply method is necessary to solve exercise 10?

I implemented concatAll() method in the following way and it is marked to be correct by your tutorial.

Array.prototype.concatAll = function() {
    var results = [];
    this.forEach(function(subArray) {
            subArray.forEach(function(element) {
            results.push(element);
        });
    });

    return results;
};

but when I clicked on 'Show Answer', it was using apply method on push, I was wondering why it was needed to use apply method given it works fine without it?

i18n ?

This is a really great tutorial for Reactive newbies like me. Is there any plan for i18n support? It would be great if it's also available in other languages.

Pressing F4 for full screen editor freezes page

I haven't been able to figure out the exact cause, but in some of the editor windows, pressing F4 to try to enter full-screen editing causes the page to freeze up and eventually causes Chrome to say the page has stopped responding and ask to kill the tab. Reloading the tab brings the page back up, but trying to hit F4 on the same editor box repeats the problem.

Currently using Chrome 44.0.2403.52 beta-m (64-bit)

Exercise 26 apparently unsolvable

I have attempted a solution to exercise 26: Converting from Arrays to Deeper Trees, without success ('undefined is not a function'). I have asked to see the hidden solution and it is practically identical to mine: the proof is that... the given solution gets the same error alert!

If I substitute in both mine and your solution the concatMap with a plain map I get the 'wrong result' message and I can see that the items in the videos arrays need some flattening (see image).
immagine
However, also if I put a concatAll() after the map I get the 'undefined is not a function' error.

The consequence is that it is not possible to proceed further in the tutorial, since the right solution triggers the error message. The only way to proceed is to ask beforehand to see all the answers, which is definitely not in the spirit of this activity.

Thank you for your attention.

Exercise 19

Hi wouldn't this code for reduce

videos.reduce(function(acc, video, index) {
  acc[video.id] = video.title;
  return acc;
}, {});

be better than using Object.create in your example

        videos.reduce(function(accumulatedMap, video) {

            // Object.create() makes a fast copy of the accumulatedMap by
            // creating a new object and setting the accumulatedMap to be the
            // new object's prototype.
            // Initially the new object is empty and has no members of its own,
            // except a pointer to the object on which it was based. If an
            // attempt to find a member on the new object fails, the new object
            // silently attempts to find the member on its prototype. This
            // process continues recursively, with each object checking its
            // prototype until the member is found or we reach the first object
            // we created.
            // If we set a member value on the new object, it is stored
            // directly on that object, leaving the prototype unchanged.
            // Object.create() is perfect for functional programming because it
            // makes creating a new object with a different member value almost
            // as cheap as changing the member on the original object!

            var copyOfAccumulatedMap = Object.create(accumulatedMap);

            copyOfAccumulatedMap[video.id] = video.title;

            return copyOfAccumulatedMap;
        },
        // Use an empty map as the initial value instead of the first item in
        // the list.
        {});

Implement exercise 42

It says that exercise 42 is about learning how to retry after errors, but it's actually just a copy of the "Distinct Until Changed Input" exercise (40). Verified this was true in the index.html in this repo as well.

Exercise #24

Greetings.
I found a mistake in the right answer, i believe.
Array.zip() by definition takes 2 arrays and a function as arguments.
But when we are using the result of reduce function on an array of objects as an argument for our Array.zip() function, it will return a single object, not an array with an object in it.
I was able to fix it by wrapping return result of reduce function with square brackets.

return Array.zip(
video.boxarts.reduce(function(acc,curr) {
if (acc.width * acc.height < curr.width * curr.height) {
return [acc];
}
else {
return [curr];
}
});

Am i correct on this or am i missing something?

Thank you.

Object comparison method

On exercise 24, I wrote my solution, ran it and... didn't match the expected output. I started debugging, I printed out each of my results, and they looked correct. So then I showed the solution, and compared each property of each of the resulting objects... also correct. So I printed both to the console; they also matched. Then I finally admitted defeat and actually looked at the solution code. The only difference I could see was the following:

solution:

return {id: video.id, title: video.title, time: interestingMoment.time, url: boxart.url}

mine:

return {id: video.id, title: video.title, url: boxart.url, time: interestingMoment.time}

In case you weren't reading closely, the only difference was the order the url and time properties were added to the returned object. I swapped the order and, lo and behold, it works. Looking at the source code, it looks like this is because the results are compared by sorting the resulting array, stringifying the results, and then comparing the result strings. Unfortunately, most browsers iterate over object properties in the order they were added, so two objects which have the exact same properties and values will NOT produce the same JSON.stringify strings.

Is there any particular reason to avoid doing property based comparisons, that is, checking to ensure both objects have the exact same set of property keys and associated values, as opposed to using the string-based comparison? I would be happy to implement the changes and submit a pull request if that would be amenable.

Thanks

Cannot read property 'answers' of null

Here is what I get by loading the page: https://jhusain.github.io/learnrx/
I haven't done anything, just loaded the page and looking at the console.

Uncaught TypeError: Cannot read property 'answers' of null
(anonymous function) @ main.js:29
x.extend.each @ jquery-1.10.2.min.js:4
x.fn.x.each @ jquery-1.10.2.min.js:4
window.onload @ main.js:24

Exercise 19: Reducing with an initial value

If I console.log() the result of this exercise, it is not like the expected one:

[
  {
    "65432445": "The Chamber",
    "675465": "Fracture",
    "70111470": "Die Hard",
    "654356453": "Bad Boys"
  }
]

it looks like this:

[
  {
    "654356453": "Bad Boys"
  }
]

Is the expected output wrong or just the solution?

Thanks for the great Exercises at all.

Confusion with reactive-extensions.github.io/learnrx/

There's an older, forked repo here: http://reactive-extensions.github.io/learnrx/

That repo looks like it diverges around exercise 10 with mergeAll.

Of course anyone can fork a repo, but that one looks like an official repo from MicroSoft but hasn't been updated for a ~1.5 years, whereas this repo looks active. Adding to the confusion (at least mine), this repo points to their exercises in the readme, as opposed to http://jhusain.github.io/learnrx/

A couple suggestions:

  1. Maybe MS could either take theirs down if no longer relevant or point to yours
  2. This readme could point to http://jhusain.github.io/learnrx/

Contributions could hit the site more easily by removing the master branch

After sending a PR, i realized that my changes wouldn't make it over to the tutorial site because i sent the patch against the master branch instead of the gh-pages branch.

i would suggest getting rid of the master branch because this project can just work off the gh-pages branch and the site would be unaffected. i think it will grease the skids for future contributors/contributions.

A better way (i guess) to implement reduce

Hi, I was following the tutorial and noticed that on exercise 16, where reduce is implemented using a while and a counter, effectively determining how the array should be traversed. Check the code below

while(counter < this.length) {
  accumulatedValue = combiner(accumulatedValue, this[counter])
  counter++;
}

I just started studying RX but, as far as I get it, one of the key points is to leave to the underlying libraries decide how to traverse the arrays? If so, I think the reduce could be better implemented like this:

var accumulatedValue;

if (arguments.length === 1) {
  counter = 1;
  // DON'T SET IT TO ANY ELEMENT
  // accumulatedValue = this[0]; 
}
else if (arguments.length >= 2) {
  counter = 0;
  accumulatedValue = initialValue;
}
else {
  throw "Invalid arguments.";
}

this.forEach(function(it) {
  if(typeof accumulatedValue == 'undefined') {
    accumulatedValue = it;
  }
  else {
    accumulatedValue = combiner(accumulatedValue, it)
  }
})

Exercise 30 functionality broken with provided answer

In Exercise 30, .take(1) doesn't seem to have any effect. On the first button press the alert appears 2-3 times and then on every subsequent button press, a single alert appears. I was testing with the answer provided.

Running on Chrome Version 48.0.2564.97 (64-bit)

concatAll() and concatMap() don't work when you resume a session.

When you come back the the page to continue the tutorial, you need to re-run the exercises 10 and 13, or the other exercises needing concatAll() and concatMap() won't run. These function should be automatically added to Array.prototype by the browser, when it finds related data on local storage.

Unclear direction

A lot of the problems have solutions that require methods that are not explained or introduced in the text preceding the problem. Specifically on Exercise 10, I would have never arrived at the answer because .apply() was never explained to me. Even to this moment I have no idea what the .apply() method does in this specific piece of code, therefore resulting in me having to leave your tutorial and find the answers elsewhere.

This leads me to wonder, why use this tutorial at all if all the information I need is not supplied to me?

Coming to this as someone who is not familiar with the core methods in JavaScript, it has been a very frustrating experience and the only reason I will continue on with this is because it is a requirement from FreeCodeCamp to proceed through their tutorials. If a user who has never used JavaScript before came to this tutorial and was expecting to learn anything from it, they would get a bit of info, but nothing like the abundance of other tutorials out there that actually take the time to walk you through the code and explain everything.

My suggestion is to spend some time, perhaps do some user testing, find out where this tutorial is lacking and update it to be a solid tutorial. If you do not have the resources or interest in doing this, then perhaps removing it from the general public would be the best solution.

small problem implementing prob 32

hello, rookie here, trying to implement drag on a small web app, not sure what Im doing wrong
(i included the code here because it is just a couple lines of code, nothing fancy in html and css)

JS

(function (global) {
    function dragger(){
        var $sprite = $('.sprite');
        var $spriteContainer = $('.container');

        var spriteMouseDowns = Rx.Observable.fromEvent($spriteContainer, "mousedown")
        var spriteContainerMouseMoves = Rx.Observable.fromEvent($spriteContainer,"mousemove")
        var spriteContainerMouseUps = Rx.Observable.fromEvent($spriteContainer,"mouseup")
        var spriteMouseDrags =
                spriteMouseDowns.
                    map(function(down){
                        return spriteContainerMouseMoves.takeUntil(spriteContainerMouseUps);
                    }).
                    concatAll();

        spriteMouseDrags.forEach(function(dragPoint){
            $sprite.style.left = dragPoint.pageX + "px";
            $sprite.style.top = dragPoint.pageY + "px";
        });
    };
    dragger();
}(window));

Question: Exercises 12 & 20 - Functionaly scalable or just tutorial?

Howdy. I'm loving the interactive nature of http://reactivex.io/learnrx/. It is awesome.

However, my quasi-functional brain is having a hard time digesting the approach in exercise 12 (and consequently 20) that calls for mapping the boxarts without an index into the array.

Here is my code that is apparently offensive because it wants to do an index (My C# Linq brain says FirstOrDefault!):

return movieLists.
    map(function(ml) {
      return ml.videos.map(function(v) { 
        return {
          id: v.id, 
          title: v.title,
          boxart: v.boxarts.filter(ba => ba.width === 150 && ba.height === 200)
                           .map(ba => ba.url)
                           [0] //<< this isn't "allowed". firstOrDefault equivalent(?)

        };
      }
        );
    }).
    concatAll();

Without the indexer, this comes up with the "right" answer, in that it is an array with a single element. However, the resulting boxart element is an array and without the indexer (or FirstOrDefault) it is utterly wrong because of this.

Here is the correct answer:

return movieLists.
      map(function(movieList) {
        return movieList.videos.
          map(function(video) {
            return video.boxarts.
              filter(function(boxart) {
                return boxart.width === 150;
              }).
              map(function(boxart) {
                return {id: video.id, title: video.title, boxart: boxart.url};
              });
          }).
          concatAll();
      }).
      concatAll();

To my non-functional brain, this was extremely ugly. I can sense that perhaps this is a nested collection, and that this is possibly related to an unfolding of an abstract construct in the functional world. However, this just doesn't seem to scale to me.

Say I were to add a second array property similar to boxarts, like relatedtitles and I had some predicate to reduce it to a single value. With my approach, you would just add another line that takes the additional properties and filter+map them. How would the corresponding functional approach look?

With this question of scalability in mind, is this just an example to get the tutorial going? Or is there something a real functional guru can shed some light on this? Or should I just keep doing the exercises!? I was avoiding asking this question at exercise 12, but then the reduce exercise 20 brought me back to it. Am I asking the question too soon? If I keep watching the movie, will all be revealed and the universe will be in harmony?

I love the exercises though. This is the best functional + Rx tutorial I've seen over the past couple years.

Exercise 19 - some clarity on why to use Object.create

Hi.
It took a day or two for me to get an explanation on why Object.create is necessary in this exercise (being that the exercise will work quite well without creating a new object). Tell me if I'm right. You want to create that new object only if you want that object to survive after the reducing is finished... so you can use that object elsewhere in your code. Even though the object is returned from the reduction. Am I close?

A little more explanation would be helpful.

Thanks for the tutorial so far!

Exercise 41: Autocomplete Box Part 2: Electric Boogaloo and distinctUntilChanged() usage/behavior

For exercise 41, the distinctUntilChanged() function is used to filter out successive repetitive values. However, when I enter a word with repetitive values aa vs a I get different results. Is this expected behavior? If yes, then the same function ( distinctUntilChanged()) does not behave the same way in exercise 40 - in that exercise, typing aa will display a. Exercise numbers refer to the tutorial found here: http://jhusain.github.io/learnrx/

Exercise 24 incorrectly evaluates based on order of items

Hey I submitted an answer which contained the same objects but in a different order and it was evaluated as incorrect. My solution preserves the order of the objects in the input.

return movieLists.concatMap(function(movieList) {
return movieList.videos.map(function(v){
return Array.zip(
v.boxarts.reduce(function(acc, curr){
return curr.width * curr.height < acc.width * acc.height ? curr : acc;
}),
v.interestingMoments.filter(function(item){
return item.type == "Middle";
}),
function(left, right){
return { id: v.id, title: v.title, time: right.time, url: left.url };
}
);
});
});

Question 12 is unfair

Up until Q12 it has been little steps, introducing new things, then combining them. Q12 combines a number of previous concepts but also assumes users will realise to use closures to reference values in previous operations.

This is unfair to the learner. You should never have questions that require specific knowledge that you either haven't previously used in exercises or or at least referenced.

I would suggest at least one preceding simpler exercise with "nested" maps where the inner one references the outer. Then you can through this complex one at them.

TypeError: verifier is not a function

In Firefox 19.0.2, I see this following error when trying to run the first exercise:
TypeError: verifier is not a function
Please comment. Thanks

The online site is not working after cancel the "Set answer JSON" promt :(

I tried to open it on my chrome browser. It is not working at all. I press run button too many times.. Nothing happens. I did some changes on code. it throws me error all the time. Even though i copied answer from other location. I clicked on show all answer nothing happens. I thought i is the prob with chome. I tried it on Firefoz though, Result is same. Run still not woking. Somehow show all works on firefox. But excep that nothing is working. Please check. I have mention all required detail below. Examples are too good. Thanks ๐Ÿ‘

Google Chrome
Version 43.0.2357.81 unknown (64-bit)
Firefox
38.0
System:
Ubuntu LTS 14.04

functional programming in javascript

Typo in ReadMe - Anchor tag does not have href!

The link to view the tutorials online does not have an associated href attribute, and therefore does not link to anything.

I think we'd all really like to know where that link is suppose to lead! ๐Ÿ˜„

Invalid implementation of map in Lesson 4 will break code navigation

CodeMirror checks for and uses map on Array.prototype if it is defined.
see it on codemirror.js L7213

  function map(array, f) {
    var out = [];
    for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
    return out;
  }
  if ([].map) map = function(array, f) { return array.map(f); };

solvable by commenting out/removing line 7213

  function map(array, f) {
    var out = [];
    for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
    return out;
  }
-  if ([].map) map = function(array, f) { return array.map(f); };

Exercise 22: incorrect comment (fragment pasted from exercise 16)

Comment for exercise 22 starts with the following:

// JSON.stringify(Array.zip([1,2,3],[4,5,6], function(left, right) { return left + right })) === '[5,7,9]' accumulatedValue + currentValue; }); === [6];

The part accumulatedValue + currentValue; }); === [6]; seems to be pasted from exercise 16 by accident.

Exercise 3: mention "push()" (for JS newbies)

While trying to solve the third puzzle, I had to consult a JS API reference to find "push()". After doing more puzzles it struck me that I could solve them without having to look at the doc again, so in retrospect it would be nice if the early puzzle mentions "push()" so I could have stayed focused on the page :-)

Some exercises don't have answers, clicking "Show all answers" clears the code

Some exercises which are actually demonstrations don't have answers in the code. This causes them to lose the demonstration code when the user clicks the "Show all the answers so I can just browse." button.

Exercises affected:

  • Exercise 28: Subscribing to an event
  • Exercise 29: Traversing an Event
  • Exercise 34: HTTP requests
  • Exercise 35: Sequencing HTTP requests with callbacks
  • Exercise 36: Traversing callback-based Asynchronous APIs
  • Exercise 37: Sequencing HTTP requests with Observable

Exercise 11

If I give a name to the anonymous function and console.log() it,
I get this error:
"TypeError: movieLists.map(...).concatAll is not a function"

exercise 33 is broken

there is a problem with contactPoint event object โ€” there are no offsetX and offsetY properties.

Exercise 44: Retrying after errors

Now that we know how to get only the distinct input, let's see how it applies to our autocomplete example...

should read:

Now that we know how to retry after errors, let's see how to catch exceptions...

get answers as JSON maxes out at 32000 chars

After completing all 42 questions I wanted to save my state locally as advocated possible at top of the page.

Only to find out the data posted to my clipboard by Safari is no longer than 32000 characters, leaving me with an incomplete dump of my state.

Correction: it is Safari 8.0.8 (only browser tested by me) that initially only selects the first 32000 chars in the popup, re-selecting the JSON grabs the full (in my case) 52k chars.

I have no idea how the browser is told to make the text (conveniently) pre-selected in the pop-up, so this might not be a bug for this repo.

Ps: liked the tutorial a lot, very educational.

concatAll() is not a function, Exercise: 12

I have solved Exercise 12, but I can't go any further because, when I click on run this error pop up ( TypeError: movieList.videos.map(...).concatAll is not a function ).

"Get Answers as JSON" doesn't work well

window.prompt() in Chrome has limit for 3000 characters. As a result we may get invalid JSON if it's longer than 3000 characters. Not sure about limitations in other browsers.

Reduce returns an array, not a value

This was mentioned in comments of other issues, but I think it warrants it's own issue. The reduce implementation in the tutorial returns an array, not an object, which goes against the JS spec. For those people coming to this tutorial who are already familiar with JavaScript, this is more than a little confusing.

I'd recommend either:

  1. Clarifying why the reduce implementation here is different from the one of the JS spec
  2. Changing the exercise so that reduce does return a single value.

Great tutorial! Lots of fun to go through the exercises.

Can't get anything working.

I've just executed the workaround for this bug, and this is printed to the console:

HTMLElement.prototype.innerText = function() { return this.textContent; }
function()

I now see the first three tests, but when I click "run", nothing is printed to the console. On the third test, however, when you click "Show answer", the following error is printed to the console:

TypeError: string.split is not a function
http://reactive-extensions.github.io/learnrx/assets/codemirror/codemirror.js
Line 3124

Otherwise, no output. I'm on Firefox 35.0.1, Windows 8.1, 64bit. I have the NoScript 2.6.9.10 Firefox plugin installed, but it's currently set to "Allow scripts globally" (which is temporary only for this tutorial). I also have Ghostery and AdBlock Plus, if that makes a difference.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.