joneshf / purescript-option

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proposal: getAll alternative that returns an Either with errors (missing required fields)

bbarker opened this issue · comments

In certain cases, it may be useful to quickly ascertain why a Record wasn't obtained, rather than just having Nothing. So instead of just:

getAll :: forall option record. GetAll option record => Option option -> Maybe (Record record)

It may be useful to have something like:

getAllWithError :: forall option record. GetAll option record => Option option -> Either (Tree String) (Record record)

In this case, the Left Tree would ideally be a sort of "stack trace" (except it is an Option trace here) that includes the fields that were absent. Here's an example mockup (if I've got this right):

type Inner = Option.Record ( reqInner :: String ) ( optInner :: Number) 
type Outer = Option.Record ( reqOuter :: Inner ) ( optOuter :: String ) 

If getAllWithError was called on Option.Empty, it would ideally return something like Left (Node { children : [Node {children: [], value: "reqInner"}], value : "reqOuter" }.

Alternatively, it may simply be best to have a function that could query which required fields are missing, and if it has nested options, show this as well. E.g., it could report ["reqOuter:reqInner"] for the above example.

Heya!

I'm down to give this a whirl. Lemme try to throw something together when I get a minute.

Also, you've raised a few issues related to nested options. To be honest, I'm not sure I really get when it'd be useful to have to deal with them. We have a few types at work where an option has an option in it and it's kind of a real pain to deal with. The easier thing is usually to flatten them to one level and namespace the field. E.g.:

type Foo
  = Option.Option
      ( foo :: Int
      , bar :: Bar
      )

type Bar
  = Option.Option
      ( baz :: Boolean
      , qux :: String
      )

would become:

type Foo
  = Option.Option
      ( foo :: Int
      , barBaz :: Boolean
      , barQux :: String
      )

I know that's not always possible, so I'm not trying to suggest that you do that everywhere. But, I'm curious if you've found that to be an alternative to having nested options.

I'm always open to making things better for the nested case, if possible.

Thanks!

Regarding nested options, I agree that it is probably not ideal when given the choice, but in my case, it comes up in the context of making a View-Model (option) out of a Model (record) type. The complete record corresponds to the compete Model, and some sub-records are embedded within it. In this case, it seemed natural to model it in a nested fashion, rather than manually constructing a large, flat model.

Actually, some recent experience in Haskell also taught me to prefer the flat choice for many situations.