[9:56]
decodeModel will return a result of Ok { name = "noah", age = 10 }
[9:56]
decodeField is a scary looking thing which is actually pretty simple:
[9:56]
String
-> Json.Decoder a
-> (Model -> a -> Model)
-> Json.Value
-> Result String Model
-> Result String Model
decodeField fieldName decoder setter value model =
case model of
Err s -> model
Ok v ->
Json.decodeValue (Json.field fieldName decoder) value
|> Result.map (setter v)
[9:56]
(there are various ways of cleaning this up some more, but this is how you do out-of-order decoding in elm)
[9:59]
It could be further simplified if elm provided a couple of things. Namely, things that were taken out of the type system that didn't need to be (e.g adding fields to a record - then we wouldn't need to provide a default)
[9:59]
This approach is infinitely more workable.
[10:00]
You can make refactoring changes to your model without worrying about the order
[10:00]
If you have the right tooling, then generating setters/getters is trivial
[10:00]
Anyway, the other point: notice how I flatten the types as soon as possible.
[10:01]
People get so confused when they see Decoder a and don't know how to make their own
fredcy [10:01 AM]
Fascinating. But my brain hurts. I hope someday you'll write this up. (I know that's not your thing though).
eeue56 [10:02 AM]
Which bit is making your brain hurt? Maybe I can explain that a bit better
fredcy [10:04 AM]
The role of the first line of decodeModel puzzles me. Just haven't seen record values built up from a default as that appears to be.
rtfeldman [10:12 AM]
AndMap (not a big fan of the name either) is exactly the right tool for the job
of course, the json-pipeline library aliases andMap, but to understand how that decoder works, you need to know how andMap works
this is not a great pitch for andMap the function itself as opposed to the concept behind it :wink:
eeue56 [10:15 AM]
@fredcy, it's exactly what decode does in elm-decode-pipeline
glenjamin [10:15 AM]
@eeue56 when thinking about it, I found the Generator one harder to refactor (only tried in my head) because of the need to chain the RNG state around - did I miss something?
eeue56 [10:15 AM]
You can think of it as "raising" or "lifting" a value into a type. Basically, just taking a Model and turning into Result x Model
[10:16]
which can then be piped down to the other functions, so they can keep a clean sig
[10:16]
@glenjamin you can pass the state onwards in the same way through a tuple if you want
[10:16]
I just didn't for the decode example since it doesn't need it
glenjamin [10:17 AM]
ah right, same general approach then - you get something like bind and return, but name them based on the concrete case?
eeue56 [10:19 AM]
you'd need a return for that example yeah
Okay, so in terms of implementing Json without depending on order
[9:52]
Let's start by defining a simple mode:
[9:52]
[9:53]
Nothing fancy really. Now let's describe how we'd like our decoders to look:
[9:53]
[9:53]
Notice how I've gotten rid of the confusing
Decoder
abstraction for now[9:53]
Also notice that name and age are out of place
[9:54]
Also notice that I define setAge and setName, lens style
[9:55]
they're mostly boilerplate but for clarity, this is what they look like:
[9:55]
finally, we use it like this:
[9:56]
decodeModel will return a result of
Ok { name = "noah", age = 10 }
[9:56]
decodeField is a scary looking thing which is actually pretty simple:
[9:56]
[9:56]
(there are various ways of cleaning this up some more, but this is how you do out-of-order decoding in elm)
[9:59]
It could be further simplified if elm provided a couple of things. Namely, things that were taken out of the type system that didn't need to be (e.g adding fields to a record - then we wouldn't need to provide a default)
[9:59]
This approach is infinitely more workable.
[10:00]
You can make refactoring changes to your model without worrying about the order
[10:00]
If you have the right tooling, then generating setters/getters is trivial
[10:00]
Anyway, the other point: notice how I flatten the types as soon as possible.
[10:01]
People get so confused when they see
Decoder a
and don't know how to make their ownfredcy [10:01 AM]
Fascinating. But my brain hurts. I hope someday you'll write this up. (I know that's not your thing though).
eeue56 [10:02 AM]
Which bit is making your brain hurt? Maybe I can explain that a bit better
fredcy [10:04 AM]
The role of the first line of
decodeModel
puzzles me. Just haven't seen record values built up from a default as that appears to be.rtfeldman [10:12 AM]
this is not a great pitch for
andMap
the function itself as opposed to the concept behind it :wink:eeue56 [10:15 AM]
@fredcy, it's exactly what
decode
does in elm-decode-pipelineglenjamin [10:15 AM]
@eeue56 when thinking about it, I found the Generator one harder to refactor (only tried in my head) because of the need to chain the RNG state around - did I miss something?
eeue56 [10:15 AM]
You can think of it as "raising" or "lifting" a value into a type. Basically, just taking a
Model
and turning intoResult x Model
[10:16]
which can then be piped down to the other functions, so they can keep a clean sig
[10:16]
@glenjamin you can pass the state onwards in the same way through a tuple if you want
[10:16]
I just didn't for the decode example since it doesn't need it
glenjamin [10:17 AM]
ah right, same general approach then - you get something like
bind
andreturn
, but name them based on the concrete case?eeue56 [10:19 AM]
you'd need a return for that example yeah