Can a pure function return a Symbol? - javascript

This may border on philosophical, but I thought it would be the right place to ask.
Suppose I have a function that creates a list of IDs. These identifiers are only used internally to the application, so it is acceptable to use ES2015 Symbol() here.
My problem is that, technically, when you ask for a Symbol, I'd imagine the JS runtime creates a unique identifier (random number? memory address? unsure) which, to prevent collisions, would require accessing global state. The reason I'm unsure is because of that word, "technically". I'm not sure (again, from a philosophical standpoint) if this ought to be enough to break the mathematical abstraction that the API presents.
tl;dr: here's an example--
function sentinelToSymbol(x) {
if (x === -1) return Symbol();
return x;
}
Is this function pure?

Not really, no, but it might not actually matter.
On the surface, (foo) => Symbol(foo) appears pure. While the runtime may do some operations with side effects, you will never see them, even if you call Symbol() at the same time with the same parameters. However, calling Symbol with the same arguments will never return the same value, which is one of the main criteria (#2, below).
From the MDN page:
Note that Symbol("foo") does not coerce the string "foo" into a symbol. It creates a new symbol each time:
Symbol("foo") === Symbol("foo"); // false
Looking solely at side effects, (foo) => Symbol(foo) is pure (above the runtime).
However, a pure function must meet more criteria. From Wikipedia:
Purely functional functions (or expressions) have no side effects (memory or I/O). This means that pure functions have several useful properties, many of which can be used to optimize the code:
If the result of a pure expression is not used, it can be removed without affecting other expressions.
If a pure function is called with arguments that cause no side-effects, the result is constant with respect to that argument list (sometimes called referential transparency), i.e. if the pure function is again called with the same arguments, the same result will be returned (this can enable caching optimizations such as memoization).
If there is no data dependency between two pure expressions, then their order can be reversed, or they can be performed in parallel and they cannot interfere with one another (in other terms, the evaluation of any pure expression is thread-safe).
If the entire language does not allow side-effects, then any evaluation strategy can be used; this gives the compiler freedom to reorder or combine the evaluation of expressions in a program (for example, using deforestation).
You could argue the preface to that list rules out everything in JavaScript, since any operation could result in memory being allocated, internal structures updated, etc. In the strictest possible interpretation, JS is never pure. That's not very interesting or useful, so...
This function meets criteria #1. Disregarding the result, (foo) => Symbol(foo) and (foo) => () are identical to any outside observer.
Criteria #2 gives us more trouble. Given bar = (foo) => Symbol(foo), bar('xyz') !== bar('xyz'), so Symbol does not meet that requirement at all. You are guaranteed to get a unique instance back every time you call Symbol.
Moving on, criteria #3 causes no problems. You can call Symbol from different threads without them conflicting (parallel) and it doesn't matter what order they are called in.
Finally, criteria #4 is more of a note than direct requirement, and is easily met (the JS runtimes shuffle everything around as they go).
Therefore:
strictly speaking, nothing in JS can be pure.
Symbol() is definitely not pure, thus the example is not either.
If all you care about is side effects rather than memoization, the example does meet those criteria.

Yes, this function is impure: sentinelToSymbol(-1) !== sentinelToSymbol(-1). We would expect equality here for a pure function.
However, if we use the concept of referential transparency in a language with object identities, we might want to loosen our definition a bit. If you consider function x() { return []; }, is it pure? Obviously x() !== x(), but still the function always returns an empty array regardless of the input, like a constant function. So what we do have to define here is the equality of values in our language. The === operator might not be the best fit here (just consider NaN). Are arrays equal to each other if the contain the same elements? Probably yes, unless they are mutated somewhere.
So you will have to answer the same question for your symbols now. Symbols are immutable, which makes that part easy. Now we could consider them equal by their [[Description]] value (or .toString()), so sentinelToSymbol would be pure by that definition.
But most languages do have functions that allow to break referential transparency - for example see How to print memory address of a list in Haskell. In JavaScript, this would be using === on otherwise equal objects. And it would be using symbols as properties, as that inspects their identity. So if you do not use such operations (or at least without being observable to the outside) in your programs, you can claim purity for your functions and use it for reasoing about your program.

Related

These concepts about Functors (Maps) and Monads (Either, Maybe, Bind, Then) are right?

I'm relatively new to studying functional programming and things were going well until I had to treat errors and promises. Trying to do it in the “right” way I get a lot of references for Monads as to be the better solution for it, but while studying it I ended up with what I honestly would call a "reference hell", where there was a lot of references and sub-references either mathematical or in programming for the same thing where this thing would have a different name for the same concepts, which was really confusing. So after persisting in the subject, I'm now trying to summarize and clarify it, and this is what I get so far:
For the sake of understanding I'll oversimplify it.
Monoids: are anything that concatenate/sum two things returning a thing of the same group so in JS any math addition or just concatenation from a string are Monoids for definition as well the composition of functions.
Maps: Maps are just methods that apply a function to each element of a group, without changing the category of the group itself or its length.
Functors: Functors are just objects that have a Map method that return the Functor itself.
Monads: Monads are Functors that use FlatMaps.
FlatMaps: FlatMaps are maps that have the capability of treat promises/fetch or summarize the received value.
Either, Maybe, Bind, Then: are all FlatMaps but with different names depending on the context you use it.
(I think they all are FlatMaps for definition but there is a difference in the way they are used since there is a library like Monets.js that have both a Maybe and a Either function, but I don’t get the use case difference).
So my question is: are these concepts right?
if anyone can reassure me what so far I got right and correct what I got wrong, or even expand on what I have missed, I would be very grateful.
Thanks to anyone who takes the time.
//=============================================================//
EDIT:
I should've emphasized more in this post, but these affirmations and simplified definitions are only from the "practical perspective in JavaScript" (I'm aware of the impossibility of making such a small simplification of a huge and complex theme like these especially if you add another field like mathematics).
//=============================================================//
Monoids: are anything that concatenate/sum two things returning a thing of the same group...
First thing that I don't like here is the word “group”. I know, you're just trying to use simple language and all, but the problem is that group has a very specific mathematical meaning, and we can't just ignore this because groups and monoids are very closely related. (A group is basically a monoid with inverse elements.) So definitely don't use this word in any definition of monoids, however informal. You could say “underlying set” there, but I'd just say type. That may not match the semantics in all programming languages, but certainly in Haskell.
So,
Monoids: are anything that concatenate/sum two things returning a thing of the same type so in JS any math addition or just concatenation from a string are Monoids for definition as well the composition of functions.
Ok. Specifically, concatenation of endofunctions is a monoid. In JavaScript, all functions are in a sense endofunctions, so you can get away with this.
But that's actually describing only a semigroup, not a monoid. (See, there's out groups... confusingly, monoids are in between semigroups and groups.) A monoid is a semigroup that has also a unit element, which can be concatenated to any other element without making a difference.
For the addition-monoid, this is the number zero.
For the string-monoid, it is the empty string.
For the function monoid, it is the identity function.
Even with unit elements, your characterization is missing the crucial feature of a semigroup/monoid: the concatenation operation must be associative. Associativity is a strangely un-intuitive property, perhaps because in most examples it seems stupidly obvious. But it's actually crucial for much of the maths that is built on those definitions.
To make the importance of associativity clear, it helps to look at some things that are not semigroups because they aren't associative. The type of integers with subtraction is such an example. The result is that you need to watch out where to put your parentheses in maths expressions, to avoid incurring sign errors. Whereas strings can just be concatenated in either order – ("Hello"+", ")+"World" is the same as "Hello"+(", "+"World").
Maps: Maps are just methods that apply a function to each element of a group, without changing the category of the group itself or its length.
Here we have the next badly chosen word: categories are again a specific maths thing that's very closely related to all we're talking about here, so please don't use the term with any other meaning.
IMO your definitions of “maps” and functors are unnecessary. Just define functors, using the already known concept of functions.
But before we can do that –
Functors: Functors are just objects...
here we go again, with the conflict between mathematical terminology and natural language. Mathematically, objects are the things that live in a category. Functors are not objects per se (although you can construct a specific category in which they are, by construction, objects). And also, itself already conflicting: in programming, “object” usually means “value with associated methods”, most often realized via a class.
Your usage of the terms seems to match neither of these established meanings, so I suggest you avoid it.
Mathematically, a functor is a mapping between two categories. That's hardly intuitive, but if you consider the category as a collection of types then a functor simply maps types to types. For example, the list functor maps some type (say, the type of integers) to the type of lists containing values of that type (the type of lists of integers).
Here of course we're running a bit into trouble when considering it all with respect to JS. In dynamic languages, you can easily have lists containing elements of multiple different types. But it's actually ok if we just treat the language as having only one big type that all values are members of. The list functor in Python maps the universal type to itself.
Blablatheory, what's the point of this all? The actual feature of a functor is not the type-mapping, but instead that it lifts a function on the contained values (i.e. on the values of the type you started with, in my example integers) to a function on the container-values (on lists of integers). More generally, the functor F lifts a function a -> b to a function F(a) -> F(b), for any types a and b. What you called “category of the group itself” means that you really are mapping lists to lists. Even in a dynamically typed language, the list functor's map method won't take a list and produce a dictionary as the result.
I suggest a different understandable-definition:
Functors: Functors wrap types as container-types, which have a mapping method that applies functions on contained values to functions on the whole container.
What you said about length is true of the list functor in particular, but it doesn't really make sense for functors in general. In Haskell we often talk about the fact that functor mapping preserves the “shape” of the container, but that too isn't actually part of the mathematical definition.
What is part of the definition is that a functor should be compatible with composition of the functions. This boils down to being able to map as often as you like. You can always map the identity function without changing the structure, and if you map two functions separately it has the same effect as mapping their composition in one go. It's kind of intuitive that this amounts to the mapping being “shape-preserving”.
Monads: Monads are Functors that use FlatMaps.
Fair enough, but of course this is just shifting everything to: what's a FlatMap?
Mathematically it's actually easier to not consider the FlatMap / >>= operation at first, but just consider the flattening operation, as well as the singleton injector. Going by example: the list monad is the list functor, equipped with
The operation that creates a list of just a plain contained value. (This is analogous to the unit value of a monoid.)
The operation that takes a nested list and flattens it out to a plain list, by gathering all the values in each of the inner lists. (This is analogous to the sum operation in a monoid.)
Again, it is important that these operations obey laws. These are also analogous to the monoid laws, but unfortunately even less intuitive because their simultaneously hard to think about and yet again so almost-trivial that they can seem a bit useless. But specifically the associativity law for lists can be phrased quite nicely:
Flattening the inner lists in a doubly nested list and then flattening the outer ones has the same effect as first flattening the outer ones and then the inner ones.
[[[1,2,3],[4,5]],[[6],[7,8,9]]] ⟼ [[1,2,3,4,5],[6,7,8,9]] ⟼ [1,2,3,4,5,6,7,8,9]
[[[1,2,3],[4,5]],[[6],[7,8,9]]]⟼[[1,2,3],[4,5],[6],[7,8,9]]⟼[1,2,3,4,5,6,7,8,9]
A Monoid is a set and an operator, such that:
The operator is associative for that set
The operator has an identity within that set
So, addition is associative for the set of real numbers, and in the set of real numbers has the identity zero.
a+(b+c) = (a+b)+c -- associative
a+0 = a -- identity
A Map is a transformation between two sets. For every element with the first set, there is a matching element in the second set. As an example, the transformation could be 'take a number and double it'.
The transformation is called a Functor. If the set is mapped back to itself, it is called an Endofunctor.
If an operator and a set is a Monoid, and also can be considered an Endofunctor, then we call that a Monad.
Monoids, Functors, Endofunctor, and Monads are not a thing but rather the property of a thing, that the operator and set has these properties. Can we declare this in Haskell by creating instances in the appropriate Monoid, Functor and Monad type-classes.
A FlatMap is a Map combined with a flattening operator. I can declare a map to be from a list to a list of lists. For a Monad we want to go from a list to a list, and so we flatten the list at the end to make it so.
To be blunt, I think all of your definitions are pretty terrible, except maybe the "monoid" one.
Here's another way of thinking about these concepts. It's not "practical" in the sense that it will tell you exactly why a flatmap over the list monad should flatten nested lists, but I think it's "practical" in the sense that it should tell you why we care about programming with monads in the first place, and what monads in general are supposed to accomplish from a practical perspective within functional programs, whether they are written in JavaScript or Haskell or whatever.
In functional programming, we write functions that take certain types as input and produce certain types as output, and we build programs by composing functions whose input and output types match. This is an elegant approach that results in beautiful programs, and it's one of the main reasons functional programmers like functional programming.
Functors provide a way to systematically transform types in a way that adds useful functionality to the original types. For example, we can use a functor to add functionality to a "normal type" that allows it to be missing or absent or "null" (Maybe) or represent either a successfully computed result or an error condition (Either) or that allows it to represent multiple possible values instead of only one (list) or that allows it to be computed at some time in the future (promise) or that requires a context for evaluation (Reader), or that allows a combination of these things.
A map allows us to reuse the functions we've defined for normal types on these new types that have been transformed by a functor, in some natural way. If we already have a function that doubles an integer, we can re-use that function on various functor transformations of integers, like doubling an integer that might be missing (mapping over a Maybe) or doubling an integer that hasn't been computed yet (mapping over a promise) or doubling every element of a list (mapping over a list).
A monad involves applying the functor concept to the output types of functions to produce "operations" that have additional functionality. With monad-less functional programming, we write functions that take "normal types" of inputs and produce "normal types" of outputs, but monads allow us to take "normal types" of inputs and produce transformed types of outputs, like the ones above. Such a monadic operation can represent a function that takes an input and Maybe produces an output, or one that takes an input and promises to produce an output later, or that takes an input and produces a list of outputs.
A flatmap generalizes the composition of functions on normal types (i.e., the way we build monad-less functional programs) to composition of monadic operations, appropriately "chaining" or combining the extra functionality provided by the transformed output types of the monadic operations. So, flatmaps over the maybe monad will compose functions as long as they keep producing outputs and give up when one of those functions has a missing output; flatmaps over the promise monad will turn a chain of operations that each take an input and promise an output into a single composed operation that takes an input and promises a final output; flatmaps over the list monad will turn a chain of operations that each take a single input and produce multiple outputs into a single composed operation that takes an input and produces multiple outputs.
Note that these concepts are useful because of their convenience and the systematic approach they take, not because they add magic functionality to functional programs that we wouldn't otherwise have. Of course we don't need a functor to create a list data type, and we don't need a monad to write a function that takes a single input and produces a list of outputs. It just ends up being useful thinking in terms of "operations that take an input and promise to produce either an error message or a list of outputs", compose 50 of those operations together, and end up with a single composed operation that takes an input and promises either an error message or a list of outputs (without requiring deeply nested lists of nested promises to be manually resolved -- hence the value of "flattening").
(In practical programming terms, monoids don't have that much to do with the rest of these, except to make hilarious in-jokes about the category of endofunctors. Monoids are just a systematic way of combining or "reducing" a bunch of values of a particular type into a single value of that type, in a manner that doesn't depend on which values are combined first or last.)
In a nutshell, functors and their maps allow us to add functionality to our types, while monads and their flatmaps provide a mechanism to use functors while retaining some semblance of the elegance of simple functional composition that makes functional programming so enjoyable in the first place.
An example might help. Consider the problem of performing a depth-first traversal of a file tree. In some sense, this is a simple recursive composition of functions. To generate a filetree() rooted at pathname, we need to call a function on the pathname to fetch its children(), and then we need to recursively call filetree() on those children(). In pseudo-JavaScript:
// to generate a filetree rooted at a pathname...
function filetree(pathname) {
// we need to get the children and generate filetrees rooted at their pathnames
filetree(children(pathname))
}
Obviously, though, this won't work as real code. For one thing, the types don't match. The filetree function should be called on a single pathname, but children(pathname) will return multiple pathnames. There are also some additional problems -- it's unclear how the recursion is supposed to stop, and there's also the issue that the original pathname appears to get lost in the shuffle as we jump right to its children and their filetrees. Plus, if we're trying to integrate this into an existing Node application with a promise-based architecture, it's unclear how this version of filetree could support the promise-based filesystem API.
But, what if there was a way to add functionality to the types involved while maintaining the elegance of this simple composition? For example, what if we had a functor that allowed us to promise to return multiple values (e.g., multiple child pathnames) while logging strings (e.g., parent pathnames) as a side effect of the processing?
Such a functor would, as I've said above, be a transformation of types. That means that it would transform a "normal" type, like a "integer", into a "promise for a list of integers together with a log of strings". Suppose we implement this as an object containing a single promise:
function M(promise) {
this.promise = promise
}
which when resolved will yield an object of form:
{
"data": [1,2,3,4] // a list of integers
"log": ["strings","that","have","been","logged"]
}
As a functor, M would have the following map function:
M.prototype = {
map: function(f) {
return this.promise.then((obj) => ({
data: obj.data.map(f),
log: obj.log
}))
}
}
which would apply a plain function to the promised data (without affecting the log).
More importantly, as a monad, M would have the following flatMap function:
M.prototype = {
...
flatMap: function(f) {
// when the promised data is ready
return new M(this.promise.then(function(obj) {
// map the function f across the data, generating promises
var promises = obj.data.map((d) => f(d).promise)
// wait on all promises
return Promise.all(promises).then((results) => ({
// flatten all the outputs
data: results.flatMap((result) => result.data),
// add to the existing log
log: obj.log.concat(results.flatMap((result) => result.log))
}))
}))
}
}
I won't explain in detail, but the idea is that if I have two monadic operations in the M monad, that take a "plain" input and produce an M-transformed output, representing a promise to provide a list of values together with a log, I can use the flatMap method on the output of the first operation to compose it with the second operation, yielding a composite operation that takes a single "plain" input and produces an M-transformed output.
By defining children as a monadic operation in the M monad that promises to take a parent pathname, write it to the log, and produce a list of the children of this pathname as its output data:
function children(parent) {
return new M(fsPromises.lstat(parent)
.then((stat) => stat.isDirectory() ? fsPromises.readdir(parent) : [])
.then((names) => ({
data: names.map((x) => path.join(parent, x)),
log: [parent]
})))
}
I can write the recursive filetree function almost as elegantly as the original above, as a flatMap-assisted composition of the children and recursively invoked filetree functions:
function filetree(pathname) {
return children(pathname).flatMap(filetree)
}
In order to use filetree, I need to "run" it to extract the log and, say, print it to the console.
// recursively list files starting at current directory
filetree(".").promise.then((x) => console.log(x.log))
The full code is below. Admittedly, there's a fair bit of it, and some of it is pretty complicated, so the elegance of the filetree function appears to have come at a fairly big cost, as we've apparently just moved all the complexity (and them some) into the M monad. However, the M monad is a general tool, not specific to performing depth-first traversals of file trees. Also, in an ideal world, a sophisticated JavaScript monad library would allow you to build the M monad from monadic pieces (promise, list, and log) with a couple lines of code.
var path = require('path')
var fsPromises = require('fs').promises
function M(promise) {
this.promise = promise
}
M.prototype = {
map: function(f) {
return this.promise.then((obj) => ({
data: obj.data.map(f),
log: obj.log
}))
},
flatMap: function(f) {
// when the promised data is ready
return new M(this.promise.then(function(obj) {
// map the function f across the data, generating promises
var promises = obj.data.map((d) => f(d).promise)
// wait on all promises
return Promise.all(promises).then((results) => ({
// flatten all the outputs
data: results.flatMap((result) => result.data),
// add to the existing log
log: obj.log.concat(results.flatMap((result) => result.log))
}))
}))
}
}
// not used in this example, but this embeds a single value of a "normal" type into the M monad
M.of = (x) => new M(Promise.resolve({ data: [x], log: [] }))
function filetree(pathname) {
return children(pathname).flatMap(filetree)
}
function children(parent) {
return new M(fsPromises.lstat(parent)
.then((stat) => stat.isDirectory() ? fsPromises.readdir(parent) : [])
.then((names) => ({
data: names.map((x) => path.join(parent, x)),
log: [parent]
})))
}
// recursively list files starting at current directory
filetree(".").promise.then((x) => console.log(x.log))

