Another post that talks about lodash/fp (with Vue)
Tags: javascript, vue
Published: 2023-07-15 09:48:53

In my previous post, "[My First Look at Functional Programming](https://dev.to/allieschen/my-first-glance-at-functional-programming-281j)," I mentioned my intention to try using fp-ts. While I'm still learning about functional programming, I believe it can be advantageous for software development. To demonstrate the advantages of functional programming, I created a [todolist-vue](https://codesandbox.io/p/github/AlliesChen/todolist-vue/main?layout=%257B%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522EDITOR%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522panelType%2522%253A%2522TABS%2522%252C%2522id%2522%253A%2522clihh71pn000b3n6musjxkzia%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522DEVTOOLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522panelType%2522%253A%2522TABS%2522%252C%2522id%2522%253A%2522clihh71pn000d3n6mj3zacpp7%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%252C%2522sizes%2522%253A%255B50%252C50%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522clihh71pn000b3n6musjxkzia%2522%253A%257B%2522id%2522%253A%2522clihh71pn000b3n6musjxkzia%2522%252C%2522activeTabId%2522%253A%2522clja9ghv600cm3n6mp4zu1wvx%2522%252C%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clihh71pn000a3n6mphe54mcg%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252FREADME.md%2522%252C%2522state%2522%253A%2522IDLE%2522%257D%252C%257B%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252Fsrc%252Fcomponents%252FTodoCreator.vue%2522%252C%2522id%2522%253A%2522clja9ghv600cm3n6mp4zu1wvx%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522state%2522%253A%2522IDLE%2522%257D%255D%257D%252C%2522clihh71pn000d3n6mj3zacpp7%2522%253A%257B%2522id%2522%253A%2522clihh71pn000d3n6mj3zacpp7%2522%252C%2522tabs%2522%253A%255B%257B%2522type%2522%253A%2522TASK_LOG%2522%252C%2522taskId%2522%253A%2522npm%2520run%2520dev%2522%252C%2522id%2522%253A%2522clihh76bb00823n6madlvkmgs%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%252C%257B%2522type%2522%253A%2522TASK_PORT%2522%252C%2522taskId%2522%253A%2522npm%2520run%2520dev%2522%252C%2522port%2522%253A5173%252C%2522id%2522%253A%2522clihh77fe00d33n6m5zph7ubz%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522path%2522%253A%2522%252F%2522%257D%255D%252C%2522activeTabId%2522%253A%2522clihh77fe00d33n6m5zph7ubz%2522%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A15%257D) web app using Vue and Tailwind Elements as an example. In this post, I will be using lodash/fp to modify the implementation of the functions in the example, which I hope will offer some insights into the benefits of this coding style and whether it's worth adopting.

