Suppose I have a parameter that exists only for the benefit of the type system, for example as in this small program:
{-# LANGUAGE GADTs #-}
module Main where
import Data.Proxy
import Data.List
data MyPoly where
MyConstr :: Proxy a -> a -> (Proxy a -> a -> Int -> Int) -> MyPoly
listOfPolys :: [MyPoly]
listOfPolys = [MyConstr Proxy 5 (const (+))
, MyConstr Proxy 10 (const (+))
, MyConstr Proxy 15 (const (+))]
main = print $ foldl' (\v (MyConstr p n a) -> a p n v) 0 listOfPolys
The Proxy arguments and members in the structure only really need to exist at compile time to help with type checking while maintaining the polymorphic MyPoly (in this case, the program will compile without it, but this contrived example is a more general problem where there are proofs or proxies that are only needed at compile time) - there is only one constructor for Proxy, and the type argument is a phantom type.
Compiling with ghc with -ddump-stg
shows that at least at the STG stage, there is no erasure of the Proxy argument to the constructor or the third argument to the constructor.
Is there any way to mark these as being compile-time only, or otherwise help ghc to do proof erasure and exclude them?
Indeed, your code does lead to
Proxy
s being stored in the constructor:However, with a small change, we get the wanted optimization. No more
Proxy
!What did I do? I made the
Proxy
field strict:In general, we can't erase non-strict proxies because of bottoms.
Proxy
andundefined
are both of typeProxy a
but they are not observationally equivalent, so we have to distinguish them at runtime.Instead, a strict
Proxy
only has one value, so GHC can optimize that away.There's no similar feature to optimize away a (non-constructor) function parameter, though. Your field
(Proxy a -> a -> Int -> Int)
will require aProxy
at runtime.