# Fractal \`update\` functions thanks to lenses

**URL:** <https://discourse.elm-lang.org/t/fractal-update-functions-thanks-to-lenses/1663>\
**Category:** Request Feedback\
**Created:** [August 20, 2018, 2:10am UTC](https://discourse.elm-lang.org/t/fractal-update-functions-thanks-to-lenses/1663 "2018-08-20T02:10:38Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![atomrc](https://avatars.discourse-cdn.com/v4/letter/a/7ba0ec/32.png) [@atomrc](https://discourse.elm-lang.org/u/atomrc)\
**Post date:** [August 20, 2018, 2:10am UTC](https://discourse.elm-lang.org/t/fractal-update-functions-thanks-to-lenses/1663/1 "2018-08-20T02:10:39Z")

</div>

Hi guys,

# Quick disclaimer

I am very new to Elm and while reading `An introduction to Elm` something bugged me. The fact that only views are shown as composable (cf. [https://guide.elm-lang.org/reuse](https://guide.elm-lang.org/reuse)).

I tried to find an elegant solution to let sub components/modules/functional slices of the app/… **update their own model without having to know about the top level app model**.

This is a very humble proposal and it’s probably missing a lot of cases (for example `Command` are not handled in my current proposal). I am looking for feedback on this idea. There might be a way that I missed to do that already, so I am up for any feedback 🙂

It’s highly inspired of the `Cycle.js` way to do that (with `cycle-onionify` and lenses [https://github.com/staltz/cycle-onionify](https://github.com/staltz/cycle-onionify)).

In the rest of the issue I’ll use the term `component` to talk about a functional slice of an app (something that knows how to render, that possesses the business logic to update its own state and _that returns some effects_ (the former is not part of this proposal)).

# My problem: Components cannot define their own `update` function

So far, what I see is that there can only be a single signature for **any** update function of the app `update : AppMessage -> AppModel -> AppModel`.  
Whether you are building an `update` function for the root component or for a nested leaf component, the function will always take a full `AppModel`.  
The problem is that leaf component then need to know about the structure of `AppModel` and cannot be reused in another context (only their view can be reused).

# Concrete example: the `checkbox` example

Let’s work on a concrete example to illustrate my proposal. The `checkbox` example is a good one I think [http://elm-lang.org/examples/checkboxes](http://elm-lang.org/examples/checkboxes)

The model looks like this

```elm
type alias Model =
  { notifications : Bool
  , autoplay : Bool
  , location : Bool
  }

```

The views are factorized with the `checkbox` function

The `update` method is defined by the parent that handles all the messages from the `checkbox` views.

# Lenses to the rescue

The idea is to be able to `select` a specific slice of the main model and let the `component` work on that slice independently. This way the `component` can work without knowing anything about the app structure.

In order to achieve that, I came up with an `isolate` function that will feed the component the right slice of the model and when an update occurs, update the parent model with the updated model of the component.

```elm
type alias Getter parentModel childModel =
    parentModel -> childModel

type alias Setter parentModel childModel =
    parentModel -> childModel -> parentModel

type alias Update message model =
    message -> model -> model

isolate : Getter parentModel childModel -> Setter parentModel childModel -> Update message childModel -> Update message parentModel
isolate getter setter update message model =
    setter model (update message (getter model))

```

# Final result

Here is the current `update` function of the given example

```elm
update : Msg -> Model -> Model
update msg model =
  case msg of
    ToggleNotifications ->
      { model | notifications = not model.notifications }

    ToggleAutoplay ->
      { model | autoplay = not model.autoplay }

    ToggleLocation ->
      { model | location = not model.location }

```

Here is the isolated version

```elm
-- checkbox.elm
checkboxUpdate: Msg -> Bool -> Bool
checkboxUpdate msg model = not model

-- main.elm
notificationUpdate = isolate (model -> model.notification) (model -> notification -> {model | notification = notification}) checkbodUpdate (\_ -> model -> model)
-- same for autoplay and location

update: Msg -> Model -> Model
update msg model = notificationUpdate msg >> autoplayUpdate msg >> locationUpdate msg

```

**This enable easy reuse of components at different level of the application without having to write a reducer every single time.**

# Limitations

This proposal is not yet a viable option for, as far as I know, two reasons:

- `Commands` are not handles (I might have a idea for that)
- messages are not isolated, meaning that all the `checkbox` will react to a click on a single one of them (I have no idea yet how to fix that).
- … probably some other limitations that I cannot see due to my limited knowledge of Elm.

# What I am looking for?

Pretty much anything from “this is a super bad idea because of this, this and that” or “this is not the elm philosophy at all” to “Good idea, I might have some idea to fix the limitations” or “Well, is already possible with this solution”.

Working on this was super interesting anyway and I really had a great time working on this, so even if this is a bad idea, my time was not lost **at all** 😉

BTW: really ❤ the language!!

---

<div class="post-metadata">

**Author:** ![evancz](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/evancz/32/16_2.png) [@evancz](https://discourse.elm-lang.org/u/evancz)\
**Post date:** [August 20, 2018, 2:41am UTC](https://discourse.elm-lang.org/t/fractal-update-functions-thanks-to-lenses/1663/2 "2018-08-20T02:41:16Z")

</div>

Haskell is the language that committed to this idea most strongly, instigating a bunch of discussion in other communities. ClojureScript explored it under the name “cursors” a bit afterwards. Since then, both of these communities cooled off on the idea after seeing it in practice. I know folks in Haskell who do not allow lenses as a _transitive_ dependency even.

At the peak excitement around this idea in 2014, I wrote [https://github.com/evancz/focus](https://github.com/evancz/focus) to explore the idea for myself. I did not think it was going to be good in the end, and I think that’s what played out in the communities that explored it at the ecosystem level. The README explains the major problems I was worried about, primarily about revealing structure that should be hidden by nicer use of modules.

My opinion is that the code you define as a problem is actually really simple. We could make things more complex to save characters. Making simple code more complex is fine, but making complex code more complex is a pretty big downside. More generally, I do not think all code should be at the absolute limit of comprehension. Some code can just be easy. I don’t think that is a bad thing.

I suggest trying Elm out more and watching some talks to get a feeling for things a bit more.

---

<div class="post-metadata">

**Author:** ![atomrc](https://avatars.discourse-cdn.com/v4/letter/a/7ba0ec/32.png) [@atomrc](https://discourse.elm-lang.org/u/atomrc)\
**Post date:** [August 20, 2018, 8:24am UTC](https://discourse.elm-lang.org/t/fractal-update-functions-thanks-to-lenses/1663/3 "2018-08-20T08:24:29Z")

</div>

Hi Evan, Thanks for this clear reply. This is a good point indeed and I might have rushed into a solution too quickly. As I said, this was super interesting to work on this, so if it ends up nowhere, that no problem 🙂

Anyway, the frustration I had, I believe, came from the fact that the guide only introduce how to split views into reusable pieces of code.  
At that point in reading the guide I felt like I was missing something. I felt the guide told me to write a huge update function in the `main.elm` that handles all the messages of all the view components.

To that day, I still don’t really know how to define smaller update functions that work on chunks of the app and that I can compose together.

I would be super nice, in my opinion, to have a chapter on this part in the guide? What do you think?

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [August 20, 2018, 8:29am UTC](https://discourse.elm-lang.org/t/fractal-update-functions-thanks-to-lenses/1663/4 "2018-08-20T08:29:39Z")

</div>

> [@atomrc](#):
>
> To that day, I still don’t really know how to define smaller update functions that work on chunks of the app and that I can compose together.

I always thought Richard’s 2017 Elm Europe talk was illuminating on the subject of breaking down your `update` function, its a good one:

[![](https://img.youtube.com/vi/DoA4Txr4GUs/maxresdefault.jpg "Elm Europe 2017 - Richard Feldman - Scaling Elm Apps") ](https://www.youtube.com/watch?v=DoA4Txr4GUs)

---

<div class="post-metadata">

**Author:** ![atomrc](https://avatars.discourse-cdn.com/v4/letter/a/7ba0ec/32.png) [@atomrc](https://discourse.elm-lang.org/u/atomrc)\
**Post date:** [August 20, 2018, 8:32am UTC](https://discourse.elm-lang.org/t/fractal-update-functions-thanks-to-lenses/1663/5 "2018-08-20T08:32:03Z")

</div>

> [@evancz](#):
>
> My opinion is that the code you define as a problem is actually really simple. We could make things more complex to save characters. Making simple code more complex is fine, but making complex code more complex is a pretty big downside. More generally, I do not think all code should be at the absolute limit of comprehension. Some code can just be easy. I don’t think that is a bad thing.

Oh and my point was not to save character but more to group together view and behavior so that a component of an app can be read in a single file and reused at many different places

---

<div class="post-metadata">

**Author:** ![atomrc](https://avatars.discourse-cdn.com/v4/letter/a/7ba0ec/32.png) [@atomrc](https://discourse.elm-lang.org/u/atomrc)\
**Post date:** [August 20, 2018, 8:38am UTC](https://discourse.elm-lang.org/t/fractal-update-functions-thanks-to-lenses/1663/6 "2018-08-20T08:38:13Z")

</div>

Thanks @rupert added to my “to watch list” 🙂

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [August 30, 2018, 8:38am UTC](https://discourse.elm-lang.org/t/fractal-update-functions-thanks-to-lenses/1663/7 "2018-08-30T08:38:16Z")

</div>

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
