Elm Ducks
Question
We have a function that sums a list of items by their .cost
values. We want
to use it to sum another list of items with .cost
, but the items are different
types.
Is there a way to write annotations to match “anything with this type of field”?
type alias Foo = { cost : Int }
type alias Bar = { cost : Int, isIron : Bool }
sumItems : List Foo -> Int
sumItems items =
List.foldl (\x acc -> x.cost + acc) 0 items
fooSum = sumItems listOfFoos
barSum = sumItems listOfBars
Answer
We can define a type that just has some fields like this.
sumItems : List ({ a | cost : Int }) -> Int
sumItems items =
List.foldl (\x acc -> x.cost + acc) 0 items
Foo
and Bar
satisfy this type, so we can now reuse sumItems
.
Bonus
If you’re using the generic type a lot, you can still use a type alias to keep things more succinct.
This example shows how we can replace something in a list of “records with an
id
field” generically.
type alias WithId a = { a | id : String }
updateById : String -> (WithId a -> WithId a) -> List (WithId a) -> List (WithId a)
updateById id getNewItem list =
List.map
(\x ->
if x.id == id then
getNewItem x
else
x
)
list
See the docs for more detail on dealing with records.