Isn't this exactly the problem solved by all the lens packages? Current popular ones are fclabels [0] and data-lens [1].
[0] http://hackage.haskell.org/package/fclabels [1] http://hackage.haskell.org/package/data-lens On Thu, Aug 2, 2012 at 7:34 AM, Jonathan Geddes <geddes.jonat...@gmail.com> wrote: > Greetings, > > tl;dr - What Haskell Records need are > semantic editor combinators for free. > > I know this is yet another Record proposal > among many, but none of them out there > strike me as being exactly what I want in > Haskell. > > Take the following types from a contrived > example. > >>type Salary = Integer >> >>data Job = Job >> { title :: String >> , salary :: Salary >> } >> >>data Person = Person >> { name :: String >> , job :: Job >> } > > Since I've used record syntax, I get > getter/accessor functions (title, salary, > name, job) for free. Now suppose I want to > 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 > kinds of updates. > > 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 > State Monad. > >> 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. > > Thanks for reading, > > --Jonathan > > [0] - http://conal.net/blog/posts/semantic-editor-combinators > [1] - > http://hackage.haskell.org/packages/archive/sec/0.0.1/doc/html/Data-SemanticEditors.html > > > > > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe > _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe