Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added :lang= annotations around all code blocks #96

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 45 additions & 34 deletions manuscript/markdown/Functions/args-again.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,57 @@ As we've discussed, when a function is applied to arguments (or "called"), JavaS

You should never attempt to define your own bindings against these names. Consider them read-only at all times. The first is called `this` and it is bound to something called the function's [context](#context). We will explore that when we start discussing objects and classes. The second is very interesting, it's called `arguments`, and the most interesting thing about it is that it contains a list of arguments passed to the function:

function plus (a, b) {
return arguments[0] + arguments[1]
}

plus(2,3)
//=> 5

{:lang="js"}
~~~~~~~~
function plus (a, b) {
return arguments[0] + arguments[1]
}

plus(2,3)
//=> 5
~~~~~~~~
Although `arguments` looks like an array, it isn't an array:[^pojo] It's more like an object[^pojo] that happens to bind some values to properties with names that look like integers starting with zero:

function args (a, b) {
return arguments
}

args(2,3)
//=> { '0': 2, '1': 3 }
{:lang="js"}
~~~~~~~~
function args (a, b) {
return arguments
}

args(2,3)
//=> { '0': 2, '1': 3 }
~~~~~~~~

`arguments` always contains all of the arguments passed to a function, regardless of how many are declared. Therefore, we can write `plus` like this:

function plus () {
return arguments[0] + arguments[1]
}

plus(2,3)
//=> 5
{:lang="js"}
~~~~~~~~
function plus () {
return arguments[0] + arguments[1]
}

plus(2,3)
//=> 5
~~~~~~~~

When discussing objects, we'll discuss properties in more depth. Here's something interesting about `arguments`:

function howMany () {
return arguments['length']
}

howMany()
//=> 0

howMany('hello')
//=> 1

howMany('sharks', 'are', 'apex', 'predators')
//=> 4

{:lang="js"}
~~~~~~~~
function howMany () {
return arguments['length']
}

howMany()
//=> 0

howMany('hello')
//=> 1

howMany('sharks', 'are', 'apex', 'predators')
//=> 4
~~~~~~~~

The most common use of the `arguments` binding is to build functions that can take a variable number of arguments. We'll see it used in many of the recipes, starting off with [partial application](#simple-partial) and [ellipses](#ellipses).
[^pojo]: We'll look at [arrays](#arrays) and [plain old javascript objects](#objects) in depth later.

