Giter Club home page Giter Club logo

functional-light-js's People

Contributors

adriano-di-giovanni avatar alan2207 avatar christianhg avatar darkamenosa avatar diaomouren avatar dkab avatar egdbear avatar exiadbq avatar exploremqt avatar fcasad avatar getify avatar hingsir avatar hoodwink73 avatar jackrsteiner avatar joehetfield avatar jtassia avatar juliomatcom avatar klequis avatar nickpapasavvas avatar pertrai1 avatar pobusama avatar rajikaimal avatar rkichenama avatar rus0000 avatar samouss avatar saroamirkhanyan avatar stevemao avatar tbroadley avatar uldissturms avatar vivaxy 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  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

functional-light-js's Issues

Tech Edit: Chapter 6

Another spot-free chapter tech-wise. Just a few possible suggestions:

  • I was a bit confused by the diagram for the persistent array data structure. Maybe it'd be good to match the specialArray code below it? I liked the diff analogy and I get the idea, I just couldn't see it from the image. (and I thought I knew this stuff! :) )

  • there's a typo with Processsing

  • The const discussion is a const-roversial for sure. As someone who often accidentally names functions the same as variables, I personally find value there, but I see your point. I want to disagree that developers can't understand the difference between immutability and reassignment, but I see that confusion all the time in the industry.

In any case, I feel it's worth a mention (somewhere in the book) that reassignment breaks ref transparency (and, therefore, equational reasoning), and adds a substantial obstacle to parallelization, which is why it is not allowed in just about every functional language. I guess I was thinking a note that in FP languages = means equals, not assignment, which is not the case in JS.

I was taken aback by this discussion, though, as it is often cited as improving readability since you don't have to track variable changes as well. As I saw it improved readability was the main aim of this book. I did appreciate and acknowledge, however, that mutation is much less conspicuous than reassignment and priority-wise, should be the focus.

A compose() with reduce() and multiple args

I understand that your chapter about Alternate Implementations for compose() is a way to make your reader think about the concept.

So I guess it's a success: it stroke me as obvious that there is another (maybe simpler) way to make the compose() with reduce() accept multiple args: by handling the first call with the given arguments then subsequent calls with reduce():

function compose2(...fns) {
    return function composed(...result){
        var first = fns.pop()(...result);
        return fns.reverse().reduce( function reducer(result,fn){
            return fn( result );
        }, first );
    };
}

Though I'm quite proud of myself, I'm not quite sure it was a matter for an issue :) I'll let you judge.

Development Edit: Chapter 6

Another strong chapter; organization is clear. Only minor comments.

Non-Local section

I'm not sure what "non-local" means in this context. Is it a reference to the fact that the value could be mutated by some other part of the program? If that's the case, there should probably be a parallel heading "local" earlier on in the "Value to Value" section.

Reassignment section

When you're talking about constants, you say "that variable cannot be reassigned to any other value." I normally think of values being assigned to variables, not the other way around. Is my ignorance showing, or have you covered this elsewhere and I forgot it? Or is that part of the "confusion in just about every language" that you mention later? You may want to spell this out a bit more thoroughly, if it's a common misconception.

Performance section

I like this section. You're anticipating an objection, and dealing with it appropriately.

The figure showing the linked list of object references isn't clear to me. I can't follow the initial state, final state, where the mutations are taking place. It could be my limited familiarity with git causing the problem.

Development edit: Chapter 4

I liked this chapter a lot. Very clear, usable, and demonstrably functional.

Intro Section

Good definition -- the metaphor is clear on what composition is. So take it the next step and make me the promise. What will I get out of this chapter? What's the use case for composition?

Output to Input section

This example:

functionValue <-- unary <-- adder <-- 3

And the figure that follows both go right-to-left, which is non-intuitive for the reader. There's a reason for doing that in FP, but that's not obvious to readers yet. So you should probably mention that you're doing it, and that you'll explain why later.

"To use these two utilities to analyze a string of text:"
Although it's pretty clear from the function names what these two utilities are intended to do, it also doesn't hurt to come out and say it plainly.

Composition Variation section

This section, while accurate, could really do with a real-world use-case or example. Without it's just a curiosity.

General Composition section

This concept is a big idea. The idea of manual composition is fine, and I think something that readers will be familiar with, or at least can easily grasph. But the idea of a function that automatically composes other functions, that's more of a stretch. You're presenting it fine, but I suggest making this section a level-1 heading to make the importance clear.

"You can also curry(..) a composition instead of partial application,"
This sounds like something that could use an example, rather than just a throw-away. Unless you wouldn't do it very often in real life?

Abstraction section

Right before this bit: "Aside from generalization vs specialization,"
I think there should be a new heading, as you're switching from the generalization purpose to...well, it needs a name. "Conceptual abstraction," I guess, but that's kind of redundant. "Declarative Abstraction"? Whatever term you choose, that should be the heading here.

Revisiting Points section

I like this section -- solid, practical, hands-on.

Summary Section

If you've added a "promise" to the intro section, this would be a good place to demonstrate that you fulfilled it. Also, where are we going from here? What's the connection between composition and side effects?

Tech Edit: Ch 8

This is a very important chapter and as far as List operations go, I think it is a grand slam. I dug the filter double negatives :) I mix that up still! I also really like the visualizations and various "real world" uses of reduce to implement other familiar list methods. You even touch of an important advanced FP practice of not destroying information (discouraging every/some). I even go as far as to not use filter and have since employed partition in its place.

Found 1 quick typo (i know it's not my job, but I figured i'd say something if i see it)

  • values together into on value -> values together into one value

