Generating record update functions to be used as parameters

The HasField typeclass from DA.Record is perfect for this!

HasField gives you getter and setter functions for each record field automatically. The stdlib documentation is a bit lacking currently, so let me try to explain how you can use it.

HasField x r a is a typeclass that takes three parameters. The first parameter x is the field name, the second parameter r is the record type, and the last parameter a is the type of the field in this record. For example, if I define a type:

data MyRecord = MyRecord with
    foo : Int
    bar : Text

Then I get, for free, the following HasField instances:

HasField "foo" MyRecord Int
HasField "bar" MyRecord Text

If I want to get a value using HasField, I can use the getField function:

getFoo : MyRecord -> Int
getFoo r = getField @"foo" r

getBar : MyRecord -> Text
getBar r = getField @"bar" r

Note that this uses the “type application” syntax (f @t) to specify the field name.

Likewise, if I want to set the value in the field, I can use the setField function:

setFoo : Int -> MyRecord -> MyRecord
setFoo a r = setField @"foo" a r

setBar : Text -> MyRecord -> MyRecord
setBar a r = setField @"bar" a r

Note that in all these examples I don’t have to pass in the arguments explicitly. I could have written it this way:

getFoo : MyRecord -> Int
getFoo = getField @"foo"

getBar : MyRecord -> Text
getBar = getField @"bar"

setFoo : Int -> MyRecord -> MyRecord
setFoo = setField @"foo"

setBar : Text -> MyRecord -> MyRecord
setBar = setField @"bar"

So to answer the original question, you can use setField @"a" to set the "a" field in your record. And this will work for any record type with an "a" field.

HasField is actually part of Daml’s built-in mechanism for record handling, and it’s used by the Daml compiler, so it’s something that is specifically optimized in the Daml compiler. As long as the record type is fixed (i.e. not polymorphic), it should be as efficient as writing a record get/set manually. So, compared to using a Lens library, this shouldn’t have any negative performance impact.

5 Likes