<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Lambda Cove</title>
    <link rel="self" type="application/atom+xml" href="https://lambda-cove.net/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://lambda-cove.net"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2025-06-08T00:00:00-04:00</updated>
    <id>https://lambda-cove.net/atom.xml</id>
    <entry xml:lang="en">
        <title>Writing a truth oracle in Lisp</title>
        <published>2025-06-08T00:00:00-04:00</published>
        <updated>2025-06-08T00:00:00-04:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://lambda-cove.net/posts/truth-oracle-lisp/"/>
        <id>https://lambda-cove.net/posts/truth-oracle-lisp/</id>
        
        <content type="html" xml:base="https://lambda-cove.net/posts/truth-oracle-lisp/">&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;This post assumes some familiarity with typed functional programming, Lisp, and formal logic.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p class=&quot;first-paragraph&quot; data-first-letter=&quot;T&quot;&gt;
Today we will attempt to write a truth oracle in Lisp.
By &quot;truth oracle,&quot; I mean a program that can determine whether arbitrary mathematical statements are true or false.
This might sound impossible, due to first-order logic being undecidable,
but let&#x27;s try anyway.
&lt;&#x2F;p&gt;
&lt;p&gt;Before that, though, we need to go over some required concepts.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;extracting-information-from-proofs&quot;&gt;Extracting information from proofs&lt;&#x2F;h2&gt;
&lt;p&gt;First, sometimes, we can extract information from proofs themselves, beyond just the facts that they prove.&lt;&#x2F;p&gt;
&lt;p&gt;Imagine you want to prove a statement of the form “\(A\) or \(B\).”
If you can prove either \(A\) or \(B\), then you can prove “\(A\) or \(B\)” by the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Disjunction_introduction&quot;&gt;or-introduction&lt;&#x2F;a&gt; rule.
Let’s say you have a proof of this form,
and you want to figure out &lt;em&gt;which&lt;&#x2F;em&gt; of \(A\) or \(B\) is the one that’s true.
This is pretty easy.
You can just look at the last step of the proof,
and see if it’s &lt;em&gt;left-or-introduction&lt;&#x2F;em&gt; or &lt;em&gt;right-or-introduction&lt;&#x2F;em&gt;.
For example, if you have a proof that a number is either divisible by three or by five, you can look at the last step of the proof to see which it’s divisible by.&lt;&#x2F;p&gt;
&lt;p&gt;The same principle applies for proofs of existence.
If you want to prove “there exists \(x\) such that \(P(x)\),”
you can use the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Existential_generalization&quot;&gt;existential introduction&lt;&#x2F;a&gt; rule.
In other words, you can give the specific value \(x\) satisfying \(P(x)\), and then prove \(P(x)\) with that value.
Then if you have a proof of this form that there exists a number \(x\) such that there is a string of digits “123456789” starting at the \(x\)th digit of \(\pi\),
you can look at the existential introduction rule of the proof to see &lt;em&gt;where&lt;&#x2F;em&gt; in \(\pi\) you can find the digit string “123456789.”&lt;&#x2F;p&gt;
&lt;p&gt;In other words, for proofs of “or” statements, we can look at the proof to see which individual statement is true, and for proofs of existence we can look at the proof to see the value that exists.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-curry-howard-correspondence&quot;&gt;The Curry-Howard correspondence&lt;&#x2F;h2&gt;
&lt;p&gt;The next concept is a relationship between proofs and programs called the
&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Curry%E2%80%93Howard_correspondence&quot;&gt;Curry-Howard correspondence&lt;&#x2F;a&gt;.
This topic has a &lt;em&gt;lot&lt;&#x2F;em&gt; of depth and I’m not going to go into the full details, but the basics aren’t too complicated.
The core idea is that formal logic &lt;em&gt;proofs&lt;&#x2F;em&gt; can be thought of as &lt;em&gt;expressions&lt;&#x2F;em&gt; in a typed functional programming language, and vice versa.
Similarly, the &lt;em&gt;types&lt;&#x2F;em&gt; of expressions can be thought of as &lt;em&gt;propositions&lt;&#x2F;em&gt;, or statements, that the expressions prove.
I’ll describe some examples below.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;implication&quot;&gt;Implication&lt;&#x2F;h3&gt;
&lt;p&gt;Consider the statement “\(A\) implies \(B\).”
If you have a proof that “\(A\) implies \(B\),” and a proof of \(A\),
you can combine them with &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Modus_ponens&quot;&gt;implication elimination&lt;&#x2F;a&gt; to get a proof of \(B\).
In the Curry-Howard correspondence, implication corresponds to function types,
and implication elimination corresponds to function application.
If you have an expression \(f\) of type \(A \to B\) and an expression \(x\) of type \(A\),
you can combine them with function application to get an expression \(f(x)\) of type \(B\).
Incidentally, the right arrow “\(\to\)” symbol is commonly used for both implication and function types.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;and&quot;&gt;And&lt;&#x2F;h3&gt;
&lt;p&gt;You can prove “\(A\) and \(B\)” using &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Conjunction_introduction&quot;&gt;and-introduction&lt;&#x2F;a&gt; if you can prove \(A\) and you can prove \(B\).
You can also use &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Conjunction_elimination&quot;&gt;and-elimination&lt;&#x2F;a&gt; with a proof of “\(A\) and \(B\)” to get back a proof of \(A\) and a proof of \(B\).
In functional programming, this corresponds to tuples.
Given an expression \(x\) of type \(A\) and \(y\) of type \(B\),
you can construct a tuple \((x,y)\) of type \((A,B)\).
And you can also destruct a tuple of type \((A,B)\) to get back \(x\) and \(y\).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;or&quot;&gt;Or&lt;&#x2F;h3&gt;
&lt;p&gt;With &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Disjunction_introduction&quot;&gt;or-introduction&lt;&#x2F;a&gt;, you can prove “\(A\) or \(B\)” from a proof of \(A\) or a proof of \(B\).
In programming languages, this corresponds to &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Tagged_union&quot;&gt;sum types&lt;&#x2F;a&gt; (types that can be one of several variants), sometimes called “either types,” variants, discriminated unions, or coproducts.
In Rust, these are called &lt;code&gt;enum&lt;&#x2F;code&gt;, or &lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;&#x2F;code&gt; for the specific case where one of the types is for normal output and the other is for errors.
In Haskell, there is a type &lt;code&gt;Either A B&lt;&#x2F;code&gt; with constructors &lt;code&gt;Left a&lt;&#x2F;code&gt; and &lt;code&gt;Right b&lt;&#x2F;code&gt;.
In Rust, if you have an expression &lt;code&gt;val&lt;&#x2F;code&gt; of type &lt;code&gt;T&lt;&#x2F;code&gt; or an expression &lt;code&gt;err&lt;&#x2F;code&gt; of type &lt;code&gt;E&lt;&#x2F;code&gt;,
you can construct an expression &lt;code&gt;Ok(val)&lt;&#x2F;code&gt; or &lt;code&gt;Err(err)&lt;&#x2F;code&gt; of type &lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;&#x2F;code&gt;.
In Haskell, if you have &lt;code&gt;a : A&lt;&#x2F;code&gt; or &lt;code&gt;b : B&lt;&#x2F;code&gt;, then you can construct &lt;code&gt;Either A B&lt;&#x2F;code&gt; with &lt;code&gt;Left a&lt;&#x2F;code&gt; or &lt;code&gt;Right b&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The opposite direction, &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Disjunction_elimination&quot;&gt;or-elimination&lt;&#x2F;a&gt;, is a little more complicated.
Given a proof of “\(A\) or \(B\),” if you prove that both \(A\) and \(B\) imply the same conclusion \(C\), then you can use or-elimination to prove \(C\).
This corresponds to pattern matching in programming languages.&lt;&#x2F;p&gt;
&lt;p&gt;In Haskell, if you have a value &lt;code&gt;x&lt;&#x2F;code&gt; of type &lt;code&gt;Either a b&lt;&#x2F;code&gt;
and you have functions mapping both &lt;code&gt;a&lt;&#x2F;code&gt; and &lt;code&gt;b&lt;&#x2F;code&gt; to a shared type &lt;code&gt;c&lt;&#x2F;code&gt;,
you can use pattern matching to get a value of type &lt;code&gt;c&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;patternMatch :: Either a b -&amp;gt; (a -&amp;gt; c) -&amp;gt; (b -&amp;gt; c) -&amp;gt; c
patternMatch x f g =
  case x of
    Left v -&amp;gt; f v
    Right v -&amp;gt; g v
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And in Rust, if you have a value &lt;code&gt;x&lt;&#x2F;code&gt; of type &lt;code&gt;Result&amp;lt;A, B&amp;gt;&lt;&#x2F;code&gt;
and you have functions mapping both &lt;code&gt;A&lt;&#x2F;code&gt; and &lt;code&gt;B&lt;&#x2F;code&gt; to a shared type &lt;code&gt;C&lt;&#x2F;code&gt;,
you can use pattern matching to get a value of type &lt;code&gt;C&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;fn pattern_match&amp;lt;A, B, C&amp;gt;(
    x: Result&amp;lt;A, B&amp;gt;,
    f: fn(A) -&amp;gt; C,
    g: fn(B) -&amp;gt; C
) -&amp;gt; C {
    match x {
        Ok(v) =&amp;gt; f(v),
        Err(v) =&amp;gt; g(v),
    }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;contradiction&quot;&gt;Contradiction&lt;&#x2F;h3&gt;
&lt;p&gt;A contradiction “\(\bot\)” is a proposition that has no proofs (i.e. it’s unprovable, and false).
Propositions correspond to types,
and proofs correspond to values.
So a contradiction corresponds to an &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Empty_type&quot;&gt;empty type&lt;&#x2F;a&gt;,
a type with no values.
In programming languages with sum types, this can be represented with a sum type with no variants, such as &lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;void&#x2F;1.0.2&#x2F;void&#x2F;enum.Void.html&quot;&gt;&lt;code&gt;enum Void {}&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; in Rust.
However, Rust also includes a &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;primitive.never.html&quot;&gt;primitive “never” type &lt;code&gt;!&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; which serves this purpose.
These types are typically used for expressions that don’t return normally,
such as infinite loops, thrown exceptions,
or fatal errors.&lt;&#x2F;p&gt;
&lt;p&gt;In formal logic,
if you have a proof of a contradiction,
you can use it to prove anything,
by the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Principle_of_explosion&quot;&gt;principle of explosion&lt;&#x2F;a&gt;.
Similarly,
in functional programming,
an expression of the empty type can be used to get an expression of any type.
If the empty type is represented as a sum type with zero variants, you can pattern match on the expression to get an expression of any arbitrary type.
In the case of Rust’s “never” type, it is coerced automatically to other types.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;negation&quot;&gt;Negation&lt;&#x2F;h3&gt;
&lt;p&gt;Logical negation “\(\lnot A\)” (“not \(A\)”) is equivalent to implying a contradiction “\(A \to \bot\)” (“\(A\) implies a contradiction”).
We can say this because
the core property we want for logical negation is that
if we know both a statement and its negation,
we can derive a contradiction.
For example,
if we know “\(A\)” and “\(A\) implies a contradiction” we can use
&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Modus_ponens&quot;&gt;implication elimination&lt;&#x2F;a&gt;
to derive a contradiction.
We’ve already shown that implication corresponds to function types, and contradictions correspond to empty types,
so we now know that logical negation is isomorphic with function types where the return type is an empty type.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h3&gt;
&lt;p&gt;Here’s a table summarizing the correspondence, adapted from the one on &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Curry%E2%80%93Howard_correspondence&quot;&gt;Wikipedia&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Logic&lt;&#x2F;th&gt;&lt;th&gt;Typed functional programming&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Statement&lt;&#x2F;td&gt;&lt;td&gt;Type&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Proof&lt;&#x2F;td&gt;&lt;td&gt;Expression&#x2F;Value&#x2F;Program&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Statement is true&lt;&#x2F;td&gt;&lt;td&gt;Type has some possible values&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Statement is false&lt;&#x2F;td&gt;&lt;td&gt;Type has no possible values&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Implication&lt;&#x2F;td&gt;&lt;td&gt;Function type&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;And (conjunction)&lt;&#x2F;td&gt;&lt;td&gt;Tuple&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Or (disjunction)&lt;&#x2F;td&gt;&lt;td&gt;Sum type&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;\(\bot\)&lt;&#x2F;td&gt;&lt;td&gt;Empty type&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;not \(A\)&lt;&#x2F;td&gt;&lt;td&gt;Type of function that takes \(A\) and returns the empty type&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;truth-oracle-in-lisp&quot;&gt;Truth oracle in Lisp&lt;&#x2F;h2&gt;
&lt;p&gt;Now that we understand how proofs in formal logic correspond to programs,
we can use this knowledge to build a function that tells us whether any logical statement is true.&lt;&#x2F;p&gt;
&lt;p&gt;Now, we know there’s a correspondence between proofs and programs, and that we can extract information from proofs, such as whether \(A\) or \(B\) is true from a proof of “\(A\) or \(B\).” As it turns out, typed Racket (a Lisp with static typing) has a function &lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt; that is Curry-Howard-isomorphic with &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Peirce%27s_law&quot;&gt;Peirce’s law&lt;&#x2F;a&gt;.
This is an axiom of logic that says that “\(((A \to B) \to A) \to A\).”
It happens to be equivalent to &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Law_of_excluded_middle&quot;&gt;the law of excluded middle&lt;&#x2F;a&gt;,
which says that every statement is either true or false (\(A\) or not \(A\)).
Since you can use Peirce’s law to prove the law of excluded middle,
we should be able to use &lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt; to implement a program that is Curry-Howard-isomorphic to the law of excluded middle.
Let’s try that.&lt;&#x2F;p&gt;
&lt;p&gt;First, we’ll use &lt;a href=&quot;https:&#x2F;&#x2F;rocq-prover.org&#x2F;&quot;&gt;Rocq Prover&lt;&#x2F;a&gt; to prove that Peirce’s law implies excluded middle.
Rocq Prover is a tool for writing formal proofs that uses a typed functional language called &lt;a href=&quot;https:&#x2F;&#x2F;rocq-prover.org&#x2F;doc&#x2F;V8.9.1&#x2F;refman&#x2F;language&#x2F;gallina-specification-language.html&quot;&gt;Gallina&lt;&#x2F;a&gt; as its proof format.
By the Curry-Howard correspondence, this is a valid way to represent proofs.
Don’t worry if you aren’t familiar with the specifics of Rocq and its syntax;
the key insight is just that we are proving Peirce’s law implies the law of excluded middle.
The proof looks like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rocq&quot; class=&quot;language-rocq &quot;&gt;&lt;code class=&quot;language-rocq&quot; data-lang=&quot;rocq&quot;&gt;Theorem peirce_implies_em :
  (forall A B, ((A -&amp;gt; B) -&amp;gt; A) -&amp;gt; A)
  -&amp;gt; (forall A, A \&amp;#x2F; ~A).
Proof.
  intros peirce A.
  apply peirce with (B := False).
  auto.
Qed.
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This proof is not written in the Gallina functional programming language, but a higher-level tactic language for manipulating the underlying Gallina expressions.
Thankfully, Rocq lets us print out the generated Gallina program.
Let’s do that, so we can translate it to typed Racket.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rocq&quot; class=&quot;language-rocq &quot;&gt;&lt;code class=&quot;language-rocq&quot; data-lang=&quot;rocq&quot;&gt;Print peirce_implies_em.
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;rocq&quot; class=&quot;language-rocq &quot;&gt;&lt;code class=&quot;language-rocq&quot; data-lang=&quot;rocq&quot;&gt;peirce_implies_em =
fun (peirce : forall A B : Type, ((A -&amp;gt; B) -&amp;gt; A) -&amp;gt; A)
    (A : Prop)
    =&amp;gt; peirce
         (A \&amp;#x2F; ~ A)
         False
         (fun (not_em : A \&amp;#x2F; ~ A -&amp;gt; False)
              =&amp;gt; or_intror
                 ((fun a : A =&amp;gt; not_em (or_introl a)) : ~ A)
         )
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice that the proof is that Peirce’s law implies excluded middle,
and the program is a function that takes as an argument a proof of Peirce’s law and returns a proof of the excluded middle.
Let’s translate the body of the function to typed Racket,
replacing &lt;code&gt;peirce&lt;&#x2F;code&gt; with &lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;#lang typed&amp;#x2F;racket

(struct (L) Left ([v : L]))
(struct (R) Right ([v : R]))
(define-type (Either L R)
  (U (Left L) (Right R)))

(define-type (Not A) (-&amp;gt; A Nothing))
(define-type (EM A) (Either A (Not A)))

(: peirce (All (A B) (-&amp;gt; (-&amp;gt; (-&amp;gt; A B) A) A)))
(define (peirce ABA) : A
  (call&amp;#x2F;cc ABA))

(: em-raw (All (A) (-&amp;gt; (-&amp;gt; A A) (EM A))))
(define (em-raw a_implies_a)
  (peirce (lambda ([not_em : (Not (EM A))]) : (EM A)
            (Right (lambda ([a : A])
                     (not_em (Left a)))))))

(define-syntax-rule (em A)
  (em-raw (lambda ([a : A]) : A a)))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here &lt;a href=&quot;https:&#x2F;&#x2F;docs.racket-lang.org&#x2F;ts-reference&#x2F;type-ref.html#%28form._%28%28lib._typed-racket%2Fbase-env%2Fbase-types..rkt%29._.Nothing%29%29&quot;&gt;&lt;code&gt;Nothing&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; is the empty type corresponding to a contradiction,
&lt;code&gt;(Either L R)&lt;&#x2F;code&gt; is a sum type corresponding to logical “or,”
and &lt;code&gt;(-&amp;gt; A B)&lt;&#x2F;code&gt; is a function type corresponding to logical implication. Due to what looks like a type inference limitation,
we need our excluded middle function to take an identity function as a parameter,
so we define a macro that takes a type as a parameter
and creates the necessary identity function and passes it to the &lt;code&gt;em-raw&lt;&#x2F;code&gt; function to get a proof that &lt;code&gt;A&lt;&#x2F;code&gt; is either true or false.&lt;&#x2F;p&gt;
&lt;p&gt;But wait, didn’t we show at the beginning that if we have a proof of “\(A\) or \(B\),” we can look at the last step of the proof to see which one of \(A\) and \(B\) is true? In this case \(B\) is just “not \(A\).” We have a function where we can input any statement, and it evaluates to an expression corresponding to a proof that the statement is either true or false. If we print this expression, we can see whether it looks like &lt;code&gt;(Left ...)&lt;&#x2F;code&gt; or &lt;code&gt;(Right ...)&lt;&#x2F;code&gt; to see whether \(A\) is true or false.&lt;&#x2F;p&gt;
&lt;p&gt;We have created our truth oracle in typed Racket.
We have a function that tells us whether any logical statement is true.
If this works, what can we do with this?&lt;&#x2F;p&gt;
&lt;p&gt;We can instantly mine every new Bitcoin,
worth (as of writing this) 48 million dollars per day,
by encoding the statement,
“there exists a &lt;a href=&quot;https:&#x2F;&#x2F;www.investopedia.com&#x2F;terms&#x2F;n&#x2F;nonce.asp&quot;&gt;nonce&lt;&#x2F;a&gt; starting with a prefix &lt;em&gt;p&lt;&#x2F;em&gt; that makes this block’s hash below the target value,”
in formal logic,
and gradually expanding the prefix while the oracle says the statement is true.
Eventually, the prefix will be the full nonce and you will have mined the block.
Since the nonce is 32-bits, you would only need to call the oracle 32 times,
once for each bit, to figure out if it should be 0 or 1.&lt;&#x2F;p&gt;
&lt;p&gt;We can solve all open problems in mathematics and formally verify our solutions,
by using a similar technique to generate formal proofs.&lt;&#x2F;p&gt;
&lt;p&gt;We can encode all known laws of physics and ask for
solutions to engineering problems.&lt;&#x2F;p&gt;
&lt;p&gt;We can figure out whether any arbitrary Turing machine will halt.&lt;&#x2F;p&gt;
&lt;p&gt;We can compute the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Kolmogorov_complexity&quot;&gt;Kolmogorov complexity&lt;&#x2F;a&gt; of all available stock market data, combined with possible future data,
to possibly perfectly predict stock price movements, but this is more speculative.&lt;&#x2F;p&gt;
&lt;p&gt;We can replace the inefficient gradient descent local optimization of machine learning with a process that &lt;em&gt;globally&lt;&#x2F;em&gt; chooses the best possible weights, and does so much more quickly, which would let any consumer-grade computer train AI systems much more powerful than leading AI labs.&lt;&#x2F;p&gt;
&lt;p&gt;We can implement &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;AIXI&quot;&gt;AIXI&lt;&#x2F;a&gt;, an algorithm for artificial general intelligence, implemented as an optimal reinforcement learning agent.&lt;&#x2F;p&gt;
&lt;p&gt;With all these possibilities, let’s try using it.&lt;&#x2F;p&gt;
&lt;p&gt;First we’ll try something simple, that “false” is false.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;(em Nothing)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;#&amp;lt;Right&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here &lt;code&gt;Nothing&lt;&#x2F;code&gt; corresponds to a contradiction,
and our oracle correctly says it’s false!&lt;&#x2F;p&gt;
&lt;p&gt;Now we’ll check “for all statements A, A is true.”&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;(em (All (A) A))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;#&amp;lt;Right&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Some things aren’t true, so it correctly says it’s false!&lt;&#x2F;p&gt;
&lt;p&gt;Next we’ll try something more complicated.
Let’s see if our oracle thinks 3 is even.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;(em (Refine [x : Natural] (= (* 2 x) 3)))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;#&amp;lt;Right&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This statement means “there exists natural number \(x\) such that \(2x = 3\),”
which is equivalent to saying 3 is even,
and it correctly says it’s false again!&lt;&#x2F;p&gt;
&lt;p&gt;Now let’s try checking if 10 is even.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;(em (Refine [x : Natural] (= (* 2 x) 10)))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;#&amp;lt;Right&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Oh, this is true but our oracle is saying it’s false.
Come to think of it, our oracle has only ever said statements are false.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s try something simpler.
Does it think any natural number exists?
Since a type having a value corresponds to a statement having a proof,
the type of natural numbers corresponds to the statement that at least one natural number exists.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;(em Natural)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;#&amp;lt;Right&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Okay, it looks like our oracle is just saying everything is false.
Maybe there’s a bug, or maybe one of our assumptions is wrong?&lt;&#x2F;p&gt;
&lt;p&gt;Wait, …but there &lt;em&gt;can’t&lt;&#x2F;em&gt; be a bug, because the type signature of &lt;code&gt;em&lt;&#x2F;code&gt; ensures the behavior we want.
It could be a bug in typed Racket’s type checker, potentially.
Let’s try to combine the proof of a false statement that it gives us with a proof of its negation, to get a contradiction.
Recall that this is Curry-Howard isomorphic with a type that has no possible values.
If we print out the impossible value that has this type,
we can try to get some idea what’s going on here.&lt;&#x2F;p&gt;
&lt;p&gt;First, we’ll set up a way to get the inner proof that no number exists.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;(let ([proof : (Either Natural (Not Natural))
       (em Natural)])
  (if (Left? proof)
    (format &amp;quot;A number exists: ~a&amp;quot;
            (Left-v proof))
    (format &amp;quot;No number exists: ~a&amp;quot;
            (Right-v proof))))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;&amp;quot;No number exists: #&amp;lt;procedure&amp;gt;&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The proof that no number exists is a &lt;code&gt;#&amp;lt;procedure&amp;gt;&lt;&#x2F;code&gt; value of type &lt;code&gt;(Not Natural)&lt;&#x2F;code&gt;.
Recall from the definition of &lt;code&gt;Not&lt;&#x2F;code&gt; that this is equivalent to
&lt;code&gt;(-&amp;gt; Natural Nothing)&lt;&#x2F;code&gt;,
so this procedure value corresponds to a proof that a natural number implies a contradiction.
We can pass the function a natural number,
and it will return a value that can’t exist.
This shouldn’t be possible, but let’s see what happens!
We’ll just replace &lt;code&gt;(Right-v proof)&lt;&#x2F;code&gt; with &lt;code&gt;((Right-v proof) 283)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;(let ([proof : (Either Natural (Not Natural))
       (em Natural)])
  (if (Left? proof)
    (format &amp;quot;A number exists: ~a&amp;quot;
            (Left-v proof))
    (format &amp;quot;Value that shouldn&amp;#x27;t exist: ~a&amp;quot;
            ((Right-v proof) 283))))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;&amp;quot;A number exists: 283&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Huh, when we modify the code to create the impossible value,
the oracle now correctly says the statement is true.
But the oracle runs &lt;strong&gt;&lt;em&gt;before&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt; the impossible value is created.
And the number it gives us to prove a number exists is the &lt;em&gt;same number&lt;&#x2F;em&gt;
we use to create the impossible value in the branch that &lt;em&gt;doesn’t even run&lt;&#x2F;em&gt;???
Not only is code that runs later in the program influencing code that runs earlier, the code that runs later doesn’t run at all, and it also somehow passes a value back in time?
The code somehow knows what number we’ll use in the future,
in code that never even runs, and changes its answer accordingly.
What!!?!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Okay, it turns out that we didn’t really write a truth oracle,
and &lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt; isn’t a normal function.
To understand what’s going on,
we need to go over some more concepts.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;constructive-vs-classical-logic&quot;&gt;Constructive vs classical logic&lt;&#x2F;h2&gt;
&lt;p&gt;One detail I glossed over earlier was the distinction between constructive and classical logic.
This is critical to understanding this bizarre behavior.
The “extracting information from proofs” section was a bit misleading.
Specifically, it stops being true once you add certain axioms.
I said that if you have a proof of “\(A\) or \(B\),”
you can look at the last step of the proof to see if
it’s the left-or-introduction or right-or-introduction rule,
to see which of \(A\) or \(B\) is the one that’s true.
But one important detail I left out is this requires that left-or-introduction and right-or-introduction are the only rules to create proofs of logical “or” statements.
There is another rule for proving “or” statements that is commonly added as an axiom, namely, the &lt;em&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Law_of_excluded_middle&quot;&gt;law of excluded middle&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;, the &lt;em&gt;same rule that we implemented in typed Racket&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Logic without the law of excluded middle, or anything equivalent to it, is called &lt;em&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Intuitionistic_logic&quot;&gt;constructive logic&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;.
It is called “constructive,” because in order to prove “\(A\) or \(B\),”
you need to decide whether \(A\) or \(B\) is true and directly construct a proof of that.
Similarly, in order to prove that a value exists that has some property,
you need to give the actual value that exists.
This makes it map nicely to functional programming in the Curry-Howard isomorphism.
Normally to get a value of a sum type, you have to know the specific variant in order to construct it.
For example, to construct a &lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;&#x2F;code&gt; in Rust,
you need to specifically use &lt;code&gt;Ok()&lt;&#x2F;code&gt; or &lt;code&gt;Err()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;When you add the law of excluded middle, or something equivalent to it,
constructive logic becomes &lt;em&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Classical_logic&quot;&gt;classical logic&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;.
It lets you prove “or” statements without you needing to know which statement is true,
and it lets you prove existence of an object without needing to actually know the object.
Here is an example classical proof to give you an idea of what this is like:&lt;&#x2F;p&gt;
&lt;p&gt;Let’s say we want to prove that there exists irrational numbers \(x\) and \(y\) such that \(x^y\) is rational.
We know that \(\sqrt 2\) is irrational.
By the law of excluded middle,
we know that \(\left(\sqrt 2 \right) ^ {\sqrt 2}\) is either rational or irrational.
We can consider the consequences of each case separately:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;If it’s rational, then we can say the values of \(x\) and \(y\) are
both \(\sqrt 2\).
Then \(x\) and \(y\) are both irrational and \(x^y\) is rational. This is what we wanted to show, so that means the proof is valid for this case.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;If \(\left(\sqrt 2 \right) ^ {\sqrt 2}\) is irrational,
then we can say the values of \(x\) and \(y\) are
\(x = \left(\sqrt 2 \right) ^ {\sqrt 2}\) and \(y = \sqrt{2}\).
Then, \(x\) and \(y\) are both irrational and&lt;&#x2F;p&gt;
&lt;p&gt;\(x^y\)
\(= \left( \left(\sqrt{2}\right)^{\sqrt{2}} \right)^{\sqrt{2}}\)
\(= \left(\sqrt{2}\right)^{\sqrt{2} \times \sqrt{2}}\)
\(= \left(\sqrt{2}\right)^2\)
\(= 2\),&lt;&#x2F;p&gt;
&lt;p&gt;which is rational,
and that finishes the proof.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;(Source: &lt;a href=&quot;https:&#x2F;&#x2F;softwarefoundations.cis.upenn.edu&#x2F;lf-current&#x2F;Logic.html&quot;&gt;Software Foundations&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;Note that even though we proved that values \(x\) and \(y\) exist,
we didn’t need to prove what they are.
We gave two possibilities, but from the proof alone,
we don’t know which possibility is correct.
This is because of the use of the law of excluded middle in the beginning.
That makes it a &lt;em&gt;non-constructive&lt;&#x2F;em&gt; proof, which lets us prove values exist without knowing what they are.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-call-cc-function&quot;&gt;The &lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt; function&lt;&#x2F;h2&gt;
&lt;p&gt;Constructive logic corresponds nicely to functional programming under the Curry-Howard correspondence.
But Racket’s &lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt; function corresponds to
&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Peirce%27s_law&quot;&gt;Peirce’s law&lt;&#x2F;a&gt;,
which is equivalent to the law of excluded middle,
and thus part of classical logic and not constructive logic.
How does this work?
Well, &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Call-with-current-continuation&quot;&gt;&lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; is not a normal function.
It has different control-flow than normally expected in functional programming languages,
which caused the strange behavior in our program.&lt;&#x2F;p&gt;
&lt;p&gt;The full name of &lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt; is &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Call-with-current-continuation&quot;&gt;call-with-current-continuation&lt;&#x2F;a&gt;.
It takes a function as its argument,
and it calls the function,
passing it something called the “current continuation.”
For example, &lt;code&gt;(call&#x2F;cc (lambda (cc) &quot;foo&quot;))&lt;&#x2F;code&gt; evaluates to &lt;code&gt;&quot;foo&quot;&lt;&#x2F;code&gt;.
But what does the “current continuation” do?&lt;&#x2F;p&gt;
&lt;p&gt;It’s a function that takes as input a value,
and rolls the program state &lt;em&gt;back in time&lt;&#x2F;em&gt;,
making the &lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt; expression return that value instead.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s look at an example to understand this better:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;#lang racket

(define (main)
  (define continuation null)
  (define value
    (string-append
     &amp;quot;prefix | &amp;quot;
     (call&amp;#x2F;cc (lambda (cc)
                (set! continuation cc)
                &amp;quot;original value&amp;quot;))))
  (println value)
  (continuation &amp;quot;new value&amp;quot;))

(main)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;&amp;quot;prefix | original value&amp;quot;
&amp;quot;prefix | new value&amp;quot;
...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this example program,
we save the continuation in a variable called &lt;code&gt;continuation&lt;&#x2F;code&gt; so we can call it easily later.
At first, the &lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt; expression returns the string &lt;code&gt;&quot;original value&quot;&lt;&#x2F;code&gt;,
and then a prefix &lt;code&gt;&quot;prefix | &quot;&lt;&#x2F;code&gt; is added and it’s saved in a variable called &lt;code&gt;value&lt;&#x2F;code&gt;.
When we print it with &lt;code&gt;(println value)&lt;&#x2F;code&gt;,
it shows the full string &lt;code&gt;&quot;prefix | original value&quot;&lt;&#x2F;code&gt;.
Then we call the continuation with &lt;code&gt;(continuation &quot;new value&quot;)&lt;&#x2F;code&gt;.
This rolls back the state of the &lt;code&gt;value&lt;&#x2F;code&gt; definition,
with the output of the &lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt; expression changed to &lt;code&gt;&quot;new value&quot;&lt;&#x2F;code&gt;.
The definition expression of &lt;code&gt;value&lt;&#x2F;code&gt; evaluates again from that point,
adding the prefix &lt;code&gt;&quot;prefix | &quot;&lt;&#x2F;code&gt; again.
Then we print &lt;code&gt;value&lt;&#x2F;code&gt; again, giving the new value &lt;code&gt;&quot;prefix | new value&quot;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To summarize what happened,
the continuation saved the state of the program,
and when we called it later, it rewound the program back to the saved state and made &lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt; return a different value.&lt;&#x2F;p&gt;
&lt;p&gt;In other words, the continuation can pass values back in time.
One way to think about this is that &lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt; both generates a time machine (continuation) and acts as a receiver for future information that get sent backwards in time.
That’s why we were seeing the strange behavior from before.&lt;&#x2F;p&gt;
&lt;p&gt;What is this function used for? Why does it exist?
As it turns out,
you can use it to implement control flow constructs that usual functional programming features can’t easily represent,
like loops, break statements, return statements, generators, and coroutines.
However, that is beyond the scope of this post,
so let’s keep trying to figure out what’s going on.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-the-code-works&quot;&gt;How the code works&lt;&#x2F;h2&gt;
&lt;p&gt;Now that we understand &lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt;,
we can return to the code and try to understand how it works.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;(call&amp;#x2F;cc (lambda ([not_em : (Not (EM A))]) : (EM A)
            (Right (lambda ([a : A])
                     (not_em (Left a))))))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;the-continuation&quot;&gt;The continuation&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;not_em&lt;&#x2F;code&gt; function is the continuation,
and it has type &lt;code&gt;(Not (EM A))&lt;&#x2F;code&gt;.
Recall that this means it is a function that takes an argument
of type &lt;code&gt;(EM A)&lt;&#x2F;code&gt; and returns a value of type &lt;code&gt;Nothing&lt;&#x2F;code&gt;,
which doesn’t actually exist.
Under the Curry-Howard isomorphism,
&lt;code&gt;not_em&lt;&#x2F;code&gt; can be interpreted as a proof that “\(A\) or not \(A\)” implies a contradiction.
Also, empty types like &lt;code&gt;Nothing&lt;&#x2F;code&gt; in Racket and the never type in Rust are commonly used for expressions with abnormal control flow that don’t evaluate to a value normally, such as &lt;code&gt;break&lt;&#x2F;code&gt; statements.
The &lt;code&gt;not_em&lt;&#x2F;code&gt; function is a continuation; it doesn’t actually return a value, so it makes sense that its return type can be &lt;code&gt;Nothing&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-result&quot;&gt;The result&lt;&#x2F;h3&gt;
&lt;p&gt;Initially (in the first timeline), the &lt;code&gt;call&#x2F;cc&lt;&#x2F;code&gt; expression
evaluates to&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;(Right (lambda ([a : A])
         (not_em (Left a))))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;Right&lt;&#x2F;code&gt; type constructor corresponds to the “false” part of the excluded middle,
which is why our oracle started out saying everything was false.
The type of this expression is &lt;code&gt;(EM A)&lt;&#x2F;code&gt;,
which is the same as &lt;code&gt;(Either A (Not A))&lt;&#x2F;code&gt;,
which we can expand further into &lt;code&gt;(Either A (-&amp;gt; A Nothing))&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So the expression&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;(lambda ([a : A])
  (not_em (Left a)))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;passed to the &lt;code&gt;Right&lt;&#x2F;code&gt; constructor must have type &lt;code&gt;(-&amp;gt; A Nothing)&lt;&#x2F;code&gt;.
The parameter does have type &lt;code&gt;A&lt;&#x2F;code&gt;,
and the body of the function calls a continuation,
which means the body has type &lt;code&gt;Nothing&lt;&#x2F;code&gt;.
So the type of &lt;code&gt;(-&amp;gt; A Nothing)&lt;&#x2F;code&gt; makes sense.
Further, since &lt;code&gt;a&lt;&#x2F;code&gt; has type &lt;code&gt;A&lt;&#x2F;code&gt;,
it must be the case that &lt;code&gt;(Left a)&lt;&#x2F;code&gt; has type &lt;code&gt;(EM A)&lt;&#x2F;code&gt;.
And &lt;code&gt;not_em&lt;&#x2F;code&gt;, the continuation, has type &lt;code&gt;(-&amp;gt; (EM A) Nothing)&lt;&#x2F;code&gt;,
so it also makes sense that the &lt;code&gt;not_em&lt;&#x2F;code&gt; call type checks.&lt;&#x2F;p&gt;
&lt;p&gt;Okay, that’s why it type checks.
What about the behavior?
Initially for a statement &lt;code&gt;A&lt;&#x2F;code&gt;,
the oracle always returned a &lt;code&gt;Right&lt;&#x2F;code&gt; value,
corresponding to a proof that &lt;code&gt;(Not A)&lt;&#x2F;code&gt;,
or &lt;code&gt;(-&amp;gt; A Nothing)&lt;&#x2F;code&gt;,
a function that takes &lt;code&gt;A&lt;&#x2F;code&gt; and returns &lt;code&gt;Nothing&lt;&#x2F;code&gt;.
When we gave the function a value &lt;code&gt;a&lt;&#x2F;code&gt; of type &lt;code&gt;A&lt;&#x2F;code&gt;,
the state of the program got rolled back to the oracle,
and it returned &lt;code&gt;(Left a)&lt;&#x2F;code&gt; instead.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;racket&quot; class=&quot;language-racket &quot;&gt;&lt;code class=&quot;language-racket&quot; data-lang=&quot;racket&quot;&gt;(Right (lambda ([a : A])
         (not_em (Left a))))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is &lt;em&gt;exactly&lt;&#x2F;em&gt; what this code does.
It returns &lt;code&gt;Right&lt;&#x2F;code&gt; with a function that takes an argument &lt;code&gt;a&lt;&#x2F;code&gt;,
and calls the continuation with &lt;code&gt;(Left a)&lt;&#x2F;code&gt;,
rolling back the state of the program to when the oracle was called
and rerunning it with the new output.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-devil-of-the-excluded-middle&quot;&gt;The Devil of the Excluded Middle&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;homepages.inf.ed.ac.uk&#x2F;wadler&#x2F;papers&#x2F;dual&#x2F;dual.pdf&quot;&gt;Philip Wadler has a story&lt;&#x2F;a&gt; about the computational interpretation of the law of excluded middle:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Once upon a time, the devil approached a man and made
an offer: “Either (a) I will give you one billion dollars, or (b)
I will grant you any wish if you pay me one billion dollars.
Of course, I get to choose whether I offer (a) or (b).”&lt;&#x2F;p&gt;
&lt;p&gt;The man was wary. Did he need to sign over his soul?
No, said the devil, all the man need do is accept the offer.&lt;&#x2F;p&gt;
&lt;p&gt;The man pondered. If he was offered (b) it was unlikely
that he would ever be able to buy the wish, but what was
the harm in having the opportunity available?&lt;&#x2F;p&gt;
&lt;p&gt;“I accept,” said the man at last. “Do I get (a) or (b)?”&lt;&#x2F;p&gt;
&lt;p&gt;The devil paused. “I choose (b).”&lt;&#x2F;p&gt;
&lt;p&gt;The man was disappointed but not surprised. That was
that, he thought. But the offer gnawed at him. Imagine
what he could do with his wish! Many years passed, and
the man began to accumulate money. To get the money he
sometimes did bad things, and dimly he realized that this
must be what the devil had in mind. Eventually he had his
billion dollars, and the devil appeared again.&lt;&#x2F;p&gt;
&lt;p&gt;“Here is a billion dollars,” said the man, handing over a
valise containing the money. “Grant me my wish!”&lt;&#x2F;p&gt;
&lt;p&gt;The devil took possession of the valise. Then he said,
“Oh, did I say (b) before? I’m so sorry. I meant (a). It is
my great pleasure to give you one billion dollars.”&lt;&#x2F;p&gt;
&lt;p&gt;And the devil handed back to the man the same valise
that the man had just handed to him.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;So our “truth oracle” reveals itself as a
computational manifestation of the devil’s bargain from this story.
In hindsight, it makes sense that the program that Curry-Howard-corresponds to the law of excluded middle has to behave like this.
It needs to actually return a concrete value, since it’s a computer program,
but it also can’t ever give the wrong answer, since that would give a value of the empty type and break the type system.
So instead it hides a time machine inside the value,
and rigs it to activate, as a fail-safe mechanism, whenever code tries to use it to do something that would disastrously break the programming language.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
