thoughtbot/Argo

Suggestion to simplify a bit

mbrandonw opened this issue ยท 7 comments

Currently y'all suggest people follow this template when decoding a value:

return curry(self.init)
  <^> json <| "key1"
  <*> json <| "key2"
  <*> json <| "key3"

Needing to use two operators is a bit confusing to new comers, and can cause strange error messages if you mix em up, or rearrange terms later and the order of <^> and <*> get moved around.

I suggest we tell people to follow this pattern instead:

return pure(curry(self.init))
  <*> json <| "key1"
  <*> json <| "key2"
  <*> json <| "key3"

we now only use one operator at the cost of introducing pure. I think we could describe pure as simply a means of lifting the constructor into the Argo world so that it is enhanced with the idea of failing to construct from json. And then we only have to describe one operator <*> as a means of one-by-one trying to decode keys and plug them into the initializer. Now we are free to move around the terms anyway we need without messing up the operators.

Whatdy'all think? I could prob update some of the docs if we wanted to go this route.

Hey @mbrandonw, what you discovered does work, but it is (IMHO) a deficiency in Swift's type system that allows this. The way we're teaching people to use Argo is "correct" as far as functional programming semantics go. My hope is that user's of Argo see past the operators and eventually (maybe not immediately) explore their concepts (which actually has more to do with Runes than Argo). For beginners, they have to know that <^> comes first and that's it, use <*> everywhere else. If you think the documentation is lacking to explain that then that would definitely be something I'd like to improve.

I just noticed the pure. I think I still prefer the original way but I'm curious what others think.

Yeah, pure is essential for sure. Sorry, I wasn't suggesting to overload <*> or curry in non-standard ways.

I will say that in the spirit of unlocking concepts to new comers, this form does that as well. Often in papers, when discussing the applicative style, authors will go straight for the canonical form of pure f <*> x_1 <*> x_2 <*> ... <*> x_n, so much so that many even create a specific syntax of idiom brackets to express it: [( f x_1 x_2 ... x_n )]. In that syntax the applicative style looks like regular old function application.

My hope is that user's of Argo see past the operators and eventually (maybe not immediately) explore their concepts

This is exactly how I started with Argo. At first, for pretty much ever model I decoded, I looked up which operator went first. Eventually I got to do some Haskell and discovered that the operators aren't just Argo specific.

From my perspective, if something had to be improved, I would say it's making people aware that these operators are fairly standard and perhaps link/explain where to learn more about them.

Worth noting also that the one operator I'm omitting <^> is the one that is not found in Haskell since we can't do <$>.

I'm ๐Ÿ‘ on this. Any interest in opening a PR to make these changes?

I'm going to go ahead and close this due to inactivity, but I'd still be ๐Ÿ‘ on a PR making these changes to the documentation.