
On Thu, Sep 10, 2020 at 11:03:59AM +0100, Tom Ellis wrote:
Ah, I see. You are saying that record updates can have a special typing rule because we have extra information that tells us that the type of the result cannot depend on the type of what was previously there.
Here's an example where the previous value matters: λ> data Y a = Y { y :: !a } deriving Show λ> defaultY :: Monoid a => Y a ; defaultY = Y undefined λ> monoUpdate :: Y a -> a -> Y a; monoUpdate r a = r { y = a } λ> monoUpdate defaultY "c" *** Exception: Prelude.undefined CallStack (from HasCallStack): error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err undefined, called at <interactive>:2:44 in interactive:Ghci2 [ The construction of "defaultY { y = "c" }" begins with a construction of "defaultY" that may fail. ] Now imagine that some Monoid instances have "mempty = undefined", and others do not. Making the constructor strict, When the struct record is strict in the updated field, (e.g. with StrictData), the initial value is constructed strictly, even with optimisation. For example the below compiled with "ghc -O2" still throws an exception when executed: {-# LANGUAGE StrictData #-} module Main (main) where data Y a = Y { y :: a } deriving Show defaultY :: Monoid a => Y a; defaultY = Y undefined monoUpdate :: Y a -> a -> Y a; monoUpdate r a = r { y = a } main :: IO () main = print $ monoUpdate defaultY "c" Turning off "StrictData" makes it go. So I think there's even less room here for special logic. The type ambiguity must be resolved, allowing defaultY to be constructed. -- Viktor.