Haskell – Use GHC to rely on time-dependent runtime costs

I am writing a dependent type library in Haskell. Using analysis on my test executable, I see something like:

< /p>

commutativity' Math 1189 4022787186 29.1 27.2 29.1 27.2

“Commutativity” is basically the (recursive) proof of the commutativity of integer addition of type-level integers. It is defined as follows:

commutativity' :: SNat n -> SNat m -> Plus (S n) m :~: Plus n (S m)
commutativity' SZ m = Refl
commutativity' (SS n) m = gcastWith (commutativity' nm) Refl

Then use gcastWith in my library to prove the equivalence of various types.

So… …29% of my runtime is spent on completely useless things, because type checking happens at compile time.

I naively think this will not happen.

What can I do to optimize these useless calls?

If you are pretty sure that the term ends, you can use something like this

unsafeProof :: proof -> proof
unsafeProof _ = unsafeCoerce ()

someFunction :: forall n m. ...
someFunction = case unsafeProof myProof :: Plus (S n) m :~: Plus n (S m) of
Refl -> ...

This must only be used to have a single parameterless construction The type of function, for example, reflects a:~:b. Otherwise, your program may crash or behave strangely. Buyers are arrogant!

A safer (but still unsafe!) variant might be

unsafeProof :: a :~: b -> a :~: b
unsafeProof _ = unsafeCoerce ()

Please note that if you pass the bottom to it, you can still crash the program.

I hope that one day GHC will be able to safely and automatically Perform this optimization to ensure that it is terminated by static analysis.

I am writing a dependent type library in Haskell. Using analysis on my test executable, I See something like:

commutativity' Math 1189 4022787186 29.1 27.2 29.1 27.2

“Commutativity” is basically a (recursive) proof type The commutative property of integer addition of a class of integers. It is defined as follows:

commutativity' :: SNat n -> SNat m -> Plus (S n) m :~: Plus n ( S m)
commutativity' SZ m = Refl
commutativity' (SS n) m = gcastWith (commutativity' nm) Refl

Then use gcastWith in my library to prove each The equivalence of types.

So… 29% of my runtime is used for completely useless things, because type checking occurs at compile time.

I naively thought this would not happen.

What can I do to optimize these useless calls?

If you are pretty sure that the term is terminated, you can use something like

unsafeProof :: proof -> proof
unsafeProof _ = unsafeCoerce ()

someFunction :: forall n m. ...
someFunction = case unsafeProof myProof :: Plus (S n) m :~: Plus n (S m) of
Refl -> ...

This must only be used for types with a single parameterless constructor, for example, reflecting a:~:b . Otherwise, your program may crash or behave strangely. Buyers are arrogant!

A safer (but still unsafe!) variant might be

unsafeProof :: a :~: b -> a :~: b
unsafeProof _ = unsafeCoerce ()

Please note that if you pass the bottom to it, you can still crash the program.

I hope that one day GHC will be able to safely and automatically Perform this optimization to ensure that it is terminated by static analysis.

Leave a Comment

Your email address will not be published.