There are some issues around Functors:

  • Functor is not artificial invented terminology - it is an exact implementation from category theory (https://en.wikipedia.org/wiki/Functor) just as isomorphism or compose is.

  • A functor is a value that has a utility for using an operator function on that value. - I'd add which preserves composition. That's very important because it means [x].map(f).map(g) === [x].map(x => g(f(x)) or in other words, means you can keep chaining maps or fusing them as we mention later in the chapter, without concern. Consider Promise.resolve('yo').then(x => x.toUpperCase()).then(x => x + '!') and Promise.resolve('yo').then(x => x.toUpperCase() + '!'). Were it not for this law, we wouldn't be able to trust then at all. (of course, we'd rename then to map to make it the proper interface)

  • The string example is not a functor because it does not preserve composition:
    const x = stringMap(x => x.letter, stringMap(x => ({letter: x}), "bob")) // ''
    const x = stringMap(x => ({letter: x}.letter), "bob") // 'bob'

Basically, the law suggests you must be able to change types within a map.

A few issues with BST

  • A typical implementation of a binary tree found in an FP language would pass the value and not the whole node. This is because map should effortlessly preserve structure and obey the above laws.

Passing the whole node allows one to alter the structure of the tree while traversing it, which can lead to super confusing behavior like replacing subtrees you just mapped.

When we need a whole node, we use the comonad instance extend which does pass the whole node in, but only replaces the value of that one node with whatever's returned. So:

tree.map(v => v.toUpperCase()) // same tree with uppercases
tree.extend(node => node.value.toUpperCase()) // same tree with uppercases, but we get more context while altering the 1 value

The map provided then, disqualifies it from being a functor. Perhaps that should be mentioned or we shouldn't have previously discussed functors since, in my opinion, it's a little confusing to the reader. Otherwise if we pass value in, it is indeed a functor and we probably should mention that :)

  • The same issue with value applies to reduce. Typically the way we'd want to get more context here is with different recursion schemes (and those have a direct relationship with comonads). Unlike map, I'd need to play around with altering the tree structure whilst reducing to understand why this matters or if it even matters.

For this one though, I realize how bending over backwards to be principled is in direct conflict with the intent of this book. If i had to pick a battle it'd be map since that does not hold the intuition and reduce is an entirely different animal.

  • Finally the S in BST is not preserved by any of these operations. For it to remain a search tree, we must balance after each map/filter/reduce.

That means we cannot make a search tree a functor anyways because of the constraint that composition is limited to "comparable" return values. e.g. how does one balance tree.map(x => Promise.resolve(x)). I think maybe the best move here is to remove the search part so it keeps the discussion focused on the utility of these functions.

In any case, I think these issues can be easily ironed out with a few adjustments and the chapter can remain perfectly in tact since it flows beautifully and teaches some great content.

Development Edit: Chapter 7

Organizationally, this chapter is fine. You make a point that this chapter is something of a digression, but it doesn't seem that way to me. Maybe it's because I'm accustomed to you making a big deal out of closures, but the content seems to fit fine with the chapters before and after. Still, I'll keep an open mind, and if I find a spot later on where it would fit better, I'll say so.

Intro quote: This quote is long enough that you should probably get written permission to use it.

The Same Page section

Although you have good examples of closure and objects here, you aren't explicit about exactly how they're defined, to you. That's important, because the readers might not get there on their own.

Behavior Too section

I think this should be a level-2 heading. "Behavior" in this case is clearly parallel with "State," so the headings should be the same level.

Isomorphic section

I don't think you gain anything by explicitly quoting a blog post that you wrote. Just repeat the content; it's yours, so there's no legal issues there. Include a link to the post for further reading, if you like.

Personal opinion: I've seen the slice() method used throughout to shallow-copy an array. It seems to me that's not particularly intuitive; it sounds like it should be used when you want a subset. I know it's common to define "a copy of the whole thing" as a "subset," and technically it is, but since you're spending so much time on code being clear and readable, I thought I'd mention it.

Summary

I get what you're going for here, and I hate to be "that editor with no sense of humor," but I think a traditional summary might be useful here, given that the concept in this chapter is kind of tricky to wind your head around.

Tech Edit: Appendix B

This is a perfect introduction and use of the Maybe monad. I'm so grateful for the clarification of Maybe - I hope everyone in JS reads this!

The intro is great. It's exactly an interface with expected behavior. Very nice way to describe these burritos. The end is fun too!

Here's what I got:

  • I think calling Humble a data structure or the "Maybe+Humble monad" is a stretch - even with the "technically it's not a monad by itself" note. It is a standard monadic function (or kleisli arrow if you like): a -> M a where M is a monad. safeProp is a monadic function as well. They are just two damn good examples of using Maybe in action. The egoChange example breaks out of the null-check box and demonstrates usage very well.

  • ap is technically part of the Applicative (aka Apply) interface, but every Monad is an Applicative so the point is moot. Could be a note, might not matter. Just sayin' :)

  • Maybe.of( x ) instead of Just( x ) in the definitions of Humble and safeProp are a bit unidiomatic. of is usually reserved for when we need a generic way to place a value in a type and start chaining away - exactly how you do in the safeProp usage. Since we don't really need to program to an interface and the intent may be a little clearer with Nothing/Just vs Nothing/of, it might be good to change. However, I see why you might want to avoid juggling 3 constructors while teaching...

Code typo in ch4, Composition As Abstraction

var wordsFound = words( text );
var uniqueWordsFound = unique( wordsFound );
var shorterWords = skipLongWords( uniqueWordsFound );

shorterWords( text );

Uncaught TypeError: shorterWords is not a function

skipLongWords( unique( words( text ) ) )( text );

Uncaught TypeError: skipLongWords(...) is not a function

Suggestions for changes to less than ten words

Hi Kyle, do you see this kind of edit as a valid suggestion:

Original: I believe very deeply that the vastly more important role of code is as a means of communication with other human beings.

Modified: I believe very deeply that code is vastly more important as a means of communication with other human beings.

If it is I can just collect everything I find into one issue, formatted clearly into their chapters, etc, for use at your discretion. I'll include original text for easy search. Cheers.

Ch5 error: replacing the object users by reference with it's own shallow copy

function safer_fetchUserData(userId,users) {
    // simple, naive ES6+ shallow object copy, could also
    // be done w/ various libs or frameworks
    users = Object.assign( {}, users );

    fetchUserData( userId );

    // return the copied state
    return users;


    // ***********************

    // original untouched impure function:
    function fetchUserData(userId) {
        ajax( "http://some.api/user/" + userId, function onUserData(userData){
            users[userId] = userData;
        } );
    }
}

should be refactored to:

function safer_fetchUserData(userId, _users) {
    // simple, naive ES6+ shallow object copy, could also
    // be done w/ various libs or frameworks
    const users = Object.assign( {}, _users );

    fetchUserData( userId );

    // return the copied state
    return users;


    // ***********************

    // original untouched impure function:
    function fetchUserData(userId) {
        ajax( "http://some.api/user/" + userId, function onUserData(userData){
            users[userId] = userData;
        } );
    }
}

