Coder Social home page Coder Social logo

mostlyadequate / mostly-adequate-guide Goto Github PK

View Code? Open in Web Editor NEW
23.2K 552.0 1.9K 5.3 MB

Mostly adequate guide to FP (in javascript)

License: Other

HTML 0.78% JavaScript 98.47% CSS 0.14% Perl 0.62%
javascript functional-programming tutorial reactive-programming

mostly-adequate-guide's People

Contributors

alaarmann avatar alvarogarcia7 avatar ayeseeem avatar ceddlyburge avatar christianhg avatar christiantakle avatar danielpintilei avatar datenreisender avatar eliranmal avatar eush77 avatar framp avatar guumaster avatar jazmit avatar kdamball avatar kottkrig avatar ktorz avatar legomushroom avatar manuganji avatar matt-paul avatar mdavidgreen avatar monkpit avatar okaybenji avatar pete-murphy avatar pmuellr avatar qm3ster avatar syzer avatar tehshrike avatar thurt avatar tonyday avatar wulfmeister 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

mostly-adequate-guide's Issues

Monad Exercise 2 answer differs on Windows

I think the answer to exercise 2 of the monads chapter is different when running on Windows due to the path separators.

Answer given is:
var ex2 = _.compose(chain(_.compose(pureLog, _.last, split('/'))), getFile);

But for me the test fails like this:

AssertionError: expected 'logged D:\\Users\\jschreuder\\Documents\\mostly-adequate-guide\\code\\part2_exercises\\exercises\\monads\\monad_exercises.js' to equal 'logged monad_exercises.js'

I had to split on \ to get the test to pass:
var ex2 = _.compose(chain(_.compose(pureLog, _.last, split('\\'))), getFile);

Might be worth switching up this exercise with some other task to avoid cross platform issues?

Rename map to fmap

What do you think about renaming map to fmap for functors. So we can eliminate confusion in this. The point is that map usually used to map collections, not single values.

Expound on functor map type signature

In chapter 8 I found this type signature:

map :: Functor f => (a -> b) -> f a -> f b

While the introductory chapter on Hindley-Milner was easy to follow, I think it doesn't cover the above signature. The problem is the f a and f b part. What does that mean? f multiplied by a? Or f applied to a? Or something else? Maybe you could elaborate on this a little.

Oh, and by the way, thanks for your impressive work so far. It's a joy to read and I like how concise you present the main principles.

Wrong definition of partial order in chapter 5

Not sure if it's wrong, or I misunderstood something.

Here is the quote:

What are some other categories, you ask? Well, we can define one for directed graphs with nodes being objects, edges being morphisms, and composition just being path concatenation. We can define one for Numbers with > as morphisms and 0 as identity[^actually any partial or total order can be a category]. There are heaps of categories, but for the purposes of this book, we'll only concern ourselves with the one defined above. We have sufficiently skimmed the surface and must move on.