What's the difference between str.fun() / str.fun / fun(str) in JavaScript?

I tried googling but couldn't find a precise answer, so allow me to try and ask here. If the question does not seem proper, please let me know and I'll delete it.
In JS you've got three different way of writing certain build in functionalities:
str.length
str.toString()
parseInt(str)
I wonder if there is a reason behind these different ways of writing. As a new user I don't grasp why it couldn't be streamlined as: length(str) / toString(str) / parseInt(str) or with dot formulation.
I however think if I do know the reason behind these differences, it would give me a better understanding of JavaScript.
Length is one of the attributes of string in JavaScript. Hence you use string.length to get the length of the string.
toString is a function for string objects, hence we use stringobj.toString().
parsInt(str) is a global function which takes string as a parameter.
JavaScript is object-oriented, so there are functions or procedures which require first an object to use as this in their bodies. str.length is a property, both syntactically and semantically. It doesn't require any parameters and represents some quality of the object. obj.toString() is a method (a function attached to an object), which doesn't represent any characteristics of the object, but rather operates on its state, computes some new values, or changes the state of the object a lot. parseInt(str) is a "global" function, which represents an operation not attached to any type or object.
Under the hood, these three ways may be well implemented with just calling a function, passing this as the first parameter (like C# does, for example). The semantic difference is the important one.
So why not use just the third syntax, like for example PHP does? First, it doesn't bloat the global environment with lots of functions which only work for one specific case and type, allowing you to specify any new function you want without breaking the old functionality. Second, it ecourages you to use object-oriented concepts, because you can already see working objects and methods in the language, and can try to make something similar.
And why isn't parseInt a method? It can as well be str.toInt() without any issues, it's just the way JavaScript designers wanted it to be, although it seems also a bit logical to me to make it a static method Number.parseInt(str), because the behaviour of the function is relevant more to the Number type than the String type.
JavaScript is based around objects. Objects have properties (e.g. a User object may have name and age properties). These are what define the user and are related to the user. Properties are accessed via dot-notation or brackets notation (to access Eliott’s age, we’ll use either eliott.age or eliott['age'] — these are equivalent).
These properties can be of any type — String, Number, Object, you name it — even functions. Now the proper syntax to call a function in JS is to put round brackets: eliott.sayHello(). This snippet actually fetches Eliott’s sayHello property, and calls it right away.
You can see Eliott as a box of properties, some of which can be functions. They only exist within the box and have no meaning out of the box: what would age be? Whose age? Who’s saying hello?
Now some functions are defined at the global level: parseInt or isNaN for instance. These functions actually belong to the global box, named window (because legacy). You can also call them like that: window.parseInt(a, 10) or window.isNaN(a). Omitting window is allowed for brevity.
var eliott = {
name: 'Eliott',
age: 32,
sayHello: function () { console.log('Hello, I’m Eliott'); }
};
eliott.name; // access the `name` property
eliott.age; // access the `age` property
eliott.sayHello; // access the `sayHello` property
eliott.sayHello(); // access the `sayHello` property and calls the function
sayHello(eliott); // Reference error: `window.sayHello` is undefined!
Note: Some types (String, Number, Boolean, etc.) are not real objects but do have properties. That’s how you can fetch the length of a string ("hello".length) and reword stuff ("hello, Eliott".replace("Eliott", "Henry")).
Behaviour of these expressions is defined in ECMAScript grammar. You could read the specification to understand it thoroughly: ECMAScript2015 specification. However, as pointed out by Bergi, it's probably not the best resource for beginners because it doesn't explain anything, it just states how things are. Moreover I think it might be too difficult for you to be able to grasp concepts described in this specification because of the very formal language used.
Therefore I recommend to start with something way simpler, such as a very basic introduction to JavaScript: JavaScript Basics on MDN. MDN is a great resource.
But to answer your question just briefly:
str.length is accessing a property of the str object.
parseInt(str) is a function call
str.toString() is a call of a function which is a property of the str object. Such functions are usually named methods.
Functions and methods are in fact very similar but one of the differences (except for the obvious syntax difference) is that methods by default have context (this) set to refer to the object which they're part of. In this case inside of toString function this equals to str.
Note: Accessing a property (as in str.length) could in effect call a getter function but it depends on how the object is defined, and is in fact transparent for the user.

Understanding ES6 Symbols

I've been around the block when it comes to languages, having worked with everything from C# to Lisp to Scala to Haskell, and in every language that supported them, symbols have acted pretty much the same; that is, any two symbols with the same name, are guaranteed to be identical because they're singleton objects.
Racket: (equal? 'foo 'foo) true
Common Lisp: (eq 'foo 'foo) true
Ruby: :foo == :foo true
Scala: 'foo == 'foo true
ES6: Symbol('foo') === Symbol('foo') false
The benefit of symbols being singletons is obvious: You can use them in maps/dictionaries without risking your key not being equal to your input because the language suddenly decided to hash it differently (looking at you, Ruby)
So why is it that ECMAScript 6 takes a different approach on this, and how can I get around it?
You can (sort-of) get the effect of symbols being "knowable" by name by using registered (global) symbols:
var s1 = Symbol.for("foo");
var s2 = Symbol.for("foo");
s1 === s2; // true
Of course you can create your own Symbol registry too, with a Map instance or a plain object.
edit — I'll add that the intention of the optional string parameter when making a new Symbol instance is to provide a way of identifying the meaning and purpose of a symbol to the programmer. Without that string, a Symbol works just fine as a Symbol, but if you dump out an object in a debugger the properties keyed by such anonymous Symbol instances are just values. If you're keeping numeric properties on an object with Symbol keys, then you'll just see some numbers, and that would be confusing. The description string associated with a Symbol instances gives the programmer reference information without compromising the uniqueness of the Symbol as a key value.
Finally, you can always compare the result of calling .toString() on two similarly-constructed Symbol instances. I suspect that that practice would be considered questionable, but you can certainly do it.
edit more — it occurs to me that the fact that the default behavior of Symbol creation in JavaScript makes the type more useful than, say, atoms in Erlang or keys in Clojure. Because the language provides by default a value guaranteed to be unique, the fundamental problem of namespace collision is solved pretty nicely. It's still possible to work with "well-known" symbols, but having unique values available without having to worry about conflicts with other code that might also want to avoid collisions is nice. JavaScript has the somewhat unique, and certainly uniquely pervasive and uncontrollable, problem of a global namespace that may be polluted by code that a programmer does not even know exists, because code can collide in the browser enviroment due to the actions of a party different from, and unknown to, an arbitrary number of software architects.

Is Underscore.js functional programming a fake?

According to my understanding of functional programming, you should be able to chain multiple functions and then execute the whole chain by going through the input data once.
In other words, when I do the following (pseudo-code):
list = [1, 2, 3];
sum_squares = list
.map(function(item) { return item * item; })
.reduce(function(total, item) { return total + item; }, 0);
I expect that the list will be traversed once, when each value will be squared and then everything will be added up (hence, the map operation would be called as needed by the reduce operation).
However, when I look at the source code of Underscore.js, I see that all the "functional programming" functions actually produce intermediate collections like, for example, so:
// Return the results of applying the iteratee to each element.
_.map = _.collect = function(obj, iteratee, context) {
iteratee = cb(iteratee, context);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length,
results = Array(length);
for (var index = 0; index < length; index++) {
var currentKey = keys ? keys[index] : index;
results[index] = iteratee(obj[currentKey], currentKey, obj);
}
return results;
};
So the question is, as stated in the title, are we fooling ourselves that we do functional programming when we use Underscore.js?
What we actually do is make program look like functional programming without actually it being functional programming in fact. Imagine, I build a long chain of K filter() functions on list of length N, and then in Underscore.js my computational complexity will be O(K*N) instead of O(N) as would be expected in functional programming.
P.S. I've heard a lot about functional programming in JavaScript, and I was expecting to see some functions, generators, binding... Am I missing something?
Is Underscore.js functional programming a fake?
No, Underscore does have lots of useful functional helper functions. But yes, they're doing it wrong. You may want to have a look at Ramda instead.
I expect that the list will be traversed once
Yes, list will only be traversed once. It won't be mutated, it won't be held in memory (if you had not a variable reference to it). What reduce traverses is a different list, the one produced by map.
All the functions actually produce intermediate collections
Yes, that's the simplest way to implement this in a language like JavaScript. Many people rely on map executing all its callbacks before reduce is called, as they use side effects. JS does not enforce pure functions, and library authors don't want to confuse people.
Notice that even in pure languages like Haskell an intermediate structure is built1, though it would be consumed lazily so that it never is allocated as a whole.
There are libraries that implement this kind of optimisation in strict languages with the concept of transducers as known from Clojure. Examples in JS are transduce, transducers-js, transducers.js or underarm. Underscore and Ramda have been looking into them2 too.
I was expecting to see some […] generators
Yes, generators/iterators that can be consumed lazily are another choice. You'll want to have a look at Lazy.js, highland, or immutable-js.
[1]: Well, not really - it's a too easy optimisation
[2]: https://github.com/jashkenas/underscore/issues/1896, https://github.com/ramda/ramda/pull/865
Functional programming has nothing to do with traversing a sequence once; even Haskell, which is as pure as you're going to get, will traverse the length of a strict list twice if you ask it to filter pred (map f x).
Functional programming is a simpler model of computation where the only things that are allowed to happen do not include side effects. For example, in Haskell basically only the following things are allowed to happen:
You can apply a value f to another value x, producing a new value f x with no side-effects. The first value f is called a "function". It must be the case that any time you apply the same f to the same x you get the same answer for f x.
You can give a name to a value, which might be a function or a simple value or whatever.
You can define a new structure for data with a new type signature, and/or structure some data with those "constructors."
You can define a new type-class or show how an existing data structure instantiates a type-class.
You can "pattern match" a data structure, which is a combination of a case dispatch with naming the parts of the data structure for the rest of your project.
Notice how "print something to the console" is not doable in Haskell, nor is "alter an existing data structure." To print something to the console, you construct a value which represents the action of printing something to the console, and then give it a special name, main. (When you're compiling Haskell, you compute the action named main and then write it to disk as an executable program; when you run the program, that action is actually completed.) If there is already a main program, you figure out where you want to include the new action in the existing actions of that program, then use a function to sequence the console logging with the existing actions. The Haskell program never does anything; it just represents doing something.
That is the essence of functional programming. It is weaker than normal programming languages where the language itself does stuff, like JavaScript's console.log() function which immediately performs its side effect whenever the JS interpreter runs through it. In particular, there are some things which are (or seem to be) O(1) or O(log(log(n))) in normal programs where our best functional equivalent is O(log(n)).

Reference to Originating Conditional Value within a Javascript IF Statement

I often find that I write IF statements which immediately reference the value of the conditional statement. For example, let's say I need to check to see if a string matches a pattern:
if (mystring.match(/mypattern/) {
var mymatch = mystring.match(/mypattern/)[1];
...
};
I suspect that what I'm looking for doesn't exist, but I've wondered whether you can reference the conditional statement's value within the if block, the way you can reference "arguments" within a function. In many cases, of course, I can rewrite it like this:
var mymatch = mystring.match(/mypattern/)[1];
if (mymatch) { ... };
But that's often not possible if there's a series of methods called. For example:
var mymatch = $('.myclass')[0].text().match(/mypattern/)[1];
... that would throw an exception if there were no item [0] on which to call .text(). Is there some convenient shorthand I'm missing out on? Or a better way to organize things? Just curious, really — I'll go on living if the answer is no.
In cases where relevant you can use the fact that the assignment operator returns a value in JavaScript, so for instance you can write things like:
if (assignedTest = testedValue) {
//value of assignedTest is now available
//and conditional will only be executed if true
This could be used if the RHS was compatible or properly set-up but it's also a huge readability concern since it's very easy to confuse the assignment = with comparison ==/===.
If you were particularly motivated to pursue this you could extract this type of functionality into a function that would behave in a reliable way: such as assigning the result of a closure to a named variable, and you could further tune the behavior to do other things (such as optionally evaluating to a different value within the test). Ultimately it would primarily be making a simple structure more complex though.

Categories