Development edit: Chapter 1

Chapter 1

General:
This chapter needs a hook, something for the reader to DO. It could be as basic as a Hello World, but the reader should see some code in this chapter. If the point is that functional code is more readable, show me a comparison of something I'd do day-to-day in JS, followed by how it should be done in FP. A simple example, if possible, so that I can understand why the FP version is more readable. And be prepared to argue for why the functional version is more readable, because it's going to look strange (and scary, and not-worth-it) to FP newbies.

You seem to be apologizing a lot in this chapter. That undermines your authority as the author, and makes the reader doubt whether this book is what they need. I'd suggest setting aside your own personal struggles with this content, at least for the time being.

The intro paragraph could push harder on the "what's in it for me?" of functional. Specifically, what's the benefit to a JS developer? Your audience is probably people who've been working in JS for a while, and will need to see a reason to change. What's the main benefit? You say later that it's "readability, therefore trustability, which leads to reduced maintenance time." If that's the primary benefit, say it up here. You can make the argument more thoroughly later, but introduce it here.

"Confidence" section:
"code that you cannot trust is code that you do not understand."
Maybe reverse that? "code that you do not understand is code you can't trust" follows a cause-to-effect pattern more clearly.

"Communication" section:
"researchers who've studied this topic" Do you have a citation for that assertion?

Lots of short paragraphs in this chapter. That's effective in a blog post, but at book length, a staccato style tends to be off-putting. Whether you change that depends on what you think the reading pattern for this audience will be.

"I think we should focus a lot -- a LOT! -- more on the readability of our code. Like, a lot more."
I suggest dropping one of the "a lot" instances. One is fine; two is overkill.

This paragraph is problematic:
"So, if we are going to spend more time concerned with making code that will be more readable and understandable, FP turns out to be a really handy pattern in that effort. The principles of FP are well established, deeply studied and vetted, and provably verifiable."
The problem is that you don't really say why FP is more readable. That's why I think an example would help. Failing that, citing a source for "deeply studied and vetted" would be helpful.

"If we use FP principles, I believe we will create code that is easier to reason about."

  1. I suggest turning around "we" to "you." If you say "we," the reader may think it's helpful for you, but not for them. Change it to "you," and your focus is helping the reader.
  2. Drop "I believe." That again ties the benefit to your experience, which may not be the reader's.
  3. What are the "principles" you're referring to? You've talked about functional as a single entity up until now; why switch to principles now?

"Readability Curve" section:
I suggest bumping this to a level-1 head. It's related to "Communication," sure, but you're also talking a lot about the learning curve here, which is about the process, where communication is the goal.

"It's really important I take a moment to call out a phenomena that has derailed and frustrated me many times over the years, and was especially acute while writing this book."
You're talking about the readability curve for two paragraphs, and a figure, without saying exactly what it is, or giving it a name. The beginning of the above sentence wastes a lot of words: "It's really important that I take a moment..." You can skip all that and get to the point. Problem is, the point isn't immediately clear. I think it's something along these lines: "When you start to transition to functional programming, you'll probably find that the readability of your code decreases at first. That's frustrating, seems counterproductive, and causes many people to give up on FP. But if you stick with it, you'll find that the readability not only comes back as you gain experience, but increases dramatically."

(Also, "phenomena" is plural; the singular is "phenomenon.")

"minimize or eliminate most of the places where you might write bugs." -- I think there's an important point here, one that you're burying. If I understand this correctly, if you're writing good functional code, you eliminate a lot of bugs not because FP is magically better, but because you're taking out the places where bugs could occur in the first place. The overall number of bugs decreases because they literally can't happen. That's a big selling point, and it's not emphasized. (Again, a side-by-side code comparison would really illustrate the point well.)

I think this section goes on a bit too long with your personal struggle. I don't deny its validity, and I think anybody who's made the transition will recognize it, but it's kind of discouraging for a new reader. Instead of telling them how big the hill is, and how it's worth it from the top, how about helping them to take the first few steps?

"Take" section
I'm not sure what this section title means. (Is that just me being old?)

I'd change the "we" language to "I" in the first paragraph. It's not what "the author and the reader" will be doing, because the reader has no say in the matter. You're outlining your approach, so say "I."

"I hope this book can..." Don't suggest what the book may do, say what it will do.

When you're talking about formalism in this section, can you break it down? Take one of those formal terms and translate it into a simple English phrase a JS user would understand. Maybe it's not possible, but talking about "formalism" in the abstract just gives readers the impression that there's something vague and scary down the road that they'd like to avoid.

"YAGNI" section
After giving this some thought, I recommend pulling this entire section, or at least postponing it until later. The section title is misleading -- readers could easily get the impression that all of FP is something they don't really need, or will trip them up later. You're telling them "don't FP unless you need to FP." Problem is, for readers in Chapter 1, FP is unknown as of yet, so how will they tell the difference between "this is hard, but will be useful later" and "I won't need this later"? This section is basically giving them another excuse to back out of the book. It's good advice, but won't make sense until they've gotten their feet under them.

Summary section

  1. I suggest putting the summary before the resources, if you want people to read it.
  2. I suggest "conclusion" or "wrapping up" rather than "summary," because it should do more than summarize.
  3. My standard advice for conclusions:
    a) An indication that the promise of the introduction was kept
    b) Hints for further exploration
    c) An organic connection to the following chapter

The conclusion in this chapter isn't working because there wasn't a promise to this chapter -- the reader didn't DO anything.

In depth use of partial - chapter 3

You make it a point to understand the partial function, and i find that it would be good to get an understanding of a use case of how it would be used.

When the partiallyApplied(..) function is later executed somewhere else in your program, it uses the closed over fn to execute the original function, first providing any of the (closed over) presetArgs partial application arguments, then any further laterArgs arguments.

Careful about explaining currying

This quote is wrong and misleading:

Currying is a special form of partial application where the arity is reduced to 1, with a chain of successive chained function calls, each which takes one argument.

Currying is not at all a special form of partial application. Some people get currying and partial application confused because in languages like Haskell, functions are curried by default, which is convenient for partial application.

What currying is much more simple. It's merely this:

curry :: ((a, b) -> c) -> (a -> b -> c)

This leads to another concern I have with your pedagogy. To get to a syntactic convenience, you go over techniques well beyond FP, like reflecting over the arity of a function. This makes currying seem much more fancy that it really is conceptually. My recommendation is to explain the basics with just the basics. Then find a way to layer on complexity more incrementally. You may not get to the slick API immediately, in exchange people may track better with the concepts you're trying to teach.

That said, I think Chapter 1 is just too long, and goes too deep into the nuances Ecmascript's function implementation. Just to start with, I'd recommend just showing people the bare minimum to play around with a lambda calculus in a REPL. That makes the discussion of simple combinators like curry, uncurry, flip, etc, much more tidy.

Development Edit, Chapter 5

I went over Chapter 5 multiple times, because I wasn't finding as much to say about it as I had the previous four, and that worried me. However, after reading the next several chapters, I think from this point on, the writing really hits a groove, and there isn't as much to say from a development standpoint. The organization is clear and strong, and easy to follow.

Once Is Enough, Thanks section

This section is all about defining what "idempotence" means, both mathematically and programmatically, but if the reader has no assumptions about the word coming in, it can be hard to get through the discussion. I think it would help to provide a "common definition" of idempotence in the first paragraph or two, for those readers who haven't encountered the concept.

Performance Effects section

Is performance the only consideration for "pragmatic referential transparency"? It's certainly important, but I got the impression that there might be other reasons for "pragmatic" referential transparency that aren't discussed. If not, then so be it.

this Revisited section

I suggest promoting this heading to level 2. It's not really a subset of "Evading Effects," it's another variation, as you say in the first sentence.

Encourage use of reduce

Hi, really great work :)

I am so excited to have a new voice / perspective in the FP community.

When teaching how to apply FP in applications I find reduce is indispensable. Elm uses foldp to convert streams into DOM snapshots and apply them to the page purely. React and Redux are all about reducers. And then most of the utilities we use in lodash or ramda can be implemented in terms of reduce e.g. (filter, takeWhile, compact, map, compose, etc)

I was just reading ch4 and noticed the variadic compose was using a while loop and popping an array.
Which is great from a performance perspective. But for learning FP I thought it might be nice to implement compose using reduce to illustrate how simple compose really is.

function compose(...fns){
   return fns.reduce(compose2)
}

It may complicate your arc, but I thought I should at least mention it.

I remember reading your transducers gist (which was great), so perhaps you are covering reduce in some later chapters (or maybe in a later book). But I think if you cover reduce early you could make use of it again and again throughout the book.

E.g. in the point free section we could redefine compose as

// unapply just turns this into a fn that accepts variadic args instead of an array
const compose = unapply(reduce(compose2))

reduce allows us to create variadic functions using binary signatures so it also could be relevant in discussions of arity.

So, reduce is useful, powerful, practical and elegant. But I know you need to pick your battles when teaching and reduce might complicate matters. So this is merely a vote of support for reduce. And keep doing what you are doing it is exactly what FP and JS needs.

Tech Edit: Chapter 3

Loved this chapter. I feel it really gets the reader excited about this stuff!

What follows is a collection of mostly unnecessary ideas rather than "tech edits". I thought the tech was spot on and the examples were great so not much to do there. Either way, here are some thoughts:

  1. You demonstrate equational reasoning several times both explicitly and implicitly.
  • Inlined the partiallyApplied definitions
  • Refactorings like mappers and constant (and several others)
  • ExplainingprintIf refactor.

I wonder if it's worth a mention that FP goes out of its way to preserve equational reasoning. Not sure if you'd want that, just saying something since these are great examples of it in action.

If it is a thing you'd want to consider, maybe also make it explicit each time, formally, instead of using english to explain refactorings:

p1.then( foo ).then( () => p2 ).then( bar ); // original
==
p1.then( foo ).then( constant( p2 ) ).then( bar ); // constant
== 
p1.then( foo ).then( ( v => () => v )( p2 ) ).then( bar ) // inline constant
==
p1.then( foo ).then( () => p2 ).then( bar ); // evaluate constant application to recover original

Anyways, just a thought. I understand this is supposed to be an informal book so no worries if this is too mathy - just something to consider so the reader gets a glimmer of the whole "reasoning about" thing and sees why purity can be so important later on.

  1. That _ in p1.then( foo ).then( _=>p2 ).then( bar ); may confuse some

I get the "why the underscore argument?" question a lot. Maybe a note that _ is often used to mean "ignored parameter" in FP would be good or just move to () => p2.

  1. "The advantage of currying here is being able to do something like curriedSum(1)(2)(3), which returns a function".

This line didn't quite drive home the distinction between partial and curry for me. I see the main difference/advantage is that currying is used at definition time and partialApplication is used "on the fly" by the caller. I suppose that's implied by the examples, but might be worthwhile to spell out since they are so similar.

  1. "Don't just assume that uncurry(curry(f)) has the same behavior as f".

This is true for some libs, but lots do strive to make that isomorphism / adjunction (an iso between homSets) work, which then gives rise to the reader/writer monads (and their respective comonads). In any case, I'd mention it's false for this implementation only since it is true for some other libs.

  1. Should it say something to the effect of "When currying, it's often useful to analyze argument position and put the "data" last". And "Usually one curries everywhere in this style". These techniques combined usually sidesteps the need for uncurry, partialRight, and reverseArgs".

I absolutely love how the printIf example ties in everything from the chapter. It is built up beautifully from the prior concepts. Although, having written code like this for a while, I found myself asking "why haven't I encountered the reverse/partialRight/uncurry pattern very often?"

I think it's two things:

  • When currying is on by default, one rarely needs to uncurry or partial
  • Argument order is usually defined for data to be last, therefore known args are at our finger tips and partialRight is almost never necessary. On rare occasions, like the when example, flip() usually does the trick.

So the common result in a ramda or haskell app would be something like:
var printIf = flip( when )( output );

With the full code being:

const when = R.curry(function when(predicate, fn, args) {
  if (predicate( args )) {
    return fn( args );
  }
});

function output(msg) {
  console.log( msg );
}

function isShortEnough(str) {
  return str.length <= 5;
}

var isLongEnough = not( isShortEnough );

var printIf = R.flip( when )( output );