I think the morphisms in a partial order with numbers should be <=, the identity should be also <= (any number less or equal to itself), and 0 could be the initial object (in case we don't include negative numbers).

Please check definition of partial order from Categories Great and Small, and of initial object from Products and Coproducts โ€” chapters from "Category Theory for Programmers" by @BartoszMilewski

Relicense to CC-BY-SA?

Is there any chance I can convince you to relicense this work to CC-BY-SA instead of what it is currently? Both NC and ND have several problems you may not be aware of - you can read about them here and here.

Replace as many as possible custom fn's with `_`

Prior definitions casually used throughout is causing confusion - especially in the case of compose where we define a non variadic version and then proceed to use the variadic one for the rest of the book.

Should replace as much as possible with ramda or lodash-fp

GitBook

The books seems to be great, but the format without good navigation is bad. Instead of using simple markdown files the GitBook format could be used.

Impure function mistake

Hi!
Its duplicating of my email via gitbook.

In Chapter 6 following function seems to be impure:

var img = function (url) {
  return $('<img />', { src: url });
};

As I've understood from previous chapters img is impure because it relies on $ which isnt directly passed via arguments. But in the text there is nothing about img impurity so some folks can assume its pure.

Am I right?

PDF version

Are there any plans to generate one PDF out of this files? It'll be handy to have it also in such format

Maybe chain / join

Hello, thanks for great book: eyes opening!

I've got a doubt concerning Maybe.join (thus Maybe.chain).

When I do f(a).map(g)

Given:

f :: a โ†’ Maybe(a)
g :: a โ†’ Maybe(a)

Then:

  • If f and g succeeds, return type is Maybe(Maybe(a))
  • If f fails, g isn't executed, return type is Maybe(null)

So when I join I either have a Maybe(a) or null... which isn't convenient for later processing.

I fixed it by writing: Maybe.join = isNothing() ? Maybe.of(null) : __value

Is that correct? Is there something else I missed or a better way?

Thanks!

Using ES6

What you think about rewriting all the code examples in the book in ES6? It feels more functional than ES5.

nom de plume

Is it Professor Frisby (per the cover) or Risby (chapter 1)? Or is the cover meant to be a portmanteau of F. Risby? Is it intended to create an air of mystery? Is he actually a Professor?

I'm going to sit here and be quiet now.

Add hint about ramda to Exercise in Chapter 4

It would help a lot, if you could add a note about ramda and what it does before the exercise in chapter 4. I was quite confused, because I didn't know that split() etc. are provided as curried functions.

Add tests for exercises

Requesting to add tests for exercises in the book. So people can test their solutions against these tests.

ch3 misisng Immutable declaration

in line:
var jobe = Immutable.Map({name:"Jobe", hp:20, team: "red"})
var Immutable = require('immutable');
is missing from code
maybe better to use Set, since is implemented in all modern browsers?

Why don't we need isSameTeam (ch 3)?

Chapter 3 reads "Since our data is immutable, we can simply replace the teams with their actual value", and then the isSameTeam is removed. Doesn't that change the api, as teammates can now punch each other?

DbConnection or IO(DbConnection)

Hi

[@DrBoolean - Thank you. Great content and (for my taste) an eminently readable style. It is rare for technical book to make me chuckle.]

In Chapter 8 I am battling to figure out how connectDb has a type of Config -> Either(Error, IO(DbConnection)) given that Postgres.connect only has a type of Url -> DbConnection.
How does the DbConnection become an IO(DbConnection) ?
Am I confused or is there an IO.for missing somewhere ?

Ch.8 withdraw and maybe

In chapter 8, the part concerning withdrawing from an account using maybes, uses two functions I can not find being defined anywhere. The line:

var finishTransaction = compose(remainingBalance, updateLedger);

Were those functions left out with the intent to not run this code or were they left to the reader to implement?

Seagulls example is confusing to me

It would help if you would explain why the non-functional example got the wrong answer. I'm not sure what it is trying to do. It would help if you had an English explanation of what conjoin and breed are supposed to do, since they seem (to me) to simply be doing the wrong thing, if you are really treating it as a simplified representation of the real world, rather than purely abstract mathematical operations.

In trying to process it, I started writing out something like this (which might be nice to have in your writeup)....

First, I expanded this:
flock_a.conjoin(flock_c).breed(flock_b).conjoin(flock_a.breed(flock_b))

to this:

flock_a.conjoin(flock_c)
// flock_a: 4, flock_c: 0

flock_a.breed(flock_b)
// flock_a: 4, flock_b: 2

flock_a.breed(flock_b)
// flock_a: 8, flock_b: 2

flock_a.conjoin(flock_a)
// flock_a: 32

Then, in English:

flock_a.conjoin(flock_c)

flock a, which has 4 seagulls, joins with flock c, which has 0 seagulls, which causes flock a to have its seagulls increased by the number of seagulls in flock b, resulting in flock a still having 4 seagulls and flock c unaffected, still having zero seagulls.

flock_a.breed(flock_b)

Then flock a (still 4 seagulls) breeds with flock b, which has 2 seagulls. This results in flock a's number of seagulls being multiplied by the number of seagulls in flock b, leaving b unaffected. Flock a will now have 8 seagulls, with b still having 2 seagulls.

flock_a.breed(flock_b)

Now flock a (having 8 seagulls) again breeds with flock b (having 2 seagulls). This results in flock a having 16 seagulls, and flock b remains with 2 seagulls.

flock_a.conjoin(flock_a )

Now flock a conjoins with itself, doubling its numbers to 32.

I notice that conjoin does not set other.seagulls to zero (you are adding the seagulls to another flock, but still leaving them in their existing flock), and breed does not add the product of breeding to the existing seagulls (i.e. all the parents in "this" are killed by the breeding). Also it seems wrong to use multiplication at all to represent breeding in this way, it doesn't make sense. These seem to be logical errors, but are somewhat masked by other things (such as having flock_c having zero members to begin with).

However, it seems the most egregious error is from having a flock conjoin with itself, which doubles its numbers.

Without any sort of English translation or other breakdown of what you are trying to do, it is extremely difficult to tell what it is.

At least with the OO approach, I can figure out what the answer actually represents (the number of seagulls in flock a), and see why it seems to be incorrect. With the functional approach, "result" may be what you consider correct, but I have no idea what that value actually represents.

EPUB errors as 'corrupt' in iBooks

After adding the ePub to iBooks, either downloaded from Gitbook or built manually, on open, iBooks reports that "This file is corrupt" and closes the book for reading.

wrong definition of curry

shouldnt curry be defined as

var curry = require('lodash').curry

and not as

var curry = require('lodash.curry')

Answers to examples

Would be nice to have answers to the examples for each chapter. Hard to know if one has grasped the concept without knowing if we've completed the example correctly!

Also, this is great stuff!! Thank you!

Curry Exercise 2: filterQs does not, in fact, filter Q's

When the filterQs function from Curry Exercise 2 is applied to test array (['quick', 'camels', 'quarry', 'over', 'quails']) it returns the same array unchanged.

The cause of this is the match function which is used by filterQs. It returns empty array when the regexp and string to which it is being applied does not match each other. Empty array is considered truthy, so the Ramda's filter does not filter anything.

I made provided test pass by changing the function to this:
var filterQs = _.reject(_.compose(_.isEmpty, _.match(/q/i)));

But this is probably not the best way to solve the exercise, as composition is subject of the next chapter.

As possible solution, the Ramda's match can be replaced with the match from the support module, so the exercise will look like this:

// Exercise 2
//==============
// Refactor to remove all arguments by partially applying the functions
// Use the provided _match function

// LEAVE BE:
var _match = _.curry(function(what, x) { return x.match(what); });

// REFACTOR THIS ONE:
var filterQs = function(xs) {
  return _.filter(function(x){ return _match(/q/i, x);  }, xs);
};

is fastestCar exercise answer pointfree?

I'm new to the pointfree concept, so I'm wondering if I'm misunderstanding, or reading too deeply into the definition of pointfree.

It means functions that never mention the data upon which they operate.

var fastestCar = _.compose(append(' is the fastest'),
                           _.prop('name'),
                           _.last,
                           _.sortBy(_.prop('horsepower')))

In this example, the function is aware of the argument's structure (properties name and horsepower), is this still considered pointfree?

`compose(id, f) == compose(f, id) == f` evaluates to false in JavaScript (chapter 5)

For 2 reasons actually :)

  1. (compose(f, id) == f) === false because even though functions are equivalent, JavaScript can't detect that equality.
  2. After compose(f, id) == f evaluates to false we are comparing compose(id, f) and false, which is also false.

