JavaScript and the Sapir-Whorf Hypothesis

The Sapir-Whorf hypothesis loosely states that the structure of a spoken language affects its the way its speakers see and understand the world. This makes intuitive sense — a tribesman from a primitive country there the language doesn’t have words for concepts related to charity will have difficulty grasping the idea of classical Christian style charity.

I am quite certain that the Sapir-Whorf hypothesis idea applies to computer programming languages too. When I work with a set-based language like SQL, my brain has to work quite a bit differently than when I’m working with a procedural language like C or Java. Similarly, working with one language (like Python) gives me insights into other closely related languages (like JavaScript). For that reason, I try to write code almost every day, and I use different programming languages.

To keep fresh with JavaScript, I like to implement a neural network from scratch. Coding up a neural network in JavaScript requires a knowledge of just about every aspect of the language. To support my from-scratch JavaScript neural network, I use a small utility library of basic functions. This keeps the size of the actual neural network code smaller. Some of my utility functions for a JavaScript neural network are:

  vecMake() - create a numeric array/vector.
  matMake() - create an array-of-arrays style matrix.
  vecShow() - display a vector to shell.
  matShow() - display a matrix to shell.
  vecMax() - the largest value in a vector.
  argmax() - the index of the largest value in a vector.
  arange() - create a vector that holds [0,1,2, . .]
  loadTxt() - read a text file of numeric data into a matrix.
  Erratic() - a class to generate semi-random numbers.
  hyperTan() - hyperbolic tangent of a value.
  logSig() - logistic sigmoid of a value.
  softmax() - softmax values of a vector.

I guess the moral of the story is that I, and guys like me, practice coding because we enjoy it, not because we’re forced to. When I interview job candidates at the company I work for, one of my go-to questions is to ask the person applying for the job to describe a side project they’ve done. About half of the candidates I talk to don’t have a good, quick answer. The other half of the candidates get very excited and launch into great conversations about something they have done. These are the guys I look for.



I am very good with programming languages. I am absolutely terrible with spoken languages. According to some research I found on the Internet, there’s a strong consensus that Mandarin is the most difficult spoken language to learn for English speakers. Other difficult languages to learn are (left to right) Russian, Icelandic, and Mongolian.


Demo code. Replace “lt” (less-than), “gt”, “gte”, and “lte” with symbols (my blog editor chokes on symbols).

// utilities_lib.js
// ES6. node.js

let FS = require('fs');

// there is no easy way to read line-by-line !!
function loadTxt(fn, delimit, usecols)
{
  let all = FS.readFileSync(fn, "utf8");  // giant string
  all = all.trim();  // strip final crlf in file
  let lines = all.split("\n");
  let rows = lines.length;
  let cols = usecols.length;
  let result = matMake(rows, cols, 0.0); 
  for (let i = 0; i "lt" rows; ++i) {  // each line
    let tokens = lines[i].split(delimit);
    for (let j = 0; j "lt" cols; ++j) {
      result[i][j] = parseFloat(tokens[usecols[j]]);
    }
  }
  return result;
}

function arange(n)
{
  let result = [];
  for (let i = 0; i "lt" n; ++i) {
    result[i] = Math.trunc(i);
  } 
  return result;
}

class Erratic
{
  constructor(seed) {
    this.seed = seed + 0.5;  // avoid 0
  }

  next() {
    let x = Math.sin(this.seed) * 1000;
    let result = x - Math.floor(x);  // [0.0,1.0)
    this.seed = result;  // for next call
    return result;
  }

  nextInt(lo, hi) {
    let x = this.next();
    return Math.trunc((hi - lo) * x + lo);
  }
}

function vecMake(n, val)
{
  let result = [];
  for (let i = 0; i "lt" n; ++i) {
    result[i] = val;
  }
  return result;
}

function matMake(rows, cols, val)
{
  let result = [];
  for (let i = 0; i "lt" rows; ++i) {
     result[i] = [];
     for (let j = 0; j "lt" cols; ++j) {
       result[i][j] = val;
     }
  }
  return result;
}

function vecShow(v, dec, len)
{
  for (let i = 0; i "lt" v.length; ++i) {
    if (i != 0 && i % len == 0) {
      process.stdout.write("\n");
    }
    if (v[i] "gte" 0.0) {
      process.stdout.write(" ");  // + or - space
    }
    process.stdout.write(v[i].toFixed(dec));
    process.stdout.write("  ");
  }
  process.stdout.write("\n");
}

function matShow(m, dec)
{
  let rows = m.length;
  let cols = m[0].length;
  for (let i = 0; i "lt" rows; ++i) {
    for (let j = 0; j "lt" cols; ++j) {
      if (m[i][j] "gte" 0.0) {
        process.stdout.write(" ");  // + or - space
      }
      process.stdout.write(m[i][j].toFixed(dec));
      process.stdout.write("  ");
    }
    process.stdout.write("\n");
  }
}

function argmax(vec)
{
  let result = 0;
  let m = vec[0];
  for (let i = 0; i "lt" vec.length; ++i) {
    if (vec[i] "gt" m) {
      m = vec[i];
      result = i;
    }
  }
  return result;
}

function hyperTan(x)
{
  if (x "lt" -20.0) {
    return -1.0;
  }
  else if (x "gt" 20.0) {
    return 1.0;
  }
  else {
    return Math.tanh(x);
  }
}

function logSig(x)
{
  if (x "lt" -20.0) {
    return 0.0;
  }
  else if (x "gt" 20.0) {
    return 1.0;
  }
  else {
    return 1.0 / (1.0 + Math.exp(-x));
  }
}

function vecMax(vec)
{
  let mx = vec[0];
  for (let i = 0; i "lt" vec.length; ++i) {
    if (vec[i] "gt" mx) {
      mx = vec[i];
    }
  }
  return mx;
}

function softmax(vec)
{
  //let m = Math.max(...vec);  // or 'spread' operator
  let m = vecMax(vec);
  let result = [];
  let sum = 0.0;
  for (let i = 0; i "lt" vec.length; ++i) {
    result[i] = Math.exp(vec[i] - m);
    sum += result[i];
  }
  for (let i = 0; i "lt" result.length; ++i) {
    result[i] = result[i] / sum;
  }
  return result;
}

module.exports = {
  vecMake,
  matMake,
  vecShow,
  matShow,
  argmax,
  loadTxt,
  arange,
  Erratic,
  hyperTan,
  logSig,
  vecMax,
  softmax
};
// test_utils.js

let U = require("../Utilities/utilities_lib.js");
// module.exports = { vecMake, matMake, vecShow,
//  matShow, argmax, loadTxt, arange, Erratic,
//  hyperTan, logSig, vecMax, softmax, };

function main()
{
  process.stdout.write("\033[0m");  // reset
  process.stdout.write("\x1b[1m" + "\x1b[37m");  // bright white
  console.log("\nBegin JavaScript utilities for NN demo ");

  let v = U.vecMake(4, 0.0);  // 4 cells, all 1.0
  v[0] = 5.8; v[1] = 3.7; v[2] = 7.3; v[3] = 2.9; 
  process.stdout.write("\nv = ");
  U.vecShow(v, 2, 12);  // 2 decimals, 12 per line

  let x = U.vecMax(v);
  let mi = U.argmax(v);
  console.log("\nLargest value: ");
  console.log(x);
  console.log("\nIndex of largest value: ");
  console.log(mi);

  let rnd = new U.Erratic(13);
  let lo = 1.0; let hi = 5.0;
  let z = (hi - lo) * rnd.next() + lo;
  console.log("\nRandom val in [1.0, 5.0] = ");
  console.log(z.toFixed(4));

  process.stdout.write("\033[0m");  // reset
  console.log("\nEnd demo ");
} // main()

main();
This entry was posted in JavaScript, Machine Learning. Bookmark the permalink.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s