var msg1 = "Hello";
var msg2 = msg1 + " World";

var printShort = printIf( isShortEnough );
var printLong = printIf( isLongEnough );

printShort( msg1 ); // Hello
printShort( msg2 );

printLong( msg1 );
printLong( msg2 ); // Hello World

The tools here are worthwhile and valid, I just don't end up encountering the situation much in day-to-day code for the reasons stated above.

I'm not sure what to do with all of these thoughts and ideas, but I'm happy to have shared them. Either way if you decide to adopt them or not, I won't have emotions about it; just wanted to share my brain dump after reading.

Again, great chapter!

Development Edit: Chapter 11

This chapter is pretty straightforward as well. There can't really be any organizational issues here, because it's a walkthrough of an extended example.

There are a lot of cross-refs in this chapter. You could make these links for the ebook.

"That <li> element (actually, a list of that element) is passed to getStockInfoChildElems(..), giving us three child <span> elements for the stock display info"
You lost me here. I don't see where the <li> elements are coming from. Unless they're introduced later in the chapter, and this section has been rearranged?

"Next, let's look at extractInfoChildElem:"
This should be extractInfoChildElemVal, right?

ES6 curry function in ch3

I am looking over the function and it seems odd. Is the line (nextCurried = prevArgs => performing an implied variable definition without var|let|const ? And if so, would that then be hoisted to the parent scope?

Chapter 2 equation - f(x) = 2x^2 + 3

Yes, I promise I've read the Contributions Guidelines.

I found this equation confusing, so I wonder if it needs an explanation. I'm actually not familiar with the symbol ^ - I've looked it up and it seems to be exponent, which I take as "to the power of". Yet, when I try it in the console (so based on JavaScript), it seems to act like a plus. So for 8^2 , I'd expect 64, but in the console, the answer is 10.

Anyway, the point is you've used an equation early on that's already flummoxed me and stopped me continuing, which is ironical given what the book is trying to do.

NB I don't have a strong programming background, but I did have a fairly strong mathematical education - although that was over 20 years ago and largely forgotten!

Development Edit: Chapter 8

Recursion is mentioned a few times in this chapter, so perhaps rearrange so the recursion chapter comes first? I'll need to revisit this after I see that chapter.
Edit: After having read Chapter 9, I can see there's not a ton of overlap between the chapters. If you want to swap 8 and 9, that would be a minor improvement to Chapter 8, because the handful of mentions of recursion would be clearer. Chapter 9 doesn't depend on any of the list content found in 8 (that I can see), so I don't think there's any harm done in swapping them.

Filtering-Out and Filtering-In section

I don't think you need this heading here. The heading basically applies to everything you've been saying in the "Filter" section up to this point. If you want to have a heading here because you're defining the solution, then I suggest you add a parallel heading earlier where you define the problem.

Looking for Lists section

"If this version is harder for you read right now than the original," Well, yeah, it is, so thanks for that.

Beyond Lists section

In your definition of binary search trees, you should probably mention the "binary" part (each node has no more than two children).

Publish to Medium?

Is it possible to publish a version of this book to Medium.com for easier consumption? I loved reading YDKJS, but from a consumption POV it was really hard to read as well as hard to keep my place on on GitHub. I know this may be asking for a bit for a free book, but I believe it would benefit your audience.

Chapter 2 Feedback

I just finished reading Chapter 2. It wasn't clear to me this was a chapter on JavaScript fundamentals. I kept expecting you to start mapping some of the features of functions to FP concepts, maybe in an overview fashion. As I read, I got more and more anxious with the mental tax of holding all this information "in memory" until the expected mapping began. For example, as I was reading about function arguments/parameters, I kept thinking, "Ok, I already know JavaScript, but why is this important?"

After I finished the chapter, I went back and re-read the beginning, thinking I must have overlooked something or misunderstood its purpose. All that to say, from my perspective, you should make it more clear at the start of the chapter you are covering JavaScript language features that will be important for learning FP patterns in the rest of the book.

Tech Edit: Chapter 5

Great chapter! I think it balances pragmatic with purist (no pun intended) well. I think this chapter did an amazing job of explaining purity and all the possible questions around it.

There weren't any technical mistakes as far as I could tell. The definitions were on point.

Just a few things:

  • Typo: "for them to understand to understand that line" -> "for them to understand that line"
  • Pure and impure are used to describe randomness, but those terms hadn't been defined at that point. Maybe a note?
  • In the purifying section, where we refactor to safer_fetchUserData, I think it's worth a mention that we hadn't actually purified it all the way (since ajax is impure). I only say this because so much of the chapter is focused on variables and mutation that a reminder might be welcome by this point.

There are a few small techniques for purity that I use (maybe they are mentioned in later chapters?)

  1. Separating side effects from pure code. This creates more pure/testable functions and untangles messy updates.
// intertwined
const renderBlog = function(post) {
const title = post.title
document.write(post.title)
const content = fromMarkdown(post.content)
document.write(content)
}

// separated
const writeToScreen = function(content) {
content.forEach(c => document.write(c))
}

// now this is pure and testable
const prepareContent = function(post) {
const title = post.title
const content = fromMarkdown(post.content)
return [title, content]
}

// composition of the pure/impure
const renderBlog = function(post) {
const content = prepareContent(post)
writeToScreen(content)
}

That's kind of a bad example (who uses document.write)...the point being if we separate side effects, we can extract more pure functions.

  1. Pushing side effects to the caller is a good strategy for purity. This is essentially what IO/Task do, but we can still get far without them.
// impure
const createServer = function(port) {
  const app = express()
  app.use(express.static('public'))
  app.listen(port)
}
createServer(3000)

vs

// pure
const createServer = function() {
  const app = express()
  app.use(express.static('public'))
  return app
}
const app = createServer()
app.listen(3000) // caller is now impure and our code is clean :)

or even

// pure
const createServer = function(port) {
  const app = express()
  app.use(express.static('public'))
  return () => app.listen(port)
}
const listen = createServer(3000)
listen() // caller is impure and port arg is preserved in refactor
  1. Usually worth a mention that throwing an error is not pure. This is a good motivation for Maybe later.

Anyways, that's all i have. Not at all essential, but I thought I'd put them out there.

Chapter 4 Abstraction example code error

comments[comments.length - 1] = txt;

The text says that this code "sticks the value at the end of the array", but note that this overwrites the last item already in the array (or if the array is empty it creates a property with a key of "-1").

This isn't relevant to the abstraction concept being discussed, but still it feels like an odd thing to do, so it's distracting.

Navigation between pages

@getify,

Wouldn't it be great, if we add links to previous and next chapters at end of each chapter (something like this: sravan-s@df0f3ae). Right now, I have to navigate back or type in the chapter name at the address bar. Or is there any simple navigation trick that I have missed?

Ch3 - questioning readability of point-free style

Hello,
I'm following along, and, as I look at this snippet:

var printIf = reverseArgs(
    uncurry( partialRight( when, output ) )
);

I start to wonder whether FP helps or not in writing more readable code. Is it just me or that's a hard to follow line? Is it just a matter of getting used to FP style and will sound obvious to me as my FP skills develop? That looks to me like something I would need to explain to some fellow team member, if I'll ever write anything like it!

What are your thoughts on this? Honestly, that piece of code alone is frightening me a bit, but maybe that's already one of those cases where you suggest that we stop and reconsider point(-ful?) style

Mention Ramda

Hi!

I understand the idea of explaining FP step-by-step with "homemade" examples. However, I suggest you to mention Ramda in later chapters when it comes to real applications.

Probably, you have a plan to publish all the external resources at the end of the book. Just wanted to make sure Ramda would be there, because it rocks and it is the most usable FP library out there for Javascript!

You could also create your own package with all those helpers and examples you coded, so people would be able to play with it rapidly.

Tech Edit: Chapter 2

  • This was an interesting section for me. It was mostly review, but then new FP ideas were intertwined: Declarative, Unary, Arity, Higher Order. Part of me wanted to skip it since I’m familiar with es2015, yet part of me knew it was going to be foundation for the rest of the book and I was afraid of missing the important intertwined areas. Anyways, I’m not sure how to handle that, but that was my experience.

  • The higher order function example is awesome. In teaching this stuff, I found a great number of people struggle with first class fn’s - they are just so used to writing things like ajax(url, function (result) { return f(result) }). Anyways, there are the this pitfalls and whatnot so maybe it’s worth putting a section in this primer somewhere…

  • The name/arrow section was very persuasive…I’m thinking hard about my own choices now :)