This line might be correct as a pseudo code, but presence of var suggest that it's a JavaScript code.

HM reduce signature

In Chapter 7, it would be helpful to give a worded explanation about the reduce signature

//  reduce :: (b -> a -> b) -> b -> [a] -> b

Semicolons

Would you like some help adding semicolons to your code examples, or do you feel strongly about not using them? I notice you tend to leave them out in a lot of cases, but it's done inconsistently, so I wasn't sure what your intention was.

Thanks!

Thanks for this awesome book - and kudos for picking up JS for teaching FP! I have two quick suggestions that might help -

  1. ES6 - Features like arrow functions, destructuring, generators etc are quite suited, in my opinion, for cases like this where you can write concise pure functions. I think using these features for code samples / exercises in book would be quite worthwhile.
[1, 2, 3, 4, 5].map((x) => x * x).reduce((a, b) => a + b)
  1. Gitbook - Gitbook is a fantastic format for publishing your books. It takes markdown files and generates beautiful books that look great on all devices. You should definitely consider publishing this guide on Gitbook!

Please share your thoughts on what you think about these ideas. Lastly, I'll be more than happy to send in PRs if you prefer.

Thanks again for writing this wonderful guide! ๐Ÿป

Disclosure: I'm in no way associated with Gitbook; just a happy reader.

