FP Lenses enhanced
Tags: javascript, functional, lenses, partialapplication
Published: 2022-04-01 12:21:44

---
title: FP Lenses enhanced
published: true
description: Continuing the use of partial applications to develop lenses 
series: Going functional one step at a time
tags: javascript, functional, lenses, partialapplication
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xss8oyko6tpntsvc0o0g.png 
---

We ended my previous post on [Lenses and Partial-application](https://dev.to/tracygjg/partial-application-going-functional-one-step-at-a-time-3g3h) with the following implementation for the lens function `lookupGenerator`.

```javascript
function lookupGenerator(...props) {
  return obj =>
    props
      .reduce((o, p) => 
        p in o ? o[p] : null, obj);
}
```

Since the previous version I have revised it to include some enhancements.

###Recap on what lenses are used for

A lens is a function used to extract a value from an object/array given the properties/subscripts that defines its path. For example:

```javascript
const testObject = {
  alpha: [
    {beta: '42', gamma: [ 'A', 'B', 'C']},
    {beta: '666', gamma: [ 'a', 'b', 'c']}
  ]
};

const testLookup = lookupGenerator('alpha', 1, 'gamma', 2);

console.log(testLookup(testObject)); // 'c'
```

Where lenses really come into their owns is when they are applied within a method on an array of objects, as follows:

```javascript
const betaLookup = lookupGenerator('beta');

testObject.alpha.forEach(obj => console.log(betaLookup(obj)));

// Output: 42, 666
```

The `testObject` in the above examples is quite small and simple but imagine using this technique to pass an array of more complicated objects through methods such as `sort`, `map` or `filter`.

###So what is the limitation with the above implementation?

As discussed in my previous post, the above function employs partial-application to improve reuse. The function is called twice, once to provide the list of properties (and subscripts) used to navigate the object to find the required value. This returns a function that can be used several times by calling it with a compatible object (or array.)

There are a couple of ways to prescribe the route through the object to the required property. In the above example an array of property names and array subscripts were provided `('alpha', 1, 'gamma', 2)` but another way is to provide the route as a string as follows `'alpha[1].gamma[2]'`. 

```javascript
function lookupGenerator(...props) {
  return obj =>
    props
      .join('.')
      .split(/[\[\]\.]+/)
      .filter(item => item !== '')
      .reduce((o, p) =>
        typeof o === 'object' && o != null && 
        p in o ? o[p] : undefined, obj);
}
```

The above implementation can support either or both prescription approaches.

```
Input options
-------------

lookupGenerator('alpha', 1, 'gamma', 2);  // arguments
lookupGenerator('alpha[1].gamma[2]');     // string
lookupGenerator('alpha[1]', 'gamma[2]');  // string arguments

```

####How does it work?

First we join all the strings together to form a single string with a dot separating each sequence. We then separate each property name and array subscript using a Regular Expression (RegExp) match. For a discussion of the power of RegExp please read this [post](https://dev.to/tracygjg/the-black-art-of-regular-expressions-a-little-computer-science-for-the-inquisitive-developer-2ee6) of mine.

The array of segments resulting from the split operation can produce empty matches that need to be filtered out before they are presented to the reduce method as before. Finally we need to guard against the reduce method failing to locate a property or finding a null mid process and throwing an exception.

I hope you have found this supplement informative but please provide any related questions you have in the discussion section below and I will be happy to try to provide an answer.

If `partial application` is of interest, you might also be interested in my post on [Currying](https://dev.to/tracygjg/curried-functions-going-functional-one-step-at-a-time-4746).