For reference, the [imperative version](https://codesandbox.io/p/sandbox/todolist-vue-9ce10s?file=%2Fsrc%2Fcomponents%2FTwSelector.vue%3A59%2C1) of the same app from the previous post.

## TL;DR

By utilizing the utility functions from lodash/fp, we can harness the advantages of functional programming. Two functions that I find particularly beneficial for my project are:

- cond-- an expression-based version of if-else statements
- flow-- an function to call its parameters in order

### Parts that are not as pleasant:

You need to become familiar with the functions, although the function names do provide information about their uses. Sometimes, the explanations of the functions in the official documentation of lodash are not very good. Fortunately, since it's a commonly used library, you can find tons of tutorials on the internet, such as [this one](https://masteringjs.io/lodash).

## Lodash and lodash/fp

So, as mentioned in the [Lodash](https://lodash.com/) documentation, it's a library for JavaScript that provides various utility functions. There is a helpful introduction titled [Things to keep in mind when using Lodash](https://geekyants.com/blog/things-to-keep-in-mind-when-using-lodash/) that you might want to take a look at. The concerns discussed in the article revolve around the bundle size and the implementation of functions, which may be a pitfall that can make debugging challenging.

[lodash/fp](https://github.com/lodash/lodash/wiki/FP-Guide) is a functional programming version of Lodash, with some differences mentioned in the linked page, we can use it to write codes in functional programming style.

ℹ️ There are libraries which has similar usage:

- [Ramda](https://ramdajs.com/)
- [Rambda](https://github.com/selfrefactor/rambda)
- [Radash](https://radash-docs.vercel.app/docs/getting-started)

## The Utilities

Although there are many functions, for me, it's `cond` and `flow` that make the code look like a functional programming language. Shamefully, I only talk about these two in the article... 😅

It's worth mentioning that the methods from `lodash/fp` come with auto-currying, a feature commonly seen in functional programming languages such as Elm and PureScript.

- elm

```elm
add : Int -> Int -> Int
add x y =
    x + y

addFive : Int -> Int
addFive =
    add 5

result : Int
result =
    addFive 3 -- result will be 8
```

> code source: [How to partially apply functions in Elm](https://www.educative.io/answers/how-to-partially-apply-functions-in-elm)

- PureScript

```purescript
mul :: Number -> Number -> Number
mul a b = a * b

times2 :: Number -> Number
times2 = mul 2
-- It's like const times2 = b => mul(2)(b) in JavaScript
```

> code source: [TypeScript vs. PureScript
](https://blog.logrocket.com/typescript-vs-purescript-not-all-compilers-are-created-equal-c16dadaa7d3e/)

### cond

Within the file path src/components/TwButton.vue, the styleContext is determined using a switch statement. Although it functions properly, it creates two scopes: one for the arrow function provided to the computed function and another for the switch statement. This redundancy is somewhat unnecessary since we only need to return the value provided by the switch statement. (Yes, you cannot just return the switch statement without placing it to a function scope.)

```javascript
const styleContext = computed(() => {
    switch (props.context) {
        case 'success':
            return 'bg-success'
        case 'danger':
            return 'bg-danger'
        case 'warning':
            return 'bg-warning'
        case 'info':
            return 'bg-info'
        default:
            return 'bg-primary'
    }
})
```

`cond` is an expression-based version of an if statement. It accepts an array consisting of arrays that represent the match patterns and their corresponding actions.

ℹ️ In the future, JavaScript might introduce a native pattern matching syntax, as proposed by TC39. This syntax would provide built-in support for match patterns in JavaScript.

```javascript
const styleMatcher = cond([
    [eq('success'), constant('bg-success')],
    [eq('danger'), constant('bg-danger')],
    [eq('warning'), constant('bg-warning')],
    [eq('info'), constant('bg-info')],
    [stubTrue, constant('bg-primary')]
])
const styleContext = computed(() => styleMatcher(props.context))
```

### flow

Usually, to get an abstraction, we write assignments, function calls like the function `resetSelect` (path: `src/components/TwSelector.vue`):

```javascript
const resetSelect = () =>
  selectRef.value
    ?.querySelector("span[data-te-select-clear-btn-ref]")
    ?.dispatchEvent(new Event("click"));
```

```javascript
const resetSelect = flow(
  constant(selectRef),
  get("value"),
  invokeArgs("querySelector", ["span[data-te-select-clear-btn-ref]"]),
  invokeArgs("dispatchEvent", [new Event("click")])
);
```

ℹ️ Unlike the functions from `lodash`, they does not support `chaining`, and lose shortcut fusion:

> It means combining (fusing) functions that are going to be applied to elements into a single call and calling it on the elements in one go, instead of requiring passes
> -- [Brilliant But Lazy](https://geekyants.com/blog/brilliant-but-lazy/)

ℹ️ [This article](https://nestedsoftware.com/2018/02/27/lazy-evaluation-in-javascript-with-generators-map-filter-and-reduce-36h5.21002.html) has an example that implements shortcut fusion.

## Conclusion

I no longer take "FP" as a magic word that solves every problem I encounter in OOP. It turns out JavaScript does have some, but not all, the features of a functional programming language. With the help of libraries, we can enjoy benefits such as improved readability and purity of methods. However, under the hood, these libraries use functions that imitate the mechanisms of functional programming languages in JavaScript, which may result in reduced efficiency during runtime.