First of all, thank you for your suggestions! I am glad you seem to like it.
I would advise using records and type aliases for this. Also, Forms are composable, so it should be easy to split them in different parts.
It initializes a form with no fields. It would be similar to Json.Decode.succeed. Form.map would have a different connotation, and it would probably be used to apply a function to the output of the form, like Json.Decode.map.
A Form represents a collection of fields. For me, Form.field would not exactly describe what the function does. I wouldn’t expect Form.field to take two Form values and return a new one. However, I agree that it would look more readable if we ignore what the |> operator is doing. There is also Form.appendMeta, but I guess we could rename it to Form.metaField or something along these lines. I will think about it!
You probably noticed this, but I want to remark that a Form type is completely opaque and should never be used in the Model, as it is mostly made of functions. In the examples, model.form is a Form.View.Model value. This is just a very simple record that is used to render the form with the particular renderer that would come with the package (anyone can implement a renderer). There is an example where I reuse model.form in two different forms.
We used to have Form.View.Model as an opaque type, but many times we need fine-grain control over the showErrors and state attributes, and using helpers felt like implementing setters and getters. That’s why I think a simple record is more appropriate. As I see it, the record is just a way to gather 3 different attributes that have nothing to do with each other, and that they could be passed individually to Form.View functions. I understand that an opaque type would give Form.View more room to change freely. Trade-off?
Thank you again!