I think I will go with the Dec.succeed, because it keeps the name of the type in the function
Just for full understanding, you can keep “the name of the type” in the function in the map2
situation too:
decodeLocations : Decoder (List Location)
decodeLocations =
Dec.field "locations"
(Dec.list
(Dec.map2 (\id name -> Location id name True)
(Dec.field "id" Dec.int)
(Dec.field "name" Dec.string)
)
)
The map3
version can also be written that way:
decodeLocations : Decoder (List Location)
decodeLocations =
Dec.field "locations"
(Dec.list
(Dec.map3 (\id name checked -> Location id name checked)
(Dec.field "id" Dec.int)
(Dec.field "name" Dec.string)
(Dec.succeed True)
)
)
However, directly calling Location
like that is usually frowned upon. It’s much more clear to just “build the record instead”: { id = id, name = name, checked = checked }
. But it’s good to know that when you make a type alias Foo
for a record (yes, only for records!), you get not only a type named Foo
, Elm also auto-generates a function called Foo
that takes all the stuff in the record in order and builds such a record. It is that auto-generated function that you use in the body of decodeLocations
, while the type with the same name is used in the decodeLocations : Decoder (List Location)
type annotation.
Yet one way of doing it is exploiting the fact that the auto-generated function takes the record contents in a specific order. So you could move checked : Bool
first in the record, then you could do (but I’m not saying it’s a good solution!):
type alias Location =
{ checked : Bool
, name : String
, id : Int
}
decodeLocations : Decoder (List Location)
decodeLocations =
Dec.field "locations"
(Dec.list
(Dec.map2 (Location True)
(Dec.field "id" Dec.int)
(Dec.field "name" Dec.string)
)
)
You don’t need to understand all of those details right now, but it might be handy some time! Either way, I like @Atlewee’s solution best too.
Any suggestions on a good beginners tutorial on Json decoding?
This blog post was enlightening for me at least: