# Hierarchical data modeling

**URL:** <https://discourse.elm-lang.org/t/hierarchical-data-modeling/9612>\
**Category:** Learn\
**Created:** [January 29, 2024, 3:58pm UTC](https://discourse.elm-lang.org/t/hierarchical-data-modeling/9612 "2024-01-29T15:58:51Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![ceving](https://avatars.discourse-cdn.com/v4/letter/c/a3d4f5/32.png) [@ceving](https://discourse.elm-lang.org/u/ceving)\
**Post date:** [January 29, 2024, 3:58pm UTC](https://discourse.elm-lang.org/t/hierarchical-data-modeling/9612/1 "2024-01-29T15:58:51Z")

</div>

I am new to Elm. I try to find out if it might be useful for me. But I am a bit disturbed by the following threads:

- [Updating nested records, again](https://discourse.elm-lang.org/t/updating-nested-records-again/1488)
- [Reddit - Dive into anything](https://www.reddit.com/r/elm/comments/9w6tzp/what_is_the_best_way_to_update_nested_record/)

I would like to write an application with several forms. Each form should contain several different inputs of different types and some inputs have themself a sub structure as for example dates (year, month, day). In every other language (JavaScript, Go, Scheme) I would create some nested records to build a tree for my data.

- form a
  - entry a
    - input a
    - input b

  - entry b
    - input a
    - input b

- form b
  - entry a
    - input a

and so on

But in the cited threads I found the following statements:

> Elm is very opinionated and part of that opinion is that nesting is often a hint at bad design.

> Although the language permits doing this, it is so strongly discouraged as a technique that I think we should step back and reexamine the surrounding code to find a fundamentally better way to address your use case

This sounds quite astonishing to me. For me organizing data in a hierarchical way is the most natural thing. Strangely enough, almost all models in the guide only consist of a few values. So the question is: how is complex data handled in Elm? How would a model for my requirement look like?

---

<div class="post-metadata">

**Author:** ![lydell](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/lydell/32/178_2.png) [@lydell](https://discourse.elm-lang.org/u/lydell)\
**Post date:** [January 29, 2024, 5:32pm UTC](https://discourse.elm-lang.org/t/hierarchical-data-modeling/9612/2 "2024-01-29T17:32:20Z")

</div>

Your suggested structure looks great! That’s how I’d do it too.

---

<div class="post-metadata">

**Author:** ![Lucas\_Payr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/lucas_payr/32/4993_2.png) [@Lucas\_Payr](https://discourse.elm-lang.org/u/Lucas_Payr)\
**Post date:** [January 29, 2024, 6:03pm UTC](https://discourse.elm-lang.org/t/hierarchical-data-modeling/9612/3 "2024-01-29T18:03:41Z")

</div>

Forms are quite a complicated topic. I would recommend not thinking too much about type safety or else you will lose yourself in a deep deep rabbit hole. Its probably just fine starting with what you got and seeing how far it gets you.

For smaller forms, I would create update functions to help me update the nested structure.

```auto
type alias SmallForm =
    { firstName : String
    , secondName: String
    , address : List String
    , birthday : {year:Int,month:Int,day:Int}
    }

updateBirthday : {year:Int,month:Int,day:Int} -> SmallForm -> SmallForm

```

For bigger forms, I would start grouping the fields by type and put them into a dict:

```auto
type alias BigForm =
    { strings : Dict String String
    , ints : Dict String Int
    }

```

No matter which way you choose, you will probably want to validate the Form after submitting it. That’s usually where I convert it into something more useful like

```auto
type alias Contact =
  { name : Name
  , address : Address
  , birthday : Date
  }
type alias Name = 
  { firstName: String
  , secondName : String
  }
type alias Address =
 { country : String
 , street: String
 , door: String
 }
type alias Date =
 { year : Int
 , month : Month
 , day : Int
 }

```

---

<div class="post-metadata">

**Author:** ![dwayne](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dwayne/32/5478_2.png) [@dwayne](https://discourse.elm-lang.org/u/dwayne)\
**Post date:** [January 29, 2024, 9:19pm UTC](https://discourse.elm-lang.org/t/hierarchical-data-modeling/9612/4 "2024-01-29T21:19:25Z")

</div>

Concerning [Updating nested records, again](https://discourse.elm-lang.org/t/updating-nested-records-again/1488).

Whenever I see **multiple dots** being used to access anything, methods nested deeply in an object hierarchy or fields nested deeply in a record or JavaScript object, I recall the [Law of Demeter](https://thoughtbot.com/ruby-science/law-of-demeter.html) ([video](https://thoughtbot.com/upcase/videos/law-of-demeter)). It suggests **a [code smell](https://thoughtbot.com/ruby-science/code-smells.html) in ALL languages**, JavaScript, Go, Scheme, no matter how easy they make it to do.

That said, it doesn’t mean don’t do it, it just means that as the code size grows your application could become more difficult to maintain. You just have to decide on the tradeoffs you want to make.

---

<div class="post-metadata">

**Author:** ![Bram](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/bram/32/4862_2.png) [@Bram](https://discourse.elm-lang.org/u/Bram)\
**Post date:** [January 30, 2024, 11:10am UTC](https://discourse.elm-lang.org/t/hierarchical-data-modeling/9612/5 "2024-01-30T11:10:19Z")

</div>

Usually, whenever I encounter the need for nested data types, I usually take one of two ways:

## Create a new data type

A lot of the sub-records are often identical, and you can create a new module with the new data type:

```elm
type alias Model =
    { formA : Form String String
    , formB : Form Int String
    , formC : Form Int Float
    }

type alias Form a b = { inputA : a, inputB : b }

```

Then, using separate functions, you can update the form types given that their inputs are of the correct type. For example:

```elm
{-| Update inputA if it is a String type. In the Model example above,
this function only works for model.formA
-}
updateFirstTextField : String -> Form String b -> Form String b
updateFirstTextField text form =
    { form | inputA = text }

-- Now use { data | formA = updateFirstField "foo" data.formA }

```

If you want separate entries per form, you can also create an `Entry` data type.

## Extensible records

Usually, flattening down isn’t as bad as it may seem! You can easily have a record like:

```elm
type alias Model =
    { form1Entry1Input1 : String
    , form1Entry1Input2 : String
    , form1Entry2Input1 : Float
    , form1Entry2Input2 : Int
    -- etc
    }

```

Then, whenever you want to write a function that can only reach very specific parts of the record:

```elm
type Form1Entry1 a = { a | form1Entry1Input1 : String, form1Entry1Input2 : String }

{-| Yes, you can use Model as an input type for this function!
-}
viewFirstForm : Form1Entry1 a -> Html msg
viewFirstForm model =
    Html.div [] []
    -- TODO: Use model.form1Entry1Input1 and model.form1Entry1Input2 to create a form view

```

These names, of course, reek of a code smell, so generally using a `List` or `Dict` is more useful when you start getting large forms with many entries.

---

<div class="post-metadata">

**Author:** ![ceving](https://avatars.discourse-cdn.com/v4/letter/c/a3d4f5/32.png) [@ceving](https://discourse.elm-lang.org/u/ceving)\
**Post date:** [January 31, 2024, 8:33am UTC](https://discourse.elm-lang.org/t/hierarchical-data-modeling/9612/6 "2024-01-31T08:33:13Z")

</div>

I think I have missed one aspect. Every input needs its particular kind of validation. And the nesting reflects the conjunctions for the validation. An entry is valid, if all nested inputs are valid. A form is valid if all nested entries are valid. A successor form becomes available, if its preceding form is valid. I do not think that flattening is a useful approach. And I have three state booleans: valid, invalid, unknown, because I can not spam the user with invalid-errors if he did not enter anything.

---

<div class="post-metadata">

**Author:** ![ceving](https://avatars.discourse-cdn.com/v4/letter/c/a3d4f5/32.png) [@ceving](https://discourse.elm-lang.org/u/ceving)\
**Post date:** [January 31, 2024, 9:18am UTC](https://discourse.elm-lang.org/t/hierarchical-data-modeling/9612/7 "2024-01-31T09:18:02Z")

</div>

Dynamic scoping seems to be the exact opposite of the law of demeter. Changing a dynamic variable has an impact on the whole call stack not just the second or third level. But dynamic scoping is useful in some situations: [EMACS: The Extensible, Customizable Display Editor - GNU Project - Free Software Foundation](https://www.gnu.org/software/emacs/emacs-paper.html#SEC17)  
You will find a similar argumentation in one of the Lambda papers:  
[https://dspace.mit.edu/bitstream/handle/1721.1/6094/AIM-453.pdf](https://dspace.mit.edu/bitstream/handle/1721.1/6094/AIM-453.pdf)  
Dynamic Scoping as a State-Decomposition Discipline (on page 43).

---

<div class="post-metadata">

**Author:** ![Lucas\_Payr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/lucas_payr/32/4993_2.png) [@Lucas\_Payr](https://discourse.elm-lang.org/u/Lucas_Payr)\
**Post date:** [January 31, 2024, 11:31am UTC](https://discourse.elm-lang.org/t/hierarchical-data-modeling/9612/8 "2024-01-31T11:31:29Z")

</div>

in that case you have two ways to go forward.

Either you use an existing package, like [dilonkearns/elm-form](https://dark.elm.dmy.fr/packages/dillonkearns/elm-form/latest/) that defines the architecture for you.

Or you write your own thing. But this has the possibility, that you go down a rabbit hole that will cost you a lot of time and maybe some of your sanity.  
My personal recommendation, if you want to go this route is to don’t try to generalize and don’t try to be smart. Make a file for every form. If you want to create a multi-step form, than you should probably use [elm-spa](https://www.elm-spa.dev/) and create one Page per form.

---

<div class="post-metadata">

**Author:** ![dwayne](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dwayne/32/5478_2.png) [@dwayne](https://discourse.elm-lang.org/u/dwayne)\
**Post date:** [January 31, 2024, 3:38pm UTC](https://discourse.elm-lang.org/t/hierarchical-data-modeling/9612/9 "2024-01-31T15:38:47Z")

</div>

I never mentioned anything about dynamic scoping/binding. And, I also agree that it has nothing to do with the Law of Demeter.

## Aside

However, since you mentioned the topic, I will share a few things:

1. I rather use a more controlled formed of dynamic binding like what [Racket provides through `parameterize`](https://docs.racket-lang.org/guide/parameterize.html).
2. I implemented dynamic scoping/binding in this [interpreter](https://github.com/dwayne/eopl3/tree/1a409e6f94335dc3667afc6c8eb5ef1f87ff2a78/solutions/03-ch3/interpreters/haskell/PROC-3.28).
3. I implemented `parameterize` (called `setdynamic`) in this [interpreter](https://github.com/dwayne/eopl3/tree/1a409e6f94335dc3667afc6c8eb5ef1f87ff2a78/solutions/04-ch4/interpreters/racket/IMPLICIT-REFS-4.21).

I always thought that `parameterize` was a neat language based solution to what they do in React with [`createContext`](https://react.dev/reference/react/createContext).

---

<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:** [February 10, 2024, 3:39pm UTC](https://discourse.elm-lang.org/t/hierarchical-data-modeling/9612/10 "2024-02-10T15:39:20Z")

</div>

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