Why not allow empty record updates?

wren ng thornton wren at freegeek.org
Wed Nov 16 01:18:21 CET 2011

On 11/15/11 12:33 PM, Yitzchak Gale wrote:
> Simon Peyton-Jones wrote:
>>>>> Trouble is, what type does this have?
>>>>>    f x = x {}
> Malcolm Wallace wrote:
>>>> f :: a ->  a
> Ian Lynagh wrote:
>>> That wouldn't help the original poster, as it is incompatible with
>>> f :: Foo Clean ->  Foo Dirty
> Only because in that expression the type of x is not known.
>>>>> ...the whole feature of type-changing update is (as you know)
>>>>> a bit obscure and not widely used, so it'd be adding
>>>>> complexity to an already-dark corner.
> To me, at least, that is surprising. The report implies that
> record updates are just sugar for the given case expression.
> Whether or not it changes a type parameter seems
> unimportant.
> In fact, I would even advocate adding a line of explanation
> in the Report that this is a convenient way of copying
> a value from an ADT to itself with a different type
> as its parameter. I agree with Malcolm that this is
> analogous to using empty record syntax in a pattern
> to avoid hard-coding the number of parameter to
> a constructor.
> I usually avoid using the combination of type parameters and
> record syntax altogether, mainly because this obvious syntax
> doesn't work. Perhaps that's the reason why type-changing
> update is not widely used.
> (Admittedly, I didn't think of Herbert's trick. But doesn't
> that seem like somewhat of an ugly hack?)
> Are you hesitant because of implementation difficulty,
> or only because you are worried about the semantics
> being confusing? In my opinion, it's more confusing
> the way it is now.

For what it's worth, I do the exact same thing in the project I've been 
working on. The phantom type is a clean/dirty bit even :)

It's an incredibly helpful thing to have for records. Especially for the 
context I'm in: I'm generating summary data over gobs of input, but the 
input can come incrementally. So long as the core of the summary is 
correct, then I don't care about maintaining the cache fields while I'm 
just shoveling data in; but I do want to make sure the caches are valid 
before I try to get any information out. This is exactly the sort of 
type-level hackery which makes Haskell a joy to work in and other 
languages such a pain.

So far I've just defined helper functions to adjust the phantom type[1], 
each of which is implemented by (\x -> x { foo = foo x }). It's a 
horrible hack, but at least it's hidden away in library functions 
instead of something I have to look at. The annoying part is that when I 
adjust the members of the records, if I remove or rename foo then I have 
to fix all those coercion functions too.

[1] set bit to Clean, set bit to Dirty, and unsafe set bit to 'a'.

Live well,

More information about the Glasgow-haskell-users mailing list