Practical benefits of using pure future returning functions?

I understand the benefits of having synchronous functions be pure functions (in any language), and I think I understand the necessity of having pure monadic functions in Haskell and having the runtime manage the side effects.

But within JavaScript's semantics, I don't understand how making future-returning functions to be pure would be beneficial.

Consider this snippet. f() is pure and g() is not:

var Promise = require('Promise');

// f :: a -> _ -> Promise Error Number
function f(a) {
    return function(){
        return new Promise(function(resolve){
            resolve(localStorage.getItem(a));
        });
    }
}

// g :: a -> Promise Error Number
function g(a) {
    return new Promise(function(resolve){
        resolve(localStorage.getItem(a));
    });
}

f() returns a thunk of a Promise. It doesn't do any execution unless we run the thunk. So it almost acts like a Task from 'folktale/data.task'. g() on the other hand starts executing right away.

Now, what's the practical benefit of using f() instead of g()? Because, the thunk returned from f() doesn't really give us any insight into what it plans to do. And we're planning to run that thunk right away anyway.

Or put another way: If we were to use a function like f() or g() as an action creator in a flux architecture, how would we benefit from using f()? What features/assurances/properties would it make possible?

Btw, I'm intentionally not using data.task here because my question is not about the benefits of using Tasks instead of Promises. It's only about having pure future-returning functions vs impure ones.

OO Seagulls

Hi,
i have just started to read your book, thank you for it !
However, i was a bit disturbed by the example of oo code you wrote in the "flock of seagulls" part.
This part is supposed to show some advantages of FP over OO, but i think it's demonstrating how NOT to code in OO !

As you wrote :

Contrast this with our absurd object version which ignores built in functions and data types in order > to model the "real world".

I don't know what it's supposed to model, but it's not the real world !
You are instantiating three Flock objects, each with an initial size. I'm not sure instantiating a zero sized flock (as you did with flock_c) means anything in real life, i probably would have forced the constructor to throw when passing zero as a parameter or to return undefined, but that's not the important point there.
The big problem comes from the actual heart of the program, as you call it the "ghastly abomination".
Here it is :

var result = flock_a.conjoin(flock_c).breed(flock_b).conjoin(flock_a.breed(flock_b)).seagulls;

What the heck is this supposed to mean ?
What real world problem is this supposed to represent ?
Let's try to understand:

First Step

