by BreakfastB0b on 8/1/22, 11:42 AM with 65 comments
by stepchowfun on 8/1/22, 1:56 PM
[1] https://github.com/stepchowfun/proofs/tree/main/proofs/Tutor...
[2] https://github.com/stepchowfun/proofs/blob/56438c9752c414560...
by homodeus on 8/1/22, 4:33 PM
by yccs27 on 8/1/22, 3:17 PM
by agluszak on 8/1/22, 2:29 PM
by benreesman on 8/1/22, 1:12 PM
It goes all the way from parametric polymorphism, up through Curry-Howard, and winds up at Girard-Reynolds. It was what got me passionate about type theory as a young lad.
by yababa_y on 8/1/22, 11:44 AM
by PoignardAzur on 8/1/22, 7:10 PM
Both this article and the article it quotes introduce the "((∃ x. P(x)) → Q) ⇔ (∀ x. (P(x) → Q))" formula with absolutely no additional explanation. I guess that's fine if the article are meant for people with a mathematics background, but at someone who has always struggled with post-high-school-maths... what the hell?
I understand what ∃, ∀, ⇔, and → represent ("there exists", "for all", "equivalent" and "implies", respectively), but I have no idea how to parse the entire formula. What are P and Q?
After multiple tries, I'm reading it as "saying that 'there exists a x such that P(x) is true' implies Q" being equivalent to "for all x, P(x) implies Q", with the idea that P and Q are arbitrary proposals or whatever the proper terms are... But still, just processing the logical reasoning in my head is tough.
On the other hand "some types implement traits, and if a function expects a trait impl you can only pass it types that implement that trait" feels absolutely clear to me. It might be that Rust is good at breaking down math concepts into the essentials you need for programming. Or it might be that formal Math notation is not for me.
by mtlmtlmtlmtl on 8/1/22, 5:44 PM
Safe Rust is truly safe if it only calls safe Rust or if all the unsafe code is correct.
And safe Rust is a little too inflexible to do certain things, so the unsafe word is a necessary evil. But turns out it's not a bug, it's a feature because now you can trivially identify which parts of the codebase require extra scrutiny to avoid memory corruption and data races.
With FM the main downside has always been the added cost and development time/complexity, needing to use obscure academically oriented systems that most developers have no experience with, etc. But that complexity is probably okay for a project like the Rust standard library, which is already a highly complex project and will only be majorly worked on by a relatively small subset of Rust developers. So you could save some of that cost by only needing it in a (relatively) small part of the ecosystem.
Ofc I realise this wouldn't give the same level of correctness as doing all code with FM. You could only verify whatever guarantees Rust provides for code with no unsafe codepaths. And proofs can have bugs too. But still I think it could increase safety a lot.
by siraben on 8/1/22, 4:35 PM
Theorem impl_trait_transform: forall (Trait: Type -> Prop) (Result: Prop),
((exists t, Trait(t)) -> Result) <-> (forall t, (Trait(t) -> Result)).
Proof.
firstorder.
Qed.
by Tainnor on 8/1/22, 10:09 PM
At least that's the case in classical logic (which is enough to understand this article), I'm not knowledgeable enough about intuitionism to know whether it typically includes second-order quantification, but even in that it would probably be better to make the quantification explicit.
by mirekrusin on 8/1/22, 9:22 PM
[0] https://www.youtube.com/playlist?list=PLre5AT9JnKShBOPeuiD9b...
[1] https://www.youtube.com/playlist?list=PLre5AT9JnKShFK9l9HYzk...
[2] https://clarksmr.github.io/sf-lectures/textbook/lf/Preface.h...
by Tainnor on 8/1/22, 4:51 PM
by howling on 8/1/22, 2:29 PM
by kelnos on 8/1/22, 9:56 PM
by max_ on 8/1/22, 5:00 PM