agda / agda2hs

Compiling Agda code to readable Haskell
https://agda.github.io/agda2hs
MIT License
175 stars 37 forks source link

Newtype constructor erroneously removed #320

Open bwbush opened 5 months ago

bwbush commented 5 months ago

Agda

record Hash (a : Set) : Set where
  constructor MakeHash
  field hashBytes : ByteString
open Hash public
{-# COMPILE AGDA2HS Hash newtype deriving (Generic, Show) #-}

instance
  iMaybeHashable : ⦃ i : Hashable a ⦄ → Hashable (Maybe a)
  iMaybeHashable {{_}} .hash Nothing = MakeHash (hashBytes (hash iUnitHashable tt))
  iMaybeHashable {{i}} .hash (Just x) = MakeHash (hashBytes (hash iPairHashable (tt , x)))
{-# COMPILE AGDA2HS iMaybeHashable #-}

becomes Haskell

newtype Hash a = MakeHash{hashBytes :: ByteString}
                   deriving (Generic, Show)

instance (Hashable a) => Hashable (Maybe a) where
    hash Nothing = hash ()
    hash (Just x) = hash ((), x)

even though MakeHash . hashBytes != id since in this case we had MakeHash :: ByteString -> Maybe a but hashBytes :: () -> ByteString etc.

jespercockx commented 4 months ago

So the problem here seems to be that Agda itself eta-contracts MakeHask (hashBytes x) to x, even when the parameters of the constructor and the projection are different, possibly caused by https://github.com/agda/agda/issues/2732. I'm not sure if there is much we can do to fix this on the agda2hs side. As a workaround, you could add a no-eta-equality clause to the record definition, which should be enough to stop Agda from eta-contracting.

jespercockx commented 3 months ago

Perhaps we should just enforce that records that are compiled to Haskell data types always have eta-equality disabled.