DEV Community

***
***

Posted on

Declarative functions

Recently I'm having fun with map, filter and reduce, but are the more functions like these that could make programming more fun?

If you know about other built-in functions or functions that you have created, write them in the comments.

Discussion (4)

Collapse
vonheikemen profile image
Heiker

In some functional programming languages there is this one function called ap, which is short for apply, is basically .map's long lost brother.

You see with .map you apply a callback to a value inside a data structure, and it all works great. But what if your callback is also trapped inside a data structure? that's where .ap comes in, it will figure out all the details to get the values out of the data structures and apply them.

An interesting example where this could be useful is if you try to make your own improvised "validation framework". Using plain objects as our data structures, we could implement map and ap for them.

const Obj = {
  map(fn, data) {
    let result = {};

    for (let key in data) {
      result[key] = fn(data[key]);
    }

    return result;
  },
  ap(Fns, data) {
    let result = {};

    for (let key in data) {
      result[key] = Fns[key](data[key]);
    }

    return result;
  },
};
Enter fullscreen mode Exit fullscreen mode

Now imagine we have this input.

const badinput = {
  password: "Anima",
  username: "O",
  email: ""
};
Enter fullscreen mode Exit fullscreen mode

If you want to validate that all you have to do is wrap your validation functions inside an object of the same shape.

const validations = {
  password: is_strong_password,
  username: is_required,
  email: is_email,
};
Enter fullscreen mode Exit fullscreen mode

With that in place you just apply them.

Obj.ap(validations, badinput);
Enter fullscreen mode Exit fullscreen mode

That will return an object of the same shape but with the result data of each validation. Since these are all plain functions you can do all sorts of crazy stuff inside them, you can have multiple validations inside one function, you can have it return a lot metadata... well anything you can think of.

Collapse
pomfrit123 profile image
*** Author

Nice, didn't knew this one, thank you for your answer

Collapse
vonheikemen profile image
Heiker • Edited on

There is a whole bunch where that came from. In the javascript world we have a specification for them, is called Fantasy Land. It's geared towards library authors but it could still be useful if you know how to read those weird signatures. Someone actually took the time to go through the spec and made a series posts about it.

Oh, and if you want to check out a cool library with utility functions, go see ramda.

Collapse
richytong profile image
Richard Tong

Try out pipe and tap. pipe takes an array of functions and lets you chain them together so that the return value of one function becomes the first argument to the next. tap takes a function and some input, calls the function with input, and returns the original input (good for effects). Both of these functions used together can get you started composing functions pretty fast. Here are some implementations for the functions.

const functionConcat = (funcA, funcB) => value => funcB(funcA(value))

// pipe(funcs Array<function>)(value any) -> any
const pipe = funcs => funcs.reduce(functionConcat)

const tap = func => value => {
  func(value)
  return value
}
Enter fullscreen mode Exit fullscreen mode

Example with pipe, tap, map, and filter

pipe([
  filter(number => number % 2 == 1), // isOdd
  map(number => number ** 2), // square
  tap(console.log),
])([1, 2, 3, 4, 5]) // -> [1, 9, 25]
Enter fullscreen mode Exit fullscreen mode

I created a library with async-capable versions of the above and more. Check it out at rubico.land