Reputation: 2710
In Elm, one of my records (the type alias
construct) have a lot of entries, and I was wondering if there's a built-in way to iterate through it. Either directly or by converting it to a Dict
So I was thinking something like:
let
myRecord = MyRecord ...
showEntry key value = ...
in
map showEntry myRecord
Thanks for your time!
To answer the questions about the actual data, I have 12 fields of the same type. The 12 fields are all required to have that exact name, hence the record type and not a Dict
. Whether it's named as a string in a record or a type in itself doesn't matter, as long as I can uniquely identify that value from the other 11. In code the record looks something like:
type alias InnerType { value : Int, ... }
type alias Record = { inner1 : InnerType, inner2 : InnerType, ... }
Since all the fields in the record have the same type, I just wanted to see if there's an easier way to go through them instead of naming all 12. Unless there's a better way to represent this, in which case I'm all ears! :-)
Upvotes: 1
Views: 1125
Reputation: 36385
If your record will only ever have twelve elements and you don't mind sacrificing a little verbosity in your type definition for type safety (make impossible states impossible!), you could start with enumeration of those twelve indexes:
type Index
= Inner1
| Inner2
...
| Inner12
You could redefine Record
to a type
instead of a record type alias:
type Record =
Record
InnerType
InnerType
-- repeat InnerType 12 times
Now you can create a few convenience functions for getting and setting values in a type-safe manner:
get : Index -> Record -> InnerType
get i (Record i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12) =
case i of
Inner1 -> i1
Inner2 -> i2
...
Inner12 -> i12
set : Index -> InnerType -> Record -> Record
set i val (Record i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12) =
case i of
Inner1 -> Record val i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12
Inner2 -> Record i1 val i3 i4 i5 i6 i7 i8 i9 i10 i11 i12
...
Inner12 -> Record i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 val
And you can create a list from your record like this:
toList : Record -> List InnerType
toList (Record i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12) =
[ i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12 ]
As you can see, this gets verbose, but it's only in the definition of the Record type that it becomes verbose. If you confine all this code to a Record
module, then accessing and modifying records is clean, concise, and more importantly, type safe. You are not subject to a Dictionary where a key may not exist, or a List or Array where an index might not exist. Your Record type would be sealed up nice and tight, at the expense of a little verbosity in the definition.
Here is a gist containing the full definition.
Upvotes: 5
Reputation: 21037
Looks like you need a List
(or an Array
) of InnerType
, as you said the structure itself is fixed at 12 of these. As for iterating, here's the example for json encoding a list of InnerType
inners
|> List.indexedMap (\idx inner -> ("inner" ++ toString idx, encodeInner inner))
|> Json.Encode.object
Upvotes: 2