| ... | ... | @@ -170,6 +170,145 @@ This would insure that by not exporting a field label, it cannot be gotten aroun | 
| 
 | 
 | 
This fix would also require the polymorphic setting ability mentioned above and would partially mitigate the need for [ReadonlyConstructors](readonly-constructors)
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
## Polymorphic Record Update take II
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
(The following was discussed briefly on the Haskell' list.)
 | 
| 
 | 
 | 
Consider the following data type:
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
```wiki
 | 
| 
 | 
 | 
data T a
 | 
| 
 | 
 | 
  = C1 { f1 :: a }
 | 
| 
 | 
 | 
  | C2 { f1 :: a, f2 :: Int }
 | 
| 
 | 
 | 
  | C3 { f2 :: Int }
 | 
| 
 | 
 | 
deriving Show
 | 
| 
 | 
 | 
```
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
Suppose we want to update the field `f1` only in such a way that
 | 
| 
 | 
 | 
its type changes. We cannot use the record update syntax, as not
 | 
| 
 | 
 | 
all constructors have a field `f1`. So we write a utility function.
 | 
| 
 | 
 | 
However, we would prefer to do as little as possible when it
 | 
| 
 | 
 | 
comes to values constructed by constructors NOT having a field
 | 
| 
 | 
 | 
`f2`. One might naively try this:
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
```wiki
 | 
| 
 | 
 | 
foo :: T a -> T Int
 | 
| 
 | 
 | 
foo x@(C1 {}) = x {f1 = 1}
 | 
| 
 | 
 | 
foo x@(C2 {}) = x {f1 = 2}
 | 
| 
 | 
 | 
foo x         = x
 | 
| 
 | 
 | 
```
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
But of course, this does not type check as the type of `x` is
 | 
| 
 | 
 | 
different on the LHS and RHS. We can get around that by reconstructing
 | 
| 
 | 
 | 
the value on the RHS:
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
```wiki
 | 
| 
 | 
 | 
foo :: T a -> T Int
 | 
| 
 | 
 | 
foo x@(C1 {})       = x {f1 = 1}
 | 
| 
 | 
 | 
foo x@(C2 {})       = x {f1 = 2}
 | 
| 
 | 
 | 
foo x@(C3 {f2 = n}) = C3 {f2 = n}
 | 
| 
 | 
 | 
```
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
However, this is bad, because we have to change the code if further
 | 
| 
 | 
 | 
constructors are added, even when they do not have a field `f1`,
 | 
| 
 | 
 | 
and we also have to change the code if further fields are added
 | 
| 
 | 
 | 
to constructors not having the field `f1`. This is tedious,
 | 
| 
 | 
 | 
error prone, and really defeats one of the main reasons for using
 | 
| 
 | 
 | 
records in the first place. For example:
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
```wiki
 | 
| 
 | 
 | 
data T a
 | 
| 
 | 
 | 
  = C1 { f1 :: a }
 | 
| 
 | 
 | 
  | C2 { f1 :: a, f2 :: Int }
 | 
| 
 | 
 | 
  | C3 { f2 :: Int, f3 :: Char }
 | 
| 
 | 
 | 
  | C4 { f2 :: Int }
 | 
| 
 | 
 | 
  deriving Show
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
foo :: T a -> T Int
 | 
| 
 | 
 | 
foo x@(C1 {})               = x {f1 = 1}
 | 
| 
 | 
 | 
foo x@(C2 {})               = x {f1 = 2}
 | 
| 
 | 
 | 
foo x@(C3 {f2 = n, f3 = c}) = C3 {f2 = n, f3 = c}
 | 
| 
 | 
 | 
foo x@(C4 {f2 = n})         = C4 {f2 = n}
 | 
| 
 | 
 | 
```
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
One might think it would be possible to do better if we're furtunate
 | 
| 
 | 
 | 
enough to have a field that is common to \*all\* constructors not having
 | 
| 
 | 
 | 
a field `f1`, as is the case for `f2` in this case:
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
```wiki
 | 
| 
 | 
 | 
foo :: T a -> T Int
 | 
| 
 | 
 | 
foo x@(C1 {}) = x {f1 = 1}
 | 
| 
 | 
 | 
foo x@(C2 {}) = x {f1 = 2}
 | 
| 
 | 
 | 
foo x         = x {f2 = f2 x}
 | 
| 
 | 
 | 
```
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
But this does not type check, and it would not apply anyway if
 | 
| 
 | 
 | 
there is no such common field.
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
What we really need is a function that reconstructs a value of type `T a`
 | 
| 
 | 
 | 
at type `T b` for all values constructed by a constructor that does not have
 | 
| 
 | 
 | 
a field `f1`:
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
```wiki
 | 
| 
 | 
 | 
coerce_no_f1 :: T a -> T b
 | 
| 
 | 
 | 
coerce_no_f1 x@(C3 {f2 = n, f3 = c}) = C3 {f2 = n, f3 = c}
 | 
| 
 | 
 | 
coerce_no_f1 x@(C4 {f2 = n})         = C4 {f2 = n}
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
foo :: T a -> T Int
 | 
| 
 | 
 | 
foo x@(C1 {}) = x {f1 = 1}
 | 
| 
 | 
 | 
foo x@(C2 {}) = x {f1 = 2}
 | 
| 
 | 
 | 
foo x         = coerce_no_f1 x
 | 
| 
 | 
 | 
```
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
But we'd rather not have to write such functions by hand, just as
 | 
| 
 | 
 | 
we'd rather not write update functions by hand. Maybe the record
 | 
| 
 | 
 | 
update syntax could be extended so that the function that gets
 | 
| 
 | 
 | 
generated behind the scenes only includes constructors that
 | 
| 
 | 
 | 
does NOT mention a particular field. For example, the field
 | 
| 
 | 
 | 
name(s) that must not occur could be prefixed by `~` which suggests
 | 
| 
 | 
 | 
negation in some settings. It does not have this connotation in Haskell,
 | 
| 
 | 
 | 
but at least `~` is already a special symbol. We could then write:
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
```wiki
 | 
| 
 | 
 | 
foo :: T a -> T Int
 | 
| 
 | 
 | 
foo x@(C1 {}) = x {f1 = 1}
 | 
| 
 | 
 | 
foo x@(C2 {}) = x {f1 = 2}
 | 
| 
 | 
 | 
foo x         = x {~f1}
 | 
| 
 | 
 | 
```
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
Now the code for `foo` only has to be changed if new constructors
 | 
| 
 | 
 | 
having a field `f1` are added.
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
Of course, it should be possible to combine this with the normal
 | 
| 
 | 
 | 
record update syntax. E.g.
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
```wiki
 | 
| 
 | 
 | 
foo :: T a -> T Int
 | 
| 
 | 
 | 
foo x@(C1 {}) = x {f1 = 1}
 | 
| 
 | 
 | 
foo x@(C2 {}) = x {f1 = 2}
 | 
| 
 | 
 | 
foo x         = x {~f1, f2 = f2 x + 1}
 | 
| 
 | 
 | 
```
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
# Meta-Proposal
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| ... | ... |  |