Re: [elm-discuss] Immutable data design problem
I'm not sure I understand all the details of your domain model, but it seems like the notable point is that accounts are created implicitly as assessment events occur, and you'd like to be able to, given an assessment event, get the related accounts? I'd probably start with making a module (maybe called "AssessmentStore") that has functions that describe what you need. I'm thinking something like: allEvents : AssessmentStore -> List AssessmentEvent and hmm... now that I write that out, it seems like that's all you want, except that you ideally want AssessmentEvent to have a list of Accounts in it. I think the approach I would prefer is similar to what you mention in your last paragraph about keeping the data in separate structures, but you question the safety of managing parallel structures. If you create a separate module to encapsulates the data, you can can limit the need for careful handling to that single module. I might try something like this in `AssessmentStore`: type AssessmentStore = AssessmentStore { assessmentEventInfo : Dict EventId { name : String, ... } -- This is not the full AssessmentEvent; just the things that don't relate to accounts. , accountsByEvent : Dict EventId (List AccountId) , accountInfo : Dict AccountId Account , allEvents : List EventId -- (or maybe you want them indexed differently, by time, etc) } then have a function to create the assessment store, and then the `allEvents` functions suggested above (or any other function to get AssessmentEvents) can take the data in that private data structure and merge it together to give the data that you actually want to return to the caller. In fact, you never need to expose the AccountIds/EventIds outside of this module. If you are still worried about safety, you can add more unit tests to this module, or try to define fuzz test properties to help you ensure that you handle the computations correctly within the module. I've found this sort of approach to work well because it lets you represent the data in whatever data structure is most performant and/or appropriate for your needs (it is often also simpler to implement because the data structures tend to be much flatter), but also hides the internal representation behind an module interface so that you can still access the data in whatever ways are most convenient for the calling code. On Sun, Jul 23, 2017 at 7:16 PM, Lyle Kopnickywrote: > I have a series of datatypes that have already been modeled in a > relational database in a product. I'm trying to construct a lighter-weight > in-memory representation in Elm for purposes of simulating operations and > visualizing the results. Ultimately I will probably want to do some > export/import operations that will allow someone to view data from the real > database, or create records in a test database. But, I don't think the > in-memory representations need to correspond exactly to the database ones > in order to do this. I'd like to focus on as simple of a representation as > possible, and I'm leaving out a fair number of fields. > > We start with a provided series of AssessmentEvents. It's just a limited > amount of data for each AssessmentEvent. Some of the fields in the database > can be calculated from the others, so those don't need to be provided. From > this data, we can calculate more information about the AssessmentEvents, > including deltas between them. We can also derive a series of Accounts in a > completely deterministic fashion. Each AssessmentEvent will have up to two > years associated with it, and for each year there will be at least one > Account. From this we can also calculate one or two Bills to go with each > Account. > > It's a fairly complex calculation. Certainly I can do it in Elm. But what > I'm waffling about is how to store the data. These calculations can be > cached - they do not need to be repeated if the user just changes their > view of the data. They only need to be revised if the user wants to > insert/edit/update AssessmentEvents. So to do all these calculations every > time the user shifts the view would be wasteful. > > It becomes tricky with immutable data. In an object-oriented program, I > would probably just have, say, extra empty fields on the AssessmentEvent > object, that I would fill in as I updated the object. E.g., it could have a > list of accounts, which initially would be a null value until I filled it > in. > > At first I thought I might do something similar in the Elm data structure. > An AssessmentEvent can contain a List of Accounts (I'm oversimplifying as > it really needs to list the accounts per year). The list of Accounts can be > initially empty. Then as I calculate the accounts, I can create a new list > of AssessmentEvents that have Accounts in the list. But wait - since the > list of AssessmentEvents is immutable, I can't change it. I can only create > a new one, and then, where in the model
[elm-discuss] Immutable data design problem
I have a series of datatypes that have already been modeled in a relational database in a product. I'm trying to construct a lighter-weight in-memory representation in Elm for purposes of simulating operations and visualizing the results. Ultimately I will probably want to do some export/import operations that will allow someone to view data from the real database, or create records in a test database. But, I don't think the in-memory representations need to correspond exactly to the database ones in order to do this. I'd like to focus on as simple of a representation as possible, and I'm leaving out a fair number of fields. We start with a provided series of AssessmentEvents. It's just a limited amount of data for each AssessmentEvent. Some of the fields in the database can be calculated from the others, so those don't need to be provided. From this data, we can calculate more information about the AssessmentEvents, including deltas between them. We can also derive a series of Accounts in a completely deterministic fashion. Each AssessmentEvent will have up to two years associated with it, and for each year there will be at least one Account. From this we can also calculate one or two Bills to go with each Account. It's a fairly complex calculation. Certainly I can do it in Elm. But what I'm waffling about is how to store the data. These calculations can be cached - they do not need to be repeated if the user just changes their view of the data. They only need to be revised if the user wants to insert/edit/update AssessmentEvents. So to do all these calculations every time the user shifts the view would be wasteful. It becomes tricky with immutable data. In an object-oriented program, I would probably just have, say, extra empty fields on the AssessmentEvent object, that I would fill in as I updated the object. E.g., it could have a list of accounts, which initially would be a null value until I filled it in. At first I thought I might do something similar in the Elm data structure. An AssessmentEvent can contain a List of Accounts (I'm oversimplifying as it really needs to list the accounts per year). The list of Accounts can be initially empty. Then as I calculate the accounts, I can create a new list of AssessmentEvents that have Accounts in the list. But wait - since the list of AssessmentEvents is immutable, I can't change it. I can only create a new one, and then, where in the model do I put it? When a user initializes the model, then, what should they pass in? Perhaps they can pass in a list of AssessmentEvents that each have an empty list of Accounts, and then that gets stored in a variable. Then the Accounts are calculated, and we generate a new list of AssessmentEvents with Accounts attached, and that is what gets stored in the model. But this has some shortcomings. The user must now create something that has this extra unused field on it (and there will be more). I guess if they are using a function to create it, they needn't know that there are these extra fields. But what if the field isn't a list - it's an Int? Then do we need to make it a Maybe Int? Then all the code that later operates on that Int will have to handle the case that the Maybe Int might be a Nothing, even though at that point I know it will always be Just something. Maybe there should be a data structure that contains an AssessmentEvent, also containing the extra fields? But what if I have a series of functions, each of which adds some new field to the AssessmentEvent? Then I need a new data type for each step that just adds one more field? Perhaps if I use untagged records, then all the functions can just operate on the fields they care about, ignoring extra fields. I sort of liked the extra type safety that came with the tagged record, but it may just get in the way. Perhaps instead of attaching this extra data to AssessmentEvents, it could be kept in separate data structures? But then how do I know how they are connected? Unless I carefully manage the data in parallel arrays, I will need to add IDs to the AssessmentEvents, so they can be stored in a Dict. These are just some of my thoughts. Does anyone have any suggested patterns to follow? Thanks, Lyle -- You received this message because you are subscribed to the Google Groups "Elm Discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [elm-discuss] Re: Systemic problem in Object Oriented languages
On Sun, Jul 23, 2017 at 1:39 AM, Dave Fordwrote: > > It's not that OOP is bad, but it encourages mutation >> > OOP does not encourage nor discourage mutation. Java, Kotlin, Scala and > OCAML all *allow* mutation. Kotlin, an OO language that I use a lot, > actually *discourages* mutation. But regardless, my question was not > about immutability. It was about combining data and logic. > I do not know Kotlin but all other OOP languages I've used allowed passing an object to a function and potentially having that object be mutated by that function. Maybe "encourage" is the wrong word here but this is an affordance that will be used. In any case, from what I remember from the discussions around object oriented programming around this list, mutability was the key feature that was brought forward as a source of problems that Elm avoids. It was linked to state in objects getting out of sync in certain contexts and to the fact that functions lose their purity. Another issue is the one you mentioned about the surface area of the language. Implementing OOP features would require permanently and irreversibly making the type system and the language more complex. The topic of typeclasses (one of the options) has been raised several times. It has been promised at one point as a feature that the language will gain in time but years passed and the topic got shelved. Outside of these two topics (immutability & complexity of the language) I don't remember seeing arguments for problems brought on by joining data and behavior together. I am interested in the topic of web components (I believe that Elm could benefit greatly from embracing this standard). I've even went as far as to implement a web components system in Elm (with the help of a little bit of Native code) and the only real argument against it that I remember is the argument of mutability. I even tried to implement a mutability-as-service component in order to try to see if this is possible. I failed. Still... the intuition of some of the senior developers of Elm is that this would be possible and that all the nice guarantees of Elm would fly out the window. This is the main reason I pointed to immutability. I think the complexity of the language issue is unavoidable but one can avoid the problems generated by mutability by having an immutable way of joining data and behavior (the FauxO system I hinted towards being one of the ways). I too would be very interested in seeing any kind of argument against joining data and behavior outside of these two main ones (immutability and complexity of the type system). -- There is NO FATE, we are the creators. blog: http://damoc.ro/ -- You received this message because you are subscribed to the Google Groups "Elm Discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.