Andrew Butterfield Andrew.Butterfield at scss.tcd.ie
Thu Aug 2 12:30:57 CEST 2012

```On 2 Aug 2012, at 09:25, Erik Hesselink wrote:

> Isn't this exactly the problem solved by all the lens packages?
> Current popular ones are fclabels [0] and data-lens [1].
>

Not sure what all of these do, but I have a simple solution I use
in my work:
>
>> Take the following types from a contrived
>> example.
>>
>>> type Salary = Integer
>>>
>>> data Job = Job
>>> { title  :: String
>>> , salary :: Salary
>>> }

Rather than setTitle :: String -> Job -> Job  we lift the first argument
and define

setfTitle  :: (String -> String) -> Job -> Job
setfTitle f jobrec = jobrec{ title = f \$ title jobrec }

then setTitle = setfTitle . const

This is all just boilerplate, so we continue

setfSalary :: (Salary -> Salary) -> Job -> Job
setfSalary f jobrec = jobrec{ salary = f \$ salary jobrec }

>>>
>>> data Person = Person
>>> { name :: String
>>> , job  :: Job
>>> }
>>

setfName :: (String -> String) -> Person -> Person
setfName f prec = prec{ name = f \$ name prec }

setfJob :: (Job -> Job) -> Person -> Person
setfJob f prec = prec{ job = f \$ job prec }

Now we can use function composition to do two levels

setfTitleInPerson :: (String -> String) -> Person -> Person
setfTitleInPerson = setfJob . setfTitle

setTitleInPerson :: String -> Person -> Person
setTitleInPerson = setfTitleInPerson . const

Simple function composition works to put these together...

I was frustrated by this problem a while back, and decided to approach it formally
(I write literate Haskell/LateX documents), and went to work, doing the math
with the intention of writing a suitable combinator, until I discovered I didn't
need one .... lifting from  X -> R -> R   to (X -> X) -> R -> R gave me all I needed...

>> Since I've used record syntax, I get
>> getter/accessor functions (title, salary,
>> create an aggregate getter function: return
>> the salary of a given person. Piece of cake,
>> it's just function composition
>>
>>> getSalary :: Person -> Salary
>>> getSalary = salary . job
>>
>> Done! Now suppose I want to write a
>> setter/mutator function for the same nested
>> field
>>
>>> setSalaryMessy :: Salary -> Person -> Person
>>> setSalaryMessy newSalary person =
>>> person {
>>>  job = (job person) {
>>>    salary = newSalary
>>>  }
>>> }
>>
>> Ouch! And that's not even very deeply nested.
>> Imagine 4 or 5 levels deep. It really makes
>> Haskell feel clunky next to `a.b.c.d = val`
>> that you see in other languages. Of course
>> immutability means that the semantics of
>> Haskell are quite different (we're creating
>> new values here, not updating old ones) but
>> it's still common to model change using these
>>
>> What if along with the free getters that
>> the compiler generates when we use record
>> syntax, we also got semantic editor
>> combinator (SEC) functions[0] that could be
>> used as follows?
>>
>>> setSalary newSalary = job' \$ salary' (const newSalary)
>>>
>>> giveRaise amount = job' \$ salary' (+amount)
>>>
>>> givePercentRaise percent = job' \$ salary' (*(1+percent))
>>
>> For each field x, the compiler generates a
>> function x' (the tic is mnemonic for change).
>> These little functions aren't hard to write,
>> but they're classic boilerplate.
>>
>>> job' :: (Job -> Job) -> Person -> Person
>>> job' f person = person {job = f \$ job person}
>>
>>> salary' :: (Salary -> Salary) -> Job -> Job
>>> salary' f job = job { salary = f \$ salary job}
>>
>> These type of utility functions are a dream
>> when working with any reference type or
>>
>>> modify \$ givePercentRaise 0.25
>>
>> The compiler could also generate polymorphic
>> SEC functions for polymorphic fields.
>> Further, the compiler could disallow using
>> old-style update syntax for fields whose SEC
>> update function is not in scope, giving us
>> fine-grained control over access and update.
>> On the other hand we currently have to create
>> new functions to achieve this (exporting the
>> getter means exporting the ability to update
>> as well, currently).
>>
>> Of course this doesn't address the
>> namespacing issues with records, but it is
>> likely nicely orthogonal to other proposals
>> which do.
>>
>> Also note that there's a package on hackage [1]
>> that will generate SEC functions using TH.
>> It's nice, but I prefer the style of field
>> names used above for updaters (field' vs
>> editField).
>>
>> Let me know what you think. I'll write up an
>> official proposal if there's a bit of
>> general interest around this.
>>
>>
>> --Jonathan
>>
>> [0] - http://conal.net/blog/posts/semantic-editor-combinators
>> [1] -
>>
>>
>>
>>
>> _______________________________________________
>>
>
> _______________________________________________

--------------------------------------------------------------------
Andrew Butterfield     Tel: +353-1-896-2517     Fax: +353-1-677-2204
Lero at TCD, Head of Foundations & Methods Research Group
Director of Teaching and Learning - Undergraduate,
School of Computer Science and Statistics,
Room G.39, O'Reilly Institute, Trinity College, University of Dublin
http://www.scss.tcd.ie/Andrew.Butterfield/
--------------------------------------------------------------------
--------------------------------------------------------------------
Andrew Butterfield     Tel: +353-1-896-2517     Fax: +353-1-677-2204
Lero at TCD, Head of Foundations & Methods Research Group
Director of Teaching and Learning - Undergraduate,
School of Computer Science and Statistics,
Room G.39, O'Reilly Institute, Trinity College, University of Dublin
http://www.scss.tcd.ie/Andrew.Butterfield/
--------------------------------------------------------------------

```