[Haskell-cafe] Some thoughts on Type-Directed Name Resolution

Evan Laforge qdunkan at gmail.com
Thu Feb 9 01:15:27 CET 2012

On Wed, Feb 8, 2012 at 2:47 PM, Malcolm Wallace <malcolm.wallace at me.com> wrote:
> On 8/02/2012, at 14:16, Steve Horne <sh006d3592 at blueyonder.co.uk> wrote:
>> I haven't given a lot of thought to updates.
> I very much fail to see the point of replacing prefix function application with postfix dots, merely for field selection.  There are already some imperfect, but adequate, solutions to the problem of global uniqueness of field names.  But you now have mentioned what is really bothering me about this discussion: record updates are simply the most painful and least beautiful part of the Haskell syntax.  Their verbosity is astonishing compared to the careful tenseness of every other language construct.  If we could spend some effort on designing a decent notation for field updates, I think it would be altogether more likely to garner support than fiddling with dots.

It's already possible, here's what I've been experimenting with, using fclabels:

import Data.Label

-- | Compose lenses.
(#) :: (a :-> b) -> (b :-> c) -> (a :-> c)
(#) = flip (.)
infixr 9 #

-- | Get: @bval = a#b $# record@
($#) :: (f :-> a) -> f -> a
($#) = get
infixr 1 $#

-- | Set: @a#b =# 42 record@
(=#) :: (f :-> a) -> a -> f -> f
(=#) = set
infix 1 =#


setTempo :: Y -> Config -> Config
setTempo y config =
    config { Config.deflt = (Config.deflt config) { Config.tempo = y } }


setTempo :: Config -> Config
setTempo y = Config.deflt#Config.tempo =# y

I haven't fully integrated this into my project because there are a
lot of labels to convert, but it's promising so far.

As far as I'm concerned, the thing to get rid of is the noisy module
qualification, which was what my suggestion was aimed at.  Then we'd
have '#deflt . #tempo =# y', which is pretty concise, if full of #s.

Of course some way to resolve 'deflt' and 'tempo' without ugly #
markers would be nicer, but I think that would have to be typeclass
overloading, which would still require explicit imports for all those
label names.  They'd also be uncontrollably global, which wouldn't let
you use them inside the module but not export.  So I'm starting to
think that in the absence of changes to typeclasses themselves, a
typeclass-using solution is never going to be satisfactory.

I agree WRT updates, btw.  I don't mind the existing record access
very much.  It's noisy (I prefix record fields too, so it's even
worse: Config.default_tempo . Config.config_default), but it composes,
so it just means a few more wrapped lines when they don't fit in 80
columns.  The non-composing non-abstract updates are what bug me, and
make me scatter about tons of 'modifyThis' functions, both for
composability and to protect from field renames.  I hope I can fix it
with lenses, but it's a bit of a hassle trying to retrofit them onto
something large.

More information about the Haskell-Cafe mailing list