relude-fetch
relude-fetch copied to clipboard
Example code without infix operators
I'm struggling to understand the decoding example in the tests
let decode: Js.Json.t => Belt.Result.t(t, string) =
json => {
make
<$> JD.intFor("userId", json)
<*> JD.intFor("id", json)
<*> JD.stringFor("title", json)
<*> JD.boolFor("completed", json)
|> Relude.Result.fromValidation
|> Relude.Result.mapError(_ => "Decode failed");
};
Would this be equal to the following?
let decode: Js.Json.t => Belt.Result.t(t, string) =
json => {
make
|> map(JD.intFor("userId", json))
|> ap(JD.intFor("id", json))
|> ap(JD.stringFor("title", json))
|> ap(JD.boolFor("completed", json))
|> Relude.Result.fromValidation
|> Relude.Result.mapError(_ => "Decode failed");
};
With some direction, I'd be glad to open a PR adding examples sans infix operators. It would be nice to able to see the two versions side by side for mere mortals like I.
This is a bit of a weird one, because the "prefix" version of <$>
expects the make
function to be its first argument, which it will partially apply to the decoded value e.g. map(make, JD.intFor(...))
. Then it will pass what's left of the make
function as the first argument to <*>
, etc. Expanded out, this means things get very nest-y without infix functions:
ap(
ap(
map(make, JD.intFor("userId", json)),
JD.intFor("id", json)
),
JD.stringFor("title", json)
)
However! The special ->
operator, of all things, might be useful here because it sends the thing on the left (the make
function in this case) into the first slot. I haven't actually tried this, but make->map(...)->ap(...)->ap(...)
seems like it should work.
Alternatively, bs-decode's pipeline (inspired by Elm and built around a flipped version of ap), can be used to avoid the infix functions. Or for a small example like this, maybe it makes sense to just use Result.map4
. Eventually the new let syntax will get merged and we can avoid all of this. :slightly_smiling_face:
Interesting. For some reason I was under the impression that JD
decoders is specific to using IO
which seemingly isn't the case. I'm using bs-decode
in my project currently, so I'll go on using that one.
Would you be interested in a PR that adds a bs-decode
example to the README (or wherever else you prefer)?
Just to add to what @mlms13 said, and to provide more background:
The JD
stuff is using the Validation
type, not IO
. Validation
is an functor/applicative/monad just like all the others, so it works with the usual map
/apply
/bind
and <$>
/<*>
/>>=
operators the same as everything else (IO
, Result
, etc.). The bs-decode type follows the same pattern, so this wouldn't behave fundamentally differently for bs-decode in terms of the low-level map/apply/<$>/<*> piping semantics. However bs-decode offers a more streamlined API because it basically flips the order of arguments for apply
so that it works better with |>
. (Like @mlms13 said above).
https://github.com/mlms13/bs-decode/blob/master/src/DecodeBase.re#L210
<$>
is just an alias for let map: ('a => 'b, t('a)) => t('b)
<*>
is an alias for let apply: (t('a => 'b), t('a)) => t('b)
so make <$> someApplicativeValue
is the same as map(make, someApplicativeValue)
, so like @mlms13, if you wanted to use piping, you'd need to use ->
rather than |>
in this example, like make -> map(someApplicativeValue)
, so the make
function is injected as the first argument.
You could use flipped versions of map
and apply
, and that would work with |>
.
Anyway, the point of these tests isn't really to demonstrate how applicative-style decoding works, so maybe it would be best to just take this out of the tests, and just focus on the fetch calls. For usage of bs-decode, it would be better to refer to the docs in bs-decode. That said, I think it's worth the time to learn how <$>
/<*>
works, because that's a pattern you'll see often in the more powerful FP languages, and it's also the same general pattern as many parsing/decoding libraries.
Thanks for the clarification guys :) I intend to learn more about infix and figured a side by side example would help. If there's anything I could do to help with documentation, just point it out and I'll open a PR.