Hello, I’m the author of the mentioned Glue library and I’m also author of Haskell library that has word “combinators” in its name - aeson-combinators. For what it’s worth I can share my perspective on few of the things mentioned in this thread.
I completely agree with all what was said above. It’s true that to some degree word “combinator” is quite under-specified - something that is quite common in programming (think of C++ std::vector or “isomorphic” applications).
I would personally define combinator as function that allows one to compose larger structure (in very abstract sense) by combining smaller pieces of the structure. The most common example of this in Elm is json
Decoder which has combinators. It for instance allows to combine
Decoder Int and
Decoder String into Decoder of pair of those and then combinator for producing Decoder of List of those composite decoders. This is something I would expect from any API that describes itself as being combinators based. I also think such library should not be closed over specific type. Some examples of what I would call combinators based API in elm:
For better or worse the Glue library is not as much about what it provides as it is about what it encourages. I originally designed it when working on quite large and complicated single-page application in a team where many members were quite new to the functional programming. There are few things that at least I personally believe lead to more extensible and easier to work with code. Let me mention few first
Use Records not Sums (for model)
I think modeling application state as record (product) rather than sum (or enum if you like) is better. Not only that it will help you avoid akward double pattern matching on
Msg constructor as well as some
Page type. It’s also more accurate model. Pretending that the previous page is dead just because route change leads to limitations in functionality. Also who is to really guarantee that is the case in presence of concurrency. Furthermore modeling some sort of
Page sum type breaks the single source of truth. What route is being active should be described by
Route data, duplicating this information is problematic. There might still be a good reasons to choose sum type over record but I don’t think sums should be automatic default
No Triplets (in update)
This pattern was used by some folks in community for a while. I was never big fan of it. In my opinion the comunication upwards should always be async to keep dataflows simple. Otherwise the boundaries of what is touching what starts to be completely invisible in the code which makes debugging quite painful.
Avoid Types module at all cost
Another pattern I wanted to avoid (which was quite popular at some time) was splitting your app into files like this:
- Types.elm - contains Msg and model definition to avoid circular deps (terrible on its own)
- Update.elm - contains giant update function (which is based on Msg and Model of course)
- View.elm - contains giant view
I disliked this type of separation with passion To me it never made sense to “split” something into modules that all depends on each other. I think such split was actually more harmful than anything else because not only that everything depend on everything the definition of that stuff was also always in some other module.
Glue is in fact just a simple lens and not much more. Beside the definition of accessor for the nested module it only contains the function from one Msg type to the other. This is traditionally just one of the Msg constructors of a consumer/parent module. There are some neat things like
compose function which might hint you that there is some underlying algebraic thing hidden perhaps but the functionality that glue provides is far less important or mostly equivalent to what you can get by following recommendations above. Perhaps with addition of:
- in any exposed function your last argument should be
- you can forget about field and Msg constructor names and remember just name of glue type
- when combining a lot of these things it feels just a tiny bit more compositional
I can’t compare it to tea-combine library because I did not know it but I think it’s cool to see people trying new ways of doing things.
All comments above are my personal opinions based on my personal biases jadyjadydada. If anything I think we should avoid being too emotionally attached to any particular way of doing / naming things. Point should be to try to improve and help the community, not to have flame wars because our ego is too attached to some way of structuring code over the other.