Concerning "Functions vs. Procedures"

Just reading the content you've added so far. This will be good, so thank you!

Wondering if you plan to bring up the side-effects part of functions versus procedures. Would that fit into that early section on the differences between the two? I could imagine it:

Excerpt (with added example):

You're probably most used to thinking of functions as general procedures. What is a procedure? An arbitrary collection of functionality. It may have inputs, it may not. It may have an output (return value), it may not. It may have side effects outside its operating scope, it may not.

But a function specifically takes input(s), and definitely has a return value. And, it always produces the same output when given the same input.

Hopefully not jumping in too early with this suggestion! If this isn't precisely part of the difference between the two, I'd like to know more about it, as I've always understood it to be core.

Tech Edit: Ch9

So hell yes. This was my favorite chapter so far!

Loved the in-depth coverage and explanations. I thought the visualizations were very nice.

I didn't find any technical issues - just maybe some stuff I noticed that you may or may not want to include:

  • The final sum PTC refactor differs in that it now returns undefined rather than 0 for an empty list. In fancy terms, we've removed the identity element, making it a semigroup operation rather than a monoidal one, which means we've lost safety.

  • The fib ptc/continutation refactor exploits the closure equivalence you explain in ch7: x is eq to () => x. Which i think is super neat and is the basis of many FP optimizations and amounts to (i think) a left kan extension in category theory.

  • Small typo we likely we'll need to use => we'll likely need to use

That's it!

Sign up for Editing assistance

Filing an issue to to track those who would like to volunteer to assist with editing. Kyle works very hard on these books and contributes volumes to the community, let's give him a hand!

If you'd like to help, this is the place to make that fact known!

Ch 2: `arguments` object not deprecated

In chapter 2, you state As of ES5, arguments is deprecated., but from the information I can find, the arguments object itself is not deprecated, but rather the property Function.arguments is.

MDN's recommendation from Deprecated and Obsolete Features is:

The caller and arguments [Function] properties are deprecated, because they leak the function caller. Instead of the arguments property, you should use the arguments object inside function closures.

If I'm mistaken, do you have any resources showing the deprecation of the arguments object?

Add additional resource

Hey, @getify I recently emailed you about my repo Functional-Programming-Exercises and was asked to file this issue. I would love for my repo to be a useful resource to help new developers, like myself, learn functional programming.

Please, when you have the time review the code, make suggestions, and send requests over so my repo can be a more suitable guide for beginners in FP.

  • Add repo to README, and possibly Chapter 1 "resources"

Problem with partialRight ?

In Chapter 3, "All For One", you say :

["1","2","3"].map( parseInt );
// [1,NaN,NaN]
["1","2","3"].map( unary( parseInt ) );
// [1,2,3]

And this scan also be solved with partialRight(parseInt,10).

However, when I tested it:

["1","2","3"].map( partialRight(parseInt,10) );
// [1,NaN,NaN]

I believe it's because partialRight does append its partial argument to the end of the arguments list. It couldn't replace arguments (the radix in this case) because it has no sense of arity.

Development Edit: Chapter 9

Perhaps it's because of my more formal education on FP, but I regard recursion as a core tenet of FP, and if anything, I think this intro could emphasize that fact more than it does.

Definition section

I think your second illustration could be made clearer if you had a visual representation of the call stack. Then you could show it unwinding. I can see you want to defer the discussion of the call stack until later in the chapter, but a cursory use of it here would make the illustration clearer.

Mutual recursion section

"While these mutual recursion examples shown are rather contrived, there are more complex use cases where mutual recursion can be very helpful." This sentence begs for a "such as" at the end of it. You don't have to explain in detail how it works, but just citing the use cases would provide some grounding.

Declarative Recursion section

In your binary tree example at the end, it probably wouldn't hurt to mention that just about anything you want to do with a binary tree is better done with recursion.

Proper Tail Calls section

"It may be possible to achieve PTC from a multiple-recursive algorithm by splitting each into separate function calls, where each is expressed respectively in PTC form."
Is that something worth showing, or would it be too complicated?

