Refraction of the matter
I’ve been meaning to get back to posting on this blog. So in order to make it easy on myself I bring you a short one today.
As I see everyone discussing the latest AI model release on Twitter, I find myself thinking that no matter what I have used AI for, it hasn’t really beat my imagination or brought me groundbreaking concepts I wasn’t searching for. So I think, at least as it stands, learning new programming concepts is very valuable.
When using immutable data structures, one problem that emerges is when you want to update a deeply nested one, you end up with a lot of boilerplate to do so. It’s common in functional programming languages to have an optics library to address this, like lens for Haskell or monocle for Scala.
I built a little library for my programming language and you can have a look at the more interesting part of the motivating example below. While it’s still a bunch of code to get the structure that allows for the succinct update, those parts are composable and reusable.
The first unit test is without using the library and the second one is using the library.
_ := UnitTest("manual update every nested email", (testkit): Void => {
company := exampleCompany
// Read every nested email by walking each level manually.
emailValues := company.people->listFlatMap((person: Person): List<String> => {
person.contacts->listFlatMap((contact: Contact): List<String> => {
when contact {
is emailContact: EmailContact => {
[emailContact.email.value]
}
other => {
<String>[]
}
}
})
})
testkit.assert.equal(["ada@example.test", "grace@example.test"], emailValues)
// Update every nested email by rebuilding each level manually.
updated := Company(
company.name,
company.people->listMap((person: Person): Person => {
Person(
person.name,
person.contacts->listMap((contact: Contact): Contact => {
when contact {
is emailContact: EmailContact => {
EmailContact(Email(emailContact.email.value->join(".verified")))
}
other unchanged => {
unchanged
}
}
})
)
})
)
testkit.assert.equal(
Company(
"Analytical Engines",
[
Person(
"Ada",
<Contact>[
EmailContact(Email("ada@example.test.verified")),
PhoneContact("+41 555 0100")
]
),
Person(
"Grace",
<Contact>[
EmailContact(Email("grace@example.test.verified"))
]
)
]
),
updated
)
})
_ := UnitTest("showcase updates every nested email", (testkit): Void => {
company := exampleCompany
// Lens: Company -> List<Person>
companyPeopleLens := companyLenses.people
// Traversal: Company -> every Person
peopleInCompany := companyPeopleLens->lensAndThenTraversal(each<Person>())
// Traversal: Company -> every List<Contact>
contactListsInCompany := peopleInCompany->traversalAndThenLens(personLenses.contacts)
// Traversal: Company -> every Contact
contactsInCompany := contactListsInCompany->traversalAndThenTraversal(each<Contact>())
// Traversal: Company -> every Email inside matching EmailContact cases
emailsInCompany := contactsInCompany->traversalAndThenPrism(emailContact)
// Traversal: Company -> every email String inside those Email wrappers
emails := emailsInCompany->traversalAndThenIso(emailString)
// Read every focused value.
testkit.assert.equal(["ada@example.test", "grace@example.test"], emails.toList(company))
// Modify every focused value.
// The phone contact is ignored because the emailContact prism does not match it.
updated := emails.modify(company, (email: String): String => {
email->join(".verified")
})
testkit.assert.equal(
Company(
"Analytical Engines",
[
Person(
"Ada",
<Contact>[
EmailContact(Email("ada@example.test.verified")),
PhoneContact("+41 555 0100")
]
),
Person(
"Grace",
<Contact>[
EmailContact(Email("grace@example.test.verified"))
]
)
]
),
updated
)
})

