joneshf / purescript-option

MIT License
37 stars 15 forks source link

Discuss possible PR for projection #9

Open bbarker opened 5 years ago

bbarker commented 5 years ago

Now that I'm back to using Option I realized I needed another function, project. I also combined this with the recently added (in PR) getAll to get a convenience function, getSubset. It works well, but there are a few possible discussion points I can think of already:

  1. Is there a way to implement project without resorting to the FFI (the unexported utility function pickFn)? This is based almost exactly on pickFn from Record-Extra, but an undefined guard is needed here since Foreign.Object can have missing values, whereas a Record cannot. In any case I tried a few things to this end, namely using alter, but ran out of steam trying to massage the types. Denis Stoyanov had this note on Slack, which I'm not sure I follow exactly:

    I use it likenewtype MyRecord (r :: # Type) = MyRecord (FO.Object (Exists Identity)) but just for example what is record will be

  2. I'm relying on Records.Extra just to get the Keys class and related functions, but we might want to reconsider this.
  3. Of course add docs when the dust settles.

Here is the branch and commit as of this posting.

joneshf commented 4 years ago

Sorry, I totally missed this. Is this still relevant, or have you figured a way out here? Happy to have the discussion, but don't want to if you're already good.

bbarker commented 4 years ago

@joneshf I think it is still relevant, but not urgent in the sense I have a workaround. But the two proposed functions (project and getSubset) seem generally useful. However, the way I've implemented them may not be ideal.

joneshf commented 4 years ago

Gotcha.

I'm not really sure what you're wanting to do with these two values. Is there a brief example of how you might use these? Based on the names, I'm making the assumption that you've got a big option and you want a smaller one. Is that about right?

Forgive me if you've already figured this out, but I also wonder if this is something that can be solved with row-polymorphism? Sometimes with these problems, if we open the row on a value (not on the type, necessarily), it can solve these problems. Sometimes inference messes up, so it's not a panacea.

For example, if we've got this:

type Person
  = Option
      ( firstName :: String
      , lastName :: String
      )

displayName ::
  Person ->
  String
displayName person = case firstName person, lastName person of
  Just first, Just last -> first <> " " <> last
  Just first, Nothing -> first
  Nothing, Just last -> last
  Nothing, Nothing -> "Anonymous"

firstName ::
  Person ->
  Data.Maybe.Maybe String
firstName person = Option.get (Data.Symbol.SProxy :: _ "firstName") person

lastName ::
  Person ->
  Data.Maybe.Maybe String
lastName person = Option.get (Data.Symbol.SProxy :: _ "lastName") person

But we don't want firstName and lastName to know about the whole person, we can change them to something like:

firstName ::
  forall option.
  Option
    ( firstName :: String
    | option
    ) ->
  Data.Maybe.Maybe String
firstName person = Option.get (Data.Symbol.SProxy :: _ "firstName") person

lastName ::
  forall option.
  Option
    ( lastName :: String
    | option
    ) ->
  Data.Maybe.Maybe String
lastName person = Option.get (Data.Symbol.SProxy :: _ "lastName") person