Development Edit: Chapter 3

Based on the conversation we had earlier this week, and reading this now, it's clear that Chapter 2 and 3 are intertwined. I think combining them would probably be a good choice, and there are clear signposts in the current 3 where chunks from 2 could go -- I've highlighted these in my comments. The trick will be doing this without blowing up the merged chapter to gargantuan proportions. My suggestion for that would be to keep the asides and edge cases to a minimum in the transferred pieces.

The intro could be beefed up some. The promise here is "I'll show you several techniques for creating functions with a single parameter," that much is clear. A reminder of why that's good, or some use-cases where that could come in handy, would engage the reader more.

"Some Now, Some Later" section
"Notice the references to fn and presetArgs inside this inner function? How does that work?" -- if you're thinking about merging Chapters 2 and 3, this would be a place where you could move the closure discussion.

"See how important understanding closure is?"
A small point, but a declarative sentence: "This is why understanding closure is critical," or similar, reads better. Rhetorical questions can become frustrating to the reader, because the question assumes the reader's response.

"One at a Time" section
"This technique is called currying." -- I'd add an intensifier on this, something like, "You're going to see this a lot."

"We're going to use some tricks from Chapter 2."
As we discussed, bringing in the Chapter 2 techniques at this point may be more useful than introducing them in advance and asking the reader to remember them (or go back and re-read).

"Why Currying And Partial Application?" -- when I'm asking a question in my head, and that question is the very next heading, that's a good sign.

"One On One" section
This discussion of how identity(..) can be used when splitting a string -- does that meet the readability standard? It works, but it doesn't seem immediately obvious to the reader why it works.

"Spread 'Em Out" section
"In Chapter 2, we briefly looked at parameter array destructuring."
Once again, if you wanted to talk about destructuring here instead of Chapter 2, that would be a valid choice.

"Order Matters" section
Not to make this a theme, but you could discuss the named arguments from Chapter 2 here.

I like the "don't go overboard with this stuff" warnings in appropriate places in this chapter.

"No Points" section
I think there's a "why" missing from this section. I get that point-free style is considered a good thing within traditional FP, but why is it a particularly good idea in JS, or for this book's audience? What do you gain from it? This is especially important if you're asking readers to make a value judgment on whether it's useful for them, because while your final example is fairly readable, it does rely on several other utilities which the reader has to understand first.

Summary -- You're summarizing the topics, which is important. You should also remind readers that you've fulfilled the promise of showing them how to create single-parameter functions, and why that's a good thing. Specifically, give me the connection to composition, which comes in the next chapter.

why favor old style loops over (es5) alternatives?

I'm reading trough the chapters as you are putting them on. I really like what I'm reading.
Just wondering why you favor (for brevity sake I'm just using the ES6 arrow function in stead of the full versions) this:

  var uncurry =
       fn =>
           (...args) => {
               var ret = fn;

               for (let i = 0; i < args.length; i++) {
                   ret = ret( args[i] );
               }

               return ret;
           };

over:

const uncurry = fn => 
    (...args) => 
       args.reduce(
            (ret,cur) => ret(cur),
            fn
       );

The .map(), .reduce() and so on seem a much better fit to explain a functional coding style.

Tech Edit: Chapter 7

There is some brilliant stuff in this chapter. I really like the church encodings in stuff like trackEvent which gives an intuition for how the state monad works.

The summary is so damn good. Just some corrections on the isomorphic stuff:

  • The next time you hear someone say "X is isomorphic with Y", what they mean is, "X and Y can be converted from either one to the other in either direction, and maintain the same behavior regardless.

But "maintain the same behavior" is a little off - usually that's precisely the point e.g. Array<Char> is isomorphic to String, but they have different behavior. I'd say "maintain the same information".

Also, we usually we say "X is isomorphic /to/ Y" :)

  • "they are isomorphisms of each other" => "they are isomorphic to each other"

  • minor typo more similar than dislike

That's all it got! Great chapter.

Development Edit: Appendixes

I don't have a lot to say about the appendixes, so I'm just going to combine them into one issue.

Appendix A: Really strong. The flow here is very clear, even though it's a complicated topic. I can't find anything to suggest on this one. Note, however, that you have one TODO left in there.

Appendix B: I'm going to question the purpose of this appendix being here. Not because I think monads are too complex for this book; they're not. But because I'm not seeing enough information here to allow me to use monads in a practical way. Maybe I'm having trouble getting past the abstract nature, but I don't see a problem in this appendix that monads will help me solve. It's an appendix, and appendixes are optional, so I'm not going to recommend strongly that you cut it, but I would suggest that you make the benefit to the reader more clear in the introduction.

Also, I'm a little fuzzy on what Just() and ap() are supposed to do; I understand that they're abstract concepts, but they seem to have some intended purpose. I get what Nothing() is for, and I assume that Just() is some sort of identity function, or simply returns its value, but that's not stated. I can't figure out from context what ap() is supposed to be for.

Appendix C: This is mostly resources, so not much to say here. However, you provide a list of nine libraries, and discuss three of them in depth. You should probably mention that you're only talking about a few of them in detail, so readers won't think you've left something out.

Development edit: Chapter 2

Intro -- good start. I'm seeing the promise here: I'll learn to work with functions. A better promise would tell me exactly what I'll do with functions. There's more to functions than I know now; OK, I get that. Tell me in a couple of sentences what I'll be able to DO after this chapter that I can't do now.

That first figure is bugging me a bit because the axes aren't equal. It's tangential to your point, but expect people to complain about it.

"What Is a Function?" section
Did you answer the question in this section? It's implied below that a function takes an input and returns a value. Is that the canonical definition you're going for here? If so, I suggest you state it definitively.

"Function vs Procedure" section -- show me some code. Give me an example so I can see what you're talking about.

Also, do you want to mention side effects in this section, or is that on the list of functional terminology you're avoiding? I think it makes sense to say that procedures have side effects (probably ONLY have side effects, and that's the point of them), whereas functions don't (shouldn't).

"Function Input" section
"the result of that expression, 6"
I'd phrase this as "the result of a * 2, which is 6" just to be clear.

"Counting Inputs" section
What's the point of this discussion on arity? I'm not seeing how it serves the goal of getting me closer to functional.