[^pojo]: We'll look at [arrays](#arrays) and [plain old javascript objects](#objects) in depth later.
73 changes: 50 additions & 23 deletions manuscript/markdown/Functions/args.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,43 @@ A> Most programmers are perfectly familiar with arguments (often called "paramet

Let's make a function with an argument:

function (room) {}

{:lang="js"}
~~~~~~~~
function (room) {}
~~~~~~~~

This function has one argument, `room`, and no body. Here's a function with two arguments and no body:

function (room, board) {}

{:lang="js"}
~~~~~~~~
function (room, board) {}
~~~~~~~~

I'm sure you are perfectly comfortable with the idea that this function has two arguments, `room`, and `board`. What does one do with the arguments? Use them in the body, of course. What do you think this is?

function (diameter) { return diameter * 3.14159265 }
{:lang="js"}
~~~~~~~~
function (diameter) { return diameter * 3.14159265 }
~~~~~~~~

It's a function for calculating the circumference of a circle given the diameter. I read that aloud as "When applied to a value representing the diameter, this function *returns* the diameter times 3.14159265."

Remember that to apply a function with no arguments, we wrote `(function () {})()`. To apply a function with an argument (or arguments), we put the argument (or arguments) within the parentheses, like this:

(function (diameter) { return diameter * 3.14159265 })(2)
//=> 6.2831853

{:lang="js"}
~~~~~~~~
(function (diameter) { return diameter * 3.14159265 })(2)
//=> 6.2831853
~~~~~~~~

You won't be surprised to see how to write and apply a function to two arguments:

(function (room, board) { return room + board })(800, 150)
//=> 950

{:lang="js"}
~~~~~~~~
(function (room, board) { return room + board })(800, 150)
//=> 950
~~~~~~~~

T> ### a quick summary of functions and bodies
T>
T> How arguments are used in a body's expression is probably perfectly obvious to you from the examples, especially if you've used any programming language (except for the dialect of BASIC--which I recall from my secondary school--that didn't allow parameters when you called a procedure).
Expand All @@ -50,8 +65,11 @@ Like most contemporary programming languages, JavaScript uses the "call by value

So when you write:

(function (diameter) { return diameter * 3.14159265 })(1 + 1)
//=> 6.2831853
{:lang="js"}
~~~~~~~~
(function (diameter) { return diameter * 3.14159265 })(1 + 1)
//=> 6.2831853
~~~~~~~~

What happened internally is that the expression `1 + 1` was evaluated first, resulting in `2`. Then our circumference function was applied to `2`.[^f2f]

Expand All @@ -61,20 +79,26 @@ What happened internally is that the expression `1 + 1` was evaluated first, res

Right now everything looks simple and straightforward, and we can move on to talk about arguments in more detail. And we're going to work our way up from `function (diameter) { return diameter * 3.14159265 }` to functions like:

function (x) { return (function (y) { return x }) }

{:lang="js"}
~~~~~~~~
function (x) { return (function (y) { return x }) }
~~~~~~~~

A> `function (x) { return (function (y) { return x }) }` just looks crazy, as if we are learning English as a second language and the teacher promises us that soon we will be using words like *antidisestablishmentarianism*. Besides a desire to use long words to sound impressive, this is not going to seem attractive until we find ourselves wanting to discuss the role of the Church of England in 19th century British politics.
A>
A> But there's another reason for learning the word *antidisestablishmentarianism*: We might learn how prefixes and postfixes work in English grammar. It's the same thing with `function (x) { return (function (y) { return x }) }`. It has a certain important meaning in its own right, and it's also an excellent excuse to learn about functions that make functions, environments, variables, and more.

In order to talk about how this works, we should agree on a few terms (you may already know them, but let's check-in together and "synchronize our dictionaries"). The first `x`, the one in `function (x) ...`, is an *argument*. The `y` in `function (y) ...` is another argument. The second `x`, the one in `{ return x }`, is not an argument, *it's an expression referring to a variable*. Arguments and variables work the same way whether we're talking about `function (x) { return (function (y) { return x }) }` or just plain `function (x) { return x }`.

Every time a function is invoked ("invoked" means "applied to zero or more arguments"), a new *environment* is created. An environment is a (possibly empty) dictionary that maps variables to values by name. The `x` in the expression that we call a "variable" is itself an expression that is evaluated by looking up the value in the environment.

How does the value get put in the environment? Well for arguments, that is very simple. When you apply the function to the arguments, an entry is placed in the dictionary for each argument. So when we write:

(function (x) { return x })(2)
//=> 2
{:lang="js"}
~~~~~~~~
(function (x) { return x })(2)
//=> 2
~~~~~~~~

What happens is this:

Expand Down Expand Up @@ -107,10 +131,13 @@ Because many references can share the same value, and because JavaScript passes

And with that, we're ready to look at *closures*. When we combine our knowledge of value types, reference types, arguments, and closures, we'll understand why this function always evaluates to `true` no matter what argument[^NaNPedantry] you apply it to:

function (value) {
return (function (copy) {
return copy === value
})(value)
}
{:lang="js"}
~~~~~~~~
function (value) {
return (function (copy) {
return copy === value
})(value)
}
~~~~~~~~

[^NaNPedantry]: Unless the argument is NaN, which isn't equal to anything, including itself
95 changes: 58 additions & 37 deletions manuscript/markdown/Functions/buildingblocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,66 +6,87 @@ When you look at functions within functions in JavaScript, there's a bit of a "s

One of the most basic of these building blocks is *composition*:

function cookAndEat (food) {
return eat(cook(food))
}

{:lang="js"}
~~~~~~~~
function cookAndEat (food) {
return eat(cook(food))
}
~~~~~~~~

It's really that simple: Whenever you are chaining two or more functions together, you're composing them. You can compose them with explicit JavaScript code as we've just done. You can also generalize composition with the B Combinator or "compose" that we saw in [Combinators and Decorators](#combinators):

function compose (a, b) {
return function (c) {
return a(b(c))
}
}
{:lang="js"}
~~~~~~~~
function compose (a, b) {
return function (c) {
return a(b(c))
}
}

var cookAndEat = compose(eat, cook);
~~~~~~~~

var cookAndEat = compose(eat, cook);

If that was all there was to it, composition wouldn't matter much. But like many patterns, using it when it applies is only 20% of the benefit. The other 80% comes from organizing your code such that you can use it: Writing functions that can be composed in various ways.

In the recipes, we'll look at a decorator called [once](#once): It ensures that a function can only be executed once. Thereafter, it does nothing. Once is useful for ensuring that certain side effects are not repeated. We'll also look at [maybe](#maybe): It ensures that a function does nothing if it is given nothing (like `null` or `undefined`) as an argument.

Of course, you needn't use combinators to implement either of these ideas, you can use if statements. But `once` and `maybe` compose, so you can chain them together as you see fit:

function actuallyTransfer(from, to, amount) {
// do something
}

var invokeTransfer = once(maybe(actuallyTransfer(...)));

{:lang="js"}
~~~~~~~~
function actuallyTransfer(from, to, amount) {
// do something
}

var invokeTransfer = once(maybe(actuallyTransfer(...)));
~~~~~~~~

### partial application

Another basic building block is *partial application*. When a function takes multiple arguments, we "apply" the function to the arguments by evaluating it with all of the arguments, producing a value. But what if we only supply some of the arguments? In that case, we can't get the final value, but we can get a function that represents *part* of our application.

Code is easier than words for this. The [Underscore] library provides a higher-order function called *map*.[^headache] It applies another function to each element of an array, like this:

_.map([1, 2, 3], function (n) { return n * n })
//=> [1, 4, 9]

{:lang="js"}
~~~~~~~~
_.map([1, 2, 3], function (n) { return n * n })
//=> [1, 4, 9]
~~~~~~~~

This code implements a partial application of the map function by applying the function `function (n) { return n * n }` as its second argument:

function squareAll (array) {
return _.map(array, function (n) { return n * n })
}
{:lang="js"}
~~~~~~~~
function squareAll (array) {
return _.map(array, function (n) { return n * n })
}
~~~~~~~~

The resulting function--`squareAll`--is still the map function, it's just that we've applied one of its two arguments already. `squareAll` is nice, but why write one function every time we want to partially apply a function to a map? We can abstract this one level higher. `mapWith` takes any function as an argument and returns a partially applied map function.

function mapWith (fn) {
return function (array) {
return _.map(array, fn)
}
}

var squareAll = mapWith(function (n) { return n * n });

squareAll([1, 2, 3])
//=> [1, 4, 9]
{:lang="js"}
~~~~~~~~
function mapWith (fn) {
return function (array) {
return _.map(array, fn)
}
}

var squareAll = mapWith(function (n) { return n * n });

squareAll([1, 2, 3])
//=> [1, 4, 9]
~~~~~~~~

We'll discuss mapWith again in [the recipes](#mapWith). The important thing to see is that partial application is orthogonal to composition, and that they both work together nicely:

var safeSquareAll = mapWith(maybe(function (n) { return n * n }));

safeSquareAll([1, null, 2, 3])
//=> [1, null, 4, 9]
{:lang="js"}
~~~~~~~~
var safeSquareAll = mapWith(maybe(function (n) { return n * n }));

safeSquareAll([1, null, 2, 3])
//=> [1, null, 4, 9]
~~~~~~~~

We generalized composition with the `compose` combinator. Partial application also has a combinator, which we'll see in the [partial](#partial) recipe.

Expand Down
Loading