prop/
imply.rs

1//! Tactics for Logical IMPLY.
2
3#![allow(unreachable_code)]
4
5use crate::*;
6
7/// `(a => b)  =>  (¬b => ¬a)`.
8///
9/// Swap sides of implication by taking their negation.
10pub fn modus_tollens<A: Prop, B: Prop>(f: Imply<A, B>) -> Imply<Not<B>, Not<A>> {
11    Rc::new(move |x| {
12        let f = f.clone();
13        Rc::new(move |y| match x(f(y)) {})
14    })
15}
16
17/// `(¬b => ¬a)  =>  (a => b)`.
18pub fn rev_modus_tollens<A: DProp, B: DProp>(f: Imply<Not<B>, Not<A>>) -> Imply<A, B> {
19    imply::rev_double_neg(Rc::new(move |x| {
20        let f = f.clone();
21        Rc::new(move |y| match x(f(y)) {})
22    }))
23}
24
25/// `(¬b => ¬a) ∧ (a ∨ ¬a) ∧ (b ∨ ¬b)  =>  (a => b)`.
26pub fn rev_modus_tollens_excm<A: Prop, B: Prop>(
27    f: Imply<Not<B>, Not<A>>,
28    excm_a: ExcM<A>,
29    excm_b: ExcM<B>,
30) -> Imply<A, B> {
31    imply::rev_double_neg_excm(Rc::new(move |x| {
32        let f = f.clone();
33        Rc::new(move |y| match x(f(y)) {})
34    }), excm_a, excm_b)
35}
36
37/// `(¬b => ¬a) ∧ ((a ∨ ¬a) == (b ∨ ¬b))  =>  (a => b)`.
38pub fn rev_modus_tollens_eq_excm<A: Prop, B: Prop>(
39    f: Imply<Not<B>, Not<A>>,
40    eq_excm_a_excm_b: Eq<ExcM<A>, ExcM<B>>,
41) -> Imply<A, B> {
42    imply::rev_double_neg_eq_excm(Rc::new(move |x| {
43        let f = f.clone();
44        Rc::new(move |y| match x(f(y)) {})
45    }), eq_excm_a_excm_b)
46}
47
48/// `(¬b => ¬a) ∧ (a => (b ∨ ¬b))  =>  (a => b)`.
49pub fn rev_modus_tollens_imply_excm<A: Prop, B: Prop>(
50    f: Imply<Not<B>, Not<A>>,
51    a_excm_b: Imply<A, ExcM<B>>,
52) -> Imply<A, B> {
53    imply::rev_double_neg_imply_excm(Rc::new(move |x| {
54        let f = f.clone();
55        Rc::new(move |y| match x(f(y)) {})
56    }), a_excm_b)
57}
58
59/// `(a => b) ∧ (b => c)  =>  (a => c)`.
60pub fn transitivity<A: Prop, B: Prop, C: Prop>(
61    f: Imply<A, B>,
62    g: Imply<B, C>,
63) -> Imply<A, C> {
64    Rc::new(move |x| g(f(x)))
65}
66
67/// `(a => b) ∧ a  =>  b`
68pub fn modus_ponens<A: Prop, B: Prop>(
69    f: Imply<A, B>,
70    a: A,
71) -> B {
72    f(a)
73}
74
75/// `(b => a) ∧ ¬a  => ¬b`.
76pub fn rev_modus_ponens<A: Prop, B: Prop>(g: Imply<B, A>, f: Not<A>) -> Not<B> {
77    Rc::new(move |b| f(g(b)))
78}
79
80/// `(a => (b => c))  =>  (b => (a => c))`
81pub fn reorder_args<A: Prop, B: Prop, C: Prop>(
82    f: Imply<A, Imply<B, C>>
83) -> Imply<B, Imply<A, C>> {
84    Rc::new(move |x| {
85        let f = f.clone();
86        Rc::new(move |y| f(y)(x.clone()))
87    })
88}
89
90/// `(a => b)  =>  (¬¬a => ¬¬b)`.
91pub fn double_neg<A: DProp, B: Prop>(f: Imply<A, B>) -> Imply<Not<Not<A>>, Not<Not<B>>> {
92    Rc::new(move |nn_a| not::double(f(not::rev_double(nn_a))))
93}
94
95/// `(¬¬a => ¬¬b)  =>  (a => b)`.
96pub fn rev_double_neg<A: DProp, B: DProp>(f: Imply<Not<Not<A>>, Not<Not<B>>>) -> Imply<A, B> {
97    use Either::*;
98
99    let a = <A as Decidable>::decide();
100    let b = <B as Decidable>::decide();
101    match (a, b) {
102        (_, Left(b)) => b.map_any(),
103        (Right(a), _) => Rc::new(move |x| match a(x) {}),
104        (Left(a), Right(b)) => match f(not::double(a))(b) {}
105    }
106}
107
108/// `(¬¬a => ¬¬b)  =>  (a => b)`.
109pub fn rev_double_neg_excm<A: Prop, B: Prop>(
110    f: Imply<Not<Not<A>>, Not<Not<B>>>,
111    excm_a: ExcM<A>,
112    excm_b: ExcM<B>,
113) -> Imply<A, B> {
114    use Either::*;
115
116    match (excm_a, excm_b) {
117        (_, Left(b)) => b.map_any(),
118        (Right(a), _) => Rc::new(move |x| match a(x) {}),
119        (Left(a), Right(b)) => match f(not::double(a))(b) {}
120    }
121}
122
123/// `(¬¬a => ¬¬b) ∧ ((a ∨ ¬a) == (b ∨ ¬b))  =>  (a => b)`.
124pub fn rev_double_neg_eq_excm<A: Prop, B: Prop>(
125    f: Imply<Not<Not<A>>, Not<Not<B>>>,
126    eq_excm_a_excm_b: Eq<ExcM<A>, ExcM<B>>,
127) -> Imply<A, B> {
128    use Either::*;
129
130    Rc::new(move |a| {
131        match eq_excm_a_excm_b.0(Left(a.clone())) {
132            Left(b) => b,
133            Right(nb) => match f(not::double(a))(nb) {}
134        }
135    })
136}
137
138/// `(¬¬a => ¬¬b) ∧ (a => (b ∨ ¬b))  =>  (a => b)`.
139pub fn rev_double_neg_imply_excm<A: Prop, B: Prop>(
140    f: Imply<Not<Not<A>>, Not<Not<B>>>,
141    a_excm_b: Imply<A, ExcM<B>>,
142) -> Imply<A, B> {
143    use Either::*;
144
145    Rc::new(move |a| {
146        match a_excm_b(a.clone()) {
147            Left(b) => b,
148            Right(nb) => match f(not::double(a))(nb) {}
149        }
150    })
151}
152
153/// `(a => b) => (¬a ∨ b)`.
154pub fn to_or_da<A: DProp, B: Prop>(f: Imply<A, B>) -> Or<Not<A>, B> {
155    to_or_excm_a(f, A::decide())
156}
157
158/// `(a => b) ⋀ (a ⋁ ¬a)  =>  (¬a ∨ b)`.
159pub fn to_or_excm_a<A: Prop, B: Prop>(f: Imply<A, B>, excm_a: ExcM<A>) -> Or<Not<A>, B> {
160    use Either::*;
161
162    match excm_a {
163        Left(a) => Right(f(a)),
164        Right(na) => Left(na),
165    }
166}
167
168/// `(a => b) => (¬a ∨ b)`.
169pub fn to_or_db<A: Prop, B: DProp>(f: Imply<A, B>) -> Or<Not<A>, B> {
170    to_or_excm_b(f, B::decide())
171}
172
173/// `(a => b) => (¬a ∨ b)`.
174pub fn to_or_excm_b<A: Prop, B: Prop>(f: Imply<A, B>, excm_b: ExcM<B>) -> Or<Not<A>, B> {
175    use Either::*;
176
177    match excm_b {
178        Left(b) => Right(b),
179        Right(nb) => Left(modus_tollens(f)(nb)),
180    }
181}
182
183/// `(¬a ∨ b) => (a => b)`.
184pub fn from_or<A: Prop, B: Prop>(f: Or<Not<A>, B>) -> Imply<A, B> {
185    Rc::new(move |a| {
186        match f.clone() {
187            Left(na) => absurd()(na(a)),
188            Right(b) => b,
189        }
190    })
191}
192
193/// `(¬a => b) => (¬b => a)`.
194pub fn flip_neg_left<A: DProp, B: Prop>(f: Imply<Not<A>, B>) -> Imply<Not<B>, A> {
195    let g = imply::modus_tollens(f);
196    Rc::new(move |x| not::rev_double(g(x)))
197}
198
199/// `(¬a => b) ⋀ (a ⋁ ¬a)  =>  (¬b => a)`.
200pub fn flip_neg_left_excm<A: Prop, B: Prop>(f: Imply<Not<A>, B>, excm: ExcM<A>) -> Imply<Not<B>, A> {
201    let g = imply::modus_tollens(f);
202    Rc::new(move |x| not::rev_double_excm(g(x), excm.clone()))
203}
204
205/// `(a => ¬b) => (b => ¬a)`.
206pub fn flip_neg_right<A: Prop, B: Prop>(f: Imply<A, Not<B>>) -> Imply<B, Not<A>> {
207    let g = imply::modus_tollens(f);
208    Rc::new(move |x| g(not::double(x)))
209}
210
211/// `((a ∧ b) => c)  =>  (a => (b => c))`.
212pub fn chain<A: Prop, B: Prop, C: Prop>(f: Imply<And<A, B>, C>) -> Imply<A, Imply<B, C>> {
213    Rc::new(move |x| {
214        let f = f.clone();
215        Rc::new(move |y| f((x.clone(), y)))
216    })
217}
218
219/// `a => (b => c)  =>  ((a ∧ b) => c)`.
220pub fn rev_chain<A: Prop, B: Prop, C: Prop>(f: Imply<A, Imply<B, C>>) -> Imply<And<A, B>, C> {
221    Rc::new(move |(a, b)| f(a)(b))
222}
223
224/// `(a => b) ∧ (a == c)  =>  (c => b)`.
225pub fn in_left_arg<A: Prop, B: Prop, C: Prop>(f: Imply<A, B>, (_, g1): Eq<A, C>) -> Imply<C, B> {
226    transitivity(g1, f)
227}
228
229/// `(a => b) ∧ (b == c)  =>  (a => c)`.
230pub fn in_right_arg<A: Prop, B: Prop, C: Prop>(f: Imply<A, B>, (g0, _): Eq<B, C>) -> Imply<A, C> {
231    transitivity(f, g0)
232}
233
234/// Makes it easier to traverse.
235pub fn in_left<A: Prop, B: Prop, C: Prop, F>(
236    ab: Imply<A, B>,
237    f: F
238) -> Imply<C, B>
239    where F: Fn(C) -> A + 'static
240{
241    Rc::new(move |c| ab(f(c)))
242}
243
244/// Makes it easier to traverse.
245pub fn in_right<A: Prop, B: Prop, C: Prop, F>(
246    ab: Imply<A, B>,
247    f: F
248) -> Imply<A, C>
249    where F: Fn(A, B) -> C + 'static
250{
251    Rc::new(move |a| f(a.clone(), ab(a)))
252}
253
254/// `(a == b)  =>  (a => c) == (b => c)`.
255pub fn eq_left<A: Prop, B: Prop, C: Prop>((ab, ba): Eq<A, B>) -> Eq<Imply<A, C>, Imply<B, C>> {
256    (Rc::new(move |ac| transitivity(ba.clone(), ac)),
257     Rc::new(move |bc| transitivity(ab.clone(), bc)))
258}
259
260/// `(a == b)  =>  (c => a) == (b => c)`.
261pub fn eq_right<A: Prop, B: Prop, C: Prop>((ab, ba): Eq<A, B>) -> Eq<Imply<C, A>, Imply<C, B>> {
262    (Rc::new(move |ca| transitivity(ca, ab.clone())),
263     Rc::new(move |cb| transitivity(cb, ba.clone())))
264}
265
266/// `(a => c) ∧ (b => c)  =>  ((a ∧ b) => c)`.
267pub fn join<A: Prop, B: Prop, C: Prop>(f: Imply<A, C>, _: Imply<B, C>) -> Imply<And<A, B>, C> {
268    Rc::new(move |(a, _)| f.clone()(a))
269}
270
271/// `false => a`.
272pub fn absurd<A: Prop>() -> Imply<False, A> {
273    Rc::new(|x| match x {})
274}
275
276/// `a => a`.
277pub fn id<A: Prop>() -> Imply<A, A> {
278    Rc::new(|x| x)
279}
280
281/// `(a => (b ∨ c))  =>  (a => b) ∨ (a => c)`.
282pub fn or_split_da<A: DProp, B: Prop, C: Prop>(
283    f: Imply<A, Or<B, C>>
284) -> Or<Imply<A, B>, Imply<A, C>> {
285    or_split_excm_a(f, A::decide())
286}
287
288/// `(a => (b ∨ c)) ⋀ (a ⋁ ¬a)  =>  (a => b) ∨ (a => c)`.
289pub fn or_split_excm_a<A: Prop, B: Prop, C: Prop>(
290    f: Imply<A, Or<B, C>>,
291    excm_a: ExcM<A>
292) -> Or<Imply<A, B>, Imply<A, C>> {
293    match excm_a {
294        Left(a) => match f(a) {
295            Left(b) => Left(b.map_any()),
296            Right(c) => Right(c.map_any())
297        }
298        Right(na) => Left(Rc::new(move |a| not::absurd(na.clone(), a)))
299    }
300}
301
302/// `(a => (b ∨ c))  =>  (a => b) ∨ (a => c)`.
303pub fn or_split_db<A: Prop, B: DProp, C: Prop>(
304    f: Imply<A, Or<B, C>>
305) -> Or<Imply<A, B>, Imply<A, C>> {
306    match B::decide() {
307        Left(b) => Left(b.map_any()),
308        Right(nb) => Right(Rc::new(move |a| match f(a) {
309            Left(b) => not::absurd(nb.clone(), b),
310            Right(c) => c
311        }))
312    }
313}
314
315/// `(a => (b ∨ c))  =>  (a => b) ∨ (a => c)`.
316pub fn or_split_dc<A: Prop, B: Prop, C: DProp>(
317    f: Imply<A, Or<B, C>>
318) -> Or<Imply<A, B>, Imply<A, C>> {
319    match C::decide() {
320        Left(c) => Right(c.map_any()),
321        Right(nc) => Left(Rc::new(move |a| match f(a) {
322            Left(b) => b,
323            Right(c) => not::absurd(nc.clone(), c)
324        }))
325    }
326}
327
328/// `a  =>  (b => (a ∧ b))`.
329pub fn and_map<A: Prop, B: Prop>(a: A) -> Imply<B, And<A, B>> {
330    Rc::new(move |b| (a.clone(), b))
331}
332
333/// `(a => b) ∨ (b => a)`.
334///
335/// This is also called "trichotomy".
336pub fn total<A: DProp, B: Prop>() -> Or<Imply<A, B>, Imply<B, A>> {
337    total_excm(A::decide())
338}
339
340/// `(a ∨ ¬a)  =>  (a => b) ∨ (b => a)`.
341///
342/// This is also called "trichotomy".
343pub fn total_excm<A: Prop, B: Prop>(excm_a: ExcM<A>) -> Or<Imply<A, B>, Imply<B, A>> {
344    match excm_a {
345        Left(a) => Right(a.map_any()),
346        Right(na) => Left(rev_modus_tollens_imply_excm(na.clone().map_any(),
347            Rc::new(move |a| not::absurd(na.clone(), a)))),
348    }
349}
350
351/// `(a => (a => b))  =>  (a => b)`.
352pub fn reduce<A: Prop, B: Prop>(x: Imply<A, Imply<A, B>>) -> Imply<A, B> {
353    Rc::new(move |a| x(a.clone())(a))
354}