DEV Community

JavaScript Joel
JavaScript Joel

Posted on Edited on

An introduction to MojiScript's enhanced map

World map

MojiScript extends and enhances map in many ways like supporting iterables and asynchronous code. This an introduction into the features MojiScript's map provides and the differences with traditional map.

This post was inspired by an excellent question Twitter:

Traditional map

Let's start out with something you should already be familiar with. This is map in it's most simple form.

const values = [1, 2, 3]
values.map(x => x * 2) //=> [2, 4, 6]
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

Now before we even begin this journey, I would like to recommend breaking the function x => x * 2 out of the map() call.

const double = x => x * 2
const values = [1, 2, 3]
values.map(double) //=> [2, 4, 6]
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

I know it seems like I am saying something trivial and obvious, but it's something I rarely see when reading code.

This is something you can do with map, filter, reduce, Promise.then calls, and more.

Syntax

MojiScript's map is a standalone function and not a method on an object. You still have the same values, map, and func. But the way you call it is just a little bit different (but not too much).

// JavaScript
values.map(func)

// MojiScript
map (func) (values)
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

Making this change opens up the possibility to easily compose new functions.

const newFunc = map (func) // a new function is born!
newFunc (values)
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

Mapping Iterators

Because JavaScript's map is a method attached to Array, it cannot easily be used with other types.

In this example, I am importing range, which is an Iterator.

import range from 'mojiscript/list/range'
console.log(...range (1) (4)) //=> 1 2 3
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

Unfortunately, JavaScript's map doesn't support Iterators.

range (1) (4)
  .map (double) //=> Error: map is not a function​​
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

Even if we do some sorcery, we can't get it to work...

Array.prototype.map.call(range (1) (4), double) //=> []
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

In JavaScript-land, the Iterator must be cast to an Array first before it can be mapped.

Array.prototype.map.call([...range (1) (4)], double) // [2, 4, 6]
//                        ----------------
//                      /
//     cast to an Array

[...range (1) (4)].map(double) //=> [2, 4, 6]
//---------------
//                 \
//                   cast to an Array
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

But with MojiScript, map has no problems with Iterators and the syntax is identical to mapping over an Array.

map (double) (range (1) (4)) //=> [2, 4, 6]
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

Mapping strings

The same syntax is used for mapping chars in a string.

const charCode = x => x.charCodeAt(0)

// JavaScript
Array.prototype.map.call('abc', charCode) //=> [97, 98, 99]

// MojiScript
map (charCode) ('abc') //=> [97, 98, 99]
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

NodeLists

NodeLists are also supported!

// JavaScript
document.querySelectorAll('div[id]').map()
//=> Error: document.querySelectorAll(...).map is not a function

// MojiScript
const getId = element => element.getAttribute('id')
const divs = document.querySelectorAll('div[id]')

const ids = map (divs) (getIds)
//=> ['id1', 'id2', 'id3']
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

Maybe

The Maybe type is an excellent alternative to a nullable type. Instead of using null and having to perform null checks, you can use a Maybe type in it's place.

JavaScript:

const upper = string =>
  string == null ? string : string.toUpperCase()

upper(null) //=> null
upper('abc') //=> 'ABC'
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

MojiScript:

Maybe can eliminate the need for most null checks. Again, the syntax is the same as any other call to map.

import map from 'mojiscript/list/map'
import Just from 'mojiscript/type/Just'
import Nothing from 'mojiscript/type/Nothing'

const upper = map (string => string.toUpperCase())

upper (Nothing) //=> Nothing
upper (Just ('abc')) //=> Just ('ABC')
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

Some helper methods to easily get you in and out of Maybes:

import Just from 'mojiscript/type/Just'
import { fromMaybe, fromNullable } from 'mojiscript/type/Maybe'
import Nothing from 'mojiscript/type/Nothing'

fromNullable (null) //=> Nothing
fromNullable ('abc') //=> Just ('abc')

fromMaybe ('') (Nothing) //=> ''
fromMaybe ('') (Just ('abc')) //=> 'abc'
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

The Maybe is far to big of a subject to cover here. Fortunately, I have written an entire article on the subject here: NULL, "The Billion Dollar Mistake", Maybe Just Nothing

Asynchronous map

MojiScript's map also supports asynchronous mapping!

const double = x => x * 2

const asyncDouble = num => new Promise(resolve => {
  setTimeout(() => {
    console.log({ num })
    resolve(double(num))
  }, 1000)
})

map (asyncDouble) (range (1) (5))
//=> [2, 4, 6, 8, 10]
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

Mapping Async Iterables

MojiScript's map also support async iterators!

const timeout = seconds =>
  new Promise(resolve => setTimeout(resolve, seconds))

async function* asyncGen() {
  await timeout (1000)
  yield 1
  await timeout (1000)
  yield 2
  await timeout (1000)
  yield 3
}

const double = x => x * 2

const iter = asyncGen();

map (double) (iter)
//=> Promise([ 2, 4, 6 ])
🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน 🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน

Summary

MojiScript can map: Array, Iterators, Async Iterators, Functors, and Strings.

MojiScript's map also supports asynchronous code, which is pretty f'n awesome.

Check out MojiScript. It's pretty awesome! Hop over to the MojiScript Discord chat and say hi!

My articles are very Functional JavaScript heavy, if you need more FP, follow me here, or on Twitter @joelnet!

Cheers!

Top comments (2)

🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน
 
codaroma profile image
codaroma •

is it not map(func)(values)?
one of your examples shows
map (range (1) (4)) (double) //=> [2, 4, 6]
looks the wrong way round to me. is this an error?

🔴 Hot News: joelnet/an introduction to mojiscripts enhanced map dpp - ประเด็นร้อน
 
joelnet profile image
JavaScript Joel •

Good catch! I have updated the post. Cheers! 🍻