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