The lengthy discussion of the ... operator seems ES6 focused, which is fine right now because you're writing it right now, but be aware that this content will become dated more quickly than the rest of the book.

I'm really lost as to the point of this section until I got to this, hiding in the middle:
"But now we start to uncover the first bits of a principle that we'll come back to many more times in this text: declarative code often communicates more cleanly than imperative code."

If that's what you're trying to say, I suggest saying so up front, so readers can be looking for it. It's one thing to leave the reader in the dark for a couple of paragraphs to get to the "aha" moment, but the discussion of arity, the ... operator, and destructuring goes on for a while before it gets to the point about declarative code.

I think the fundamental problem is that I think you're saying "this is declarative and inherently more readable:

function foo( [x,y,...args] ) {
    // ..
}

foo( [1,2,3] );

Than this, which is imperative and inherently unreadable:

function foo(params) {
    var x = params[0];
    var y = params[1];
    var args = params.slice( 2 );

    // ..
}

This is the sort of side-by-side comparison I was arguing for in Chapter 1, but it runs up against an experience problem. If readers aren't familiar with the ... operator from having used ES6, they might find it very unnatural and unreadable. The stack of manual assignments, while long and awkward, is pretty readable.

This paragraph seems to be the crux of your point in this section:
"Declarative code, like destructuring in the earlier snippet, focuses on what the outcome of a piece of code should be. Imperative code, like the manual assignments just shown, focuses more on how to get the outcome. If you later read the code, you have to mentally execute it to understand the desired outcome. The outcome is coded there, but it's not as clear."

But I'm not sure you're adequately making your case to someone with a habit of imperative programming, to whom the assignment snippet is natural to read. I think you need to make the point better that "the outcome" and "how you get to the outcome" are two different things, and that's not clear yet. You need to define what you mean by "the outcome."

"Functions Varying by Input" section
I get what you're saying in this section -- that function overloading is dangerous if you sacrifice readability for convenience. But what does that have to do with FP? I don't see the connection.

"Function Output" section
Tip regarding "separated into two or more smaller single-purpose functions"
Normally, I'd suggest giving an example, because that would make your point clearer, but this is just a tip, so maybe it's not appropriate here.

"Functions of Functions" section
Now we're getting FP! It hasn't been clear so far in this chapter that this is what we're leading up to. Maybe spend some more time on the concept that functions can take and return functions? That's pretty fundamental to FP as I understand it, and can be tricky to grasp for beginners.

"What's This" section
If the conclusion is "don't use this," then why spend time discussing it? I don't think it's necessary to spend time on the specific reasons why using this is a bad idea.

Development Edit: Chapter 10

Not a ton to say in this chapter. The organization is pretty straightforward, leading to the discussion of observables at the end.

You may want to mention observables and RxJS in the introduction, because that's where the chapter is heading. As far as I can tell, there's no other structure that will allow lazy mapping in the way you've laid it out here, so you should warn readers that you're dealing with a library outside the ECMA spec, even if it is one that everybody's heard of, and uses.

You might also consider providing a reference to an outside source where readers can learn more about RxJS. (This one, for example: https://pragprog.com/book/smreactjs/reactive-programming-with-rxjs )

There are a bunch of short paragraphs in this chapter that could be combined without harming the meaning.

Reducing Time section

I suggest bumping this up to a level-1 heading.

Unassigned variables should be compared to undefined rather than null

Yes, I promise I've read the Contributions Guidelines.

Admittedly, this is a minor quibble. But since this is a teaching text I'll mention it for your consideration.

In Chapter 2, the section on early returns, your example program that has been refactored to have a single return, gates each assignment to retValue with an if (retValue == null && ...). Since no assignment has ever been made to retValue, it's actual value is undefined and it is coerced into a null by the equality operator. This works, but seems unnecessarily fragile when you could either explicitly set retValue = null in your declaration, or you could compare directly to undefined. Any time == would cause my program to do one thing and === would cause my program to do another, I become a little concerned.

Ch5: error in indepotent example

var hist = document.getElementById( "orderHistory" )

// idempotent:
hist.orderHistory.innerHTML = order.historyText

// non-idempotent:
var update = document.createTextNode( order.latestUpdate )
hist.orderHistory.appendChild( update )

should be:

var hist = document.getElementById( "orderHistory" )

// idempotent:
hist.innerHTML = order.historyText;

// non-idempotent:
var update = document.createTextNode( order.latestUpdate );
hist.appendChild( update );

Tech Edit: Chapter 1

Nailed it. Two things:

  • "It's been around almost as long as any programming has been around" felt a little awkward, but perhaps I read it incorrectly. Maybe "programming paradigm" or "any"
  • Frisbee => Frisby :)

Tech Edit: Chapter 4

Another chapter where the code is flawless and examples are clear. I'm writing my thoughts, but again, this is not as much a tech edit as it is an opinionated brain dump:

This was an interesting chapter where fp-lite vs fp-dark™ is concerned. In pure fp, compose is everything since, in a pure function, one can only ever pass output to the next input or it is lost. It is the only way to program; category theory is based entirely on it.

So in fp-lite, I’m trying to gauge its utility and purpose. After this chapter, I see compose as a “workflow builder”. The main, high level data flow of one’s application. Is that accurate? The last example does a very nice job of that.

Anyways, I foresee some purist quibbles about compose should be mathematical function composition which is unary on its first argument too. That doesn’t matter much to me, but thought I’d mention it to save some angry reddit thread.

You did an amazing job of explaining compose and the candy factory was a spot on analogy (an oompa loompa song about impurity might have really driven it home…).

I think people look to your writing specifically because you dive deep into topics and show the interworkings. So no criticism of the various implementation details.

“The slight performance advantage to pipe(..)”
I’m concerned that line might give readers the impression that pipe() is always more performant and henceforth spawn an army of pipers over composers. But maybe not. In any case, it’s only more performant in our implementation, but not true in general.

Loved the abstraction stuff. Not sure if it’s worth a mention that, due to associativity, one can always “extract method” from a composition:

const app = compose(fourth, third, second, first)
==
const middle = compose(third, second)
const app = compose(fourth, middle, first)

And lastly, pre-composing and post-composing via partialRight/partialLeft is rad. On top of this tower of abstractions, I’ve been using profunctors for that, which has the same effect, but comes with considerably more overhead.

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.