flock_a join with flock_c (remember, it's a zero sized flock, if that mean anything).
So the flocks are joining, they becomes one only flock, the members of flock_c are coming into flock_a or the opposite. Is it not a very good case for state modification ? What does it mean to take two flocks as parameters and get a new flock ? Does it really make sense to make the flocks immutable ? After flock_c has joined flock_a, is there still a flock_c ? Can we say that flock_a has not changed ? (actually it has not since flock_c has zero members, but let's pretend the opposite).
Is the adding of flock_c members really an addition of two immutable value or the mutation of flock_a state and the disapearance of flock_c ?
I vote for this last propostion, and i write this operation like this :

flock_a.conjoin(flock_c);

How could this be simpler ?
I could even add a method on Flock that would put the population at zero when consumed by Flock.conjoin()
Let's do that.

Flock.prototype.empties = function(){
  this.seagulls = 0;
}

And modify conjoin accordingly:

Flock.prototype.conjoin = function(other){
  this.seagulls += other.seagulls;
  other.empties();
}

And we don't return this, because it violate the law of demeter and makes your code a mess.

2nd step:

It seams that the result of flock_a joining force with flock_c, which we choose to still call flock_a, is now doing some breeding business with flock_b.
From your defintion in the class, we understand that after a round of reproduction, the child stay with the object whose breeding method was called and the other parent which continue on his own doesn't keep parental authority. So the flock_a population is again modified, and flock_b population doesn't change. Easy !

flock_a.breed(flock_b);

How could this be simpler ?

3rd step :

Now the resulting flock (again flock_a) is joining with the result of flock_a.breed(flock_b) which is also flock_a.... Wow wow wow, stop where you are ! What does it mean in the real world to join a flock with itself ??? I don't get it, are you just counting seagulls or are you breeding/joining them ?

Ok, perhaps i have not understood the problem correctly, when two flocks breed, they are producing a completely new Flock and are themselves unmodified.
But then the breed method is not correct and should be rewritten like this:

Flock.prototype.breed = function(other) {
  return new Flock(this.seagulls * other.seagulls);
};

And that changes everything !
Let's reconsider each steps with this new information.

Step1

flock_a.conjoin(flock_c); // no change flock_a = 4

Step2

flock_d = flock_a.breed(flock_b) // flock_d = 8; flock_a = 4; flock_b = 2;

Step3

//flock_a.breed(flock_b) return a new Flock which size is 4x2 = 8
//which will then join with flock_a
flock_a.conjoin(flock_a.breed(flock_b)) // flock_a = 8 + 4 = 12; flock_b = 2

Now it's finished, we have three discrete flocks, flock_a whose size is 12, flock_b whose size is still 2, flock_d of size 8 (and we still have the fantom flock_c of size 0).

Now, let's enjoy some functionnal programming ;)

var total = [flock_a, flock_b, flock_c, flock_d].reduce(function(total, flock){
  return total + flock.seagulls;
},0);

Which gives us a total of 22 ! Not 16, not 32, 22 ! Unless i made a mistake.

I still think that good OO is very handy when modeling reality.

Complete source code to be sure we are on the same page :

var Flock = function(n) {
  "use strict";
  this.seagulls = n;
};

Flock.prototype.empties = function(){
  "use strict";
  this.seagulls = 0;
};

Flock.prototype.conjoin = function(other){
  "use strict";
  this.seagulls += other.seagulls;
  other.empties();
};

Flock.prototype.breed = function(other) {
  return new Flock(this.seagulls * other.seagulls);
};

var flock_a = new Flock(4);
var flock_b = new Flock(2);
var flock_c = new Flock(0);

flock_a.conjoin(flock_c);

var flock_d = flock_a.breed(flock_b);

flock_a.conjoin(flock_a.breed(flock_b));

var total = [flock_a, flock_b, flock_c, flock_d].reduce(function(total, flock){
  return total + flock.seagulls;
},0);

console.log(total);

Thank you for your attention !

Lack of real world examples

I've done reading all available chapters in this book and I think that this is the best available guide about FP ever. But the problem is that like others it miss real world examples.
I'm requesting to add chapter with an implementation of some non trivial application, that uses all the staff explained in this books. I suggest to use more complex example than flickr.

How does the reduce call work in the reverse() example?

I can't find an implementation of reduce() that this line of code works with from your example:

var reverse = reduce(function(acc, x){ return [x].concat(acc); }, []);

Is it a typo or can you provide a link that would explain how this reverse function operates?

And, to demonstrate my further confusion, shouldn't reverse be in the form of a composable pure function with one argument, as in reverse=function(x) {..} in order to be used with compose?

BlogController example misses different "this" binding

ch2.md:109 equates the verbose and concise versions of BlogController. But in the verbose version, won't index be run with a "this"-context of Views, whereas in the concise version, index would be run in the "this"-context of BlogController?

That, then, is an important difference, particularly if Views.index uses any state of "this". While that may not fit the vision for functional programming, it's likely a reality that BlogController must accommodate in the broader world of mixed-paradigm programming.

This general concept is acknowledged later, but perhaps the caveat should be acknowledged sooner?

IO in Chapter 8

The IO functor in chapter 8 is not working for me. When I console.log the output, I just get IO{}

edit: I just figured out that I needed to call __value() to get the result

lodash-fp

Hey Brian! I noticed a couple lodash mentions and thought you'd dig lodash-fp since its the auto-curried iteratee-first data-last flavor of lodash which fits a bit more with the text.

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.