HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

FizzBuzz functional implementation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
functionalimplementationfizzbuzz

Problem

I was playing around with ES6 arrow functions, currying and partial application and I decided to try a functional implementation of the FizzBuzz problem:

function* range(start, stop) {
  for (var i = start; i  res => x => fn(x) ? res : null
var isDividedBy = dividend => divisor => divisor % dividend === 0
var mapDividedBy = x => map(isDividedBy(x))
var mappers = [
  mapDividedBy(3)('Fizz'),
  mapDividedBy(5)('Buzz')
]
var applyMappers = mappers => x => mappers.map(fn => fn(x)).join('') || x

var result = Array.from(range(1, 100)).map(applyMappers(mappers))

console.log(result)


My main focus was to be able to easily add any other case like "print Zazz for numbers lower than 10" by simply adding map(x => x < 10)('Zazz') to the mappers array.

What do you think?

Solution

map vs if

var map = fn => res => x => fn(x) ? res : null


I would rename this to something more like ifThen or when -- calling this function map is confusing, to me at least, given the normal usage of map. This is an if where the else is always null.

In a larger program you may find that providing the true/false results as functions instead of constants would be more powerful, but here that would just add noise.

const

Most of your vars could be consts. Doesn't make much difference here but since you're deliberately being functional const would help declare your intent.

without mapDividedBy

I don't think you need this specialized function. Just pass the predicate and true-result into your when/if:

const when = pred => trueRes => x => pred(x) ? trueRes : null
const isDividedBy = dividend => divisor => divisor % dividend === 0
const mappers = [
  when(isDividedBy(3))('Fizz'),
  when(isDividedBy(5))('Buzz'),
]


naming

I'm not sure mappers is the most descriptive name. I can't think of anything better at present, so that's not very helpful, but any (pure) function is just a "mapper" from inputs to output(s). Maybe tests? Hmm.

In any event, since this is a FizzBuzz I suggest providing a final function named as such, for convenience and readability:

const fizzbuzz = applyMappers(mappers)
const result = Array.from(range(1, 100)).map(fizzbuzz)


misc

I like your currying approach.

Clojure has a function juxt which does the same thing as mappers.map(fn => fn(x)) but looks a little cleaner, being a separate function:

const fizzbuzz = x => juxt(mappers)(x).join('') || x


But whether this is more readable or more obscure depends on whether you know Clojure, so I've left this point to the end.

Code Snippets

var map = fn => res => x => fn(x) ? res : null
const when = pred => trueRes => x => pred(x) ? trueRes : null
const isDividedBy = dividend => divisor => divisor % dividend === 0
const mappers = [
  when(isDividedBy(3))('Fizz'),
  when(isDividedBy(5))('Buzz'),
]
const fizzbuzz = applyMappers(mappers)
const result = Array.from(range(1, 100)).map(fizzbuzz)
const fizzbuzz = x => juxt(mappers)(x).join('') || x

Context

StackExchange Code Review Q#115743, answer score: 3

Revisions (0)

No revisions yet.