Zulip Chat Archive
Stream: new members
Topic: Classical vs constructive logic in computation
Rekkyn (Jan 26 2025 at 23:21):
I've heard that constructive logic plays better with computation compared to classical logic. But I've also heard that all Prop
s are erased during computation, so it wouldn't seem to matter if a Prop
was created in a classical or constructive way. Is it true that constructive logic is better for computations, and if so are there any examples of that?
Tristan Figueroa-Reid (Jan 27 2025 at 00:10):
Rekkyn said:
I've heard that constructive logic plays better with computation compared to classical logic. But I've also heard that all
Prop
s are erased during computation, so it wouldn't seem to matter if aProp
was created in a classical or constructive way. Is it true that constructive logic is better for computations, and if so are there any examples of that?
I don't have a good example for Prop
at hand, but Prop
s aren't the only things that can be created with classical logic (the axiom of choice is part of classical logic, and is the backing axiom for the LEM by Diaconescu's theorem)
An example of how classical logic wouldn't play well with computation is graph coloring: graph coloring can be made classically.
Tristan Figueroa-Reid (Jan 27 2025 at 00:15):
Correction: there is no good example for Prop
s (assuming what you mean by "Prop
s are erased by computation" is from #tpil (at Axioms and Computations))
Kyle Miller (Jan 27 2025 at 00:50):
I think that's a bit different from what Rekkyn is asking. That's a noncomputable
instance, and it's noncomputable because it's using choice to "construct" a list of all the colorings. (Side note: we should change that to be a Finite
instance!) There was never any hope that it would be computable.
For definitions, it doesn't matter one way or another if the proofs that appear in them are proved using choice or not. It all gets erased when the function is compiled for evaluation.
If you care about defeq properties, it's possible for something like Eq.rec
or Acc.rec
to get stuck on a classical proof (since in reduction proofs are not erased). I've never run into this as an issue however.
Sometimes people talk about writing proofs without constructive logic so that they can be reduced to compute witnesses "for free". That's probably where "better for computations" comes from. My understanding of the situation for Lean is (1) reducing proofs is largely a non-goal so things can get unnecessarily stuck because, for example, types aren't reduced and Eq.rec
can get stuck during reduction of an otherwise "computable" definition and (2) people have found that reduction of proofs is not normalizing ( ) so perhaps it's not good to try relying on this in Lean.
In practice, rather than writing proofs of existentials, you can make definitions that compute a witness and then write theorems that prove the witnesses have certain properties.
Kyle Miller (Jan 27 2025 at 00:56):
It's possible to work constructively in the sense of making sure to give algorithms for everything that is meaningfully computable, without subscribing to constructive logic, which is making the proofs themselves computable in some sense too. (I think CS outside of type theory tends not to ever think about avoiding LEM in proofs about algorithms for example. That doesn't make the algorithms any less computable.)
Aaron Liu (Jan 27 2025 at 01:31):
Kyle Miller said:
That's a
noncomputable
instance, and it's noncomputable because it's using choice to "construct" a list of all the colorings. (Side note: we should change that to be aFinite
instance!) There was never any hope that it would be computable.
I think you can make it computable if you add DecidableRel G.Adj
. Why give up on computability?
Rekkyn (Jan 27 2025 at 02:01):
Kyle Miller said:
I think that's a bit different from what Rekkyn is asking. That's a
noncomputable
instance, and it's noncomputable because it's using choice to "construct" a list of all the colorings. (Side note: we should change that to be aFinite
instance!) There was never any hope that it would be computable.For definitions, it doesn't matter one way or another if the proofs that appear in them are proved using choice or not. It all gets erased when the function is compiled for evaluation.
If you care about defeq properties, it's possible for something like
Eq.rec
orAcc.rec
to get stuck on a classical proof (since in reduction proofs are not erased). I've never run into this as an issue however.Sometimes people talk about writing proofs without constructive logic so that they can be reduced to compute witnesses "for free". That's probably where "better for computations" comes from. My understanding of the situation for Lean is (1) reducing proofs is largely a non-goal so things can get unnecessarily stuck because, for example, types aren't reduced and
Eq.rec
can get stuck during reduction of an otherwise "computable" definition and (2) people have found that reduction of proofs is not normalizing ( ) so perhaps it's not good to try relying on this in Lean.In practice, rather than writing proofs of existentials, you can make definitions that compute a witness and then write theorems that prove the witnesses have certain properties.
This makes sense, thanks! I'm guessing there's no reason why someone couldn't make "computable" versions of the built-in Prop
s like this?
inductive TypeOr (a b : Prop) : Type where
| inl (h : a) : TypeOr a b
| inr (h : b) : TypeOr a b
Aaron Liu (Jan 27 2025 at 02:03):
My understanding is, there also hasn't been any reason for anyone to do this either.
Aaron Liu (Jan 27 2025 at 02:06):
If you want to emulate this behavior, use docs#PLift to change the arguments from Prop
to Type
, then use Sum/Prod/Sigma to construct the "computable" version.
Rekkyn (Jan 27 2025 at 02:12):
Aaron Liu said:
If you want to emulate this behavior, use docs#PLift to change the arguments from
Prop
toType
, then use Sum/Prod/Sigma to construct the "computable" version.
That's useful to know, thanks!
Kyle Miller (Jan 27 2025 at 03:31):
If you think you can make it computable (ideally with an efficient algorithm) then go ahead @Aaron Liu!
There are two points here:
- Noncomputable
Fintype
instances are useless. They should beFinite
instances. This instance pre-datesFinite
, otherwise I would have written it as aFinite
instance. - It is worth having
Finite
instances since they do not bring in unnecessary dependence on algorithms. Inside a proof, it does not matter at all that there's some arbitrary way to make aList
of all simple graphs. Mere finiteness suffices.
Edward van de Meent (Jan 27 2025 at 08:13):
Inside a proof, it may matter if there is a computable list: if you're working with a concrete type and you want to do case analysis using fin_cases
, you need a computable Fintype
instance.
Aaron Liu (Jan 27 2025 at 14:09):
Kyle Miller said:
If you think you can make it computable (ideally with an efficient algorithm) then go ahead Aaron Liu!
For now, it's not efficient. Maybe I'll implement an efficient algorithm later.
Code
Aaron Liu (Jan 27 2025 at 22:14):
I had some time, so I made it more efficient (without tactics).
More Efficient
Kyle Miller (Jan 27 2025 at 22:32):
I'm not sure why it's written with all the proofs as proof terms — using tactics for proofs doesn't make definitions any less efficient, and using proof terms significantly harms readability.
Also, it's almost always better to use recursion instead of raw recursors. That motive doesn't look like it's complicated, so match
ought to be able to handle the situation itself.
Aaron Liu (Jan 27 2025 at 22:35):
I tried match
and it didn't work (not generalizing enough) (yes I tried (generalizing := true)
), so I used Nat.rec
directly.
I was writing it in term mode because "don't construct terms using tactics" and before I knew it, I had written the whole thing in terms.
I tried this on #eval Fintype.card ((⊤ : (SimpleGraph (Fin 8))).Coloring (Fin 7))
and this solution was 8 times faster than the other one I wrote.
Kyle Miller (Jan 27 2025 at 22:37):
That's fair, but if we want to include it in mathlib, we'll have to write it in a readable style. Ideally, we would factor out the key ideas into multiple definitions too. This is not an irreducibly complex computation.
Last updated: May 02 2025 at 03:31 UTC