Skip to main content

argumentation_schemes/catalog/
source.rs

1//! Source-based schemes: attacking or bolstering the person, not the argument.
2//!
3//! Ref: Walton, Reed & Macagno 2008, Chapter 5 + Appendix 1.
4
5use crate::catalog::SOURCE_ID_OFFSET;
6use crate::critical::CriticalQuestion;
7use crate::scheme::*;
8use crate::types::*;
9
10/// Return all source-based schemes.
11pub fn all() -> Vec<SchemeSpec> {
12    vec![
13        ad_hominem(),
14        ad_hominem_circumstantial(),
15        argument_from_bias(),
16        ethotic_argument(),
17    ]
18}
19
20/// Ad Hominem — generic (Walton 2008 p.141).
21///
22/// Negated-conclusion scheme: target has flaw F, therefore ¬claim.
23pub fn ad_hominem() -> SchemeSpec {
24    SchemeSpec {
25        id: SchemeId(SOURCE_ID_OFFSET),
26        name: "Ad Hominem".into(),
27        category: SchemeCategory::SourceBased,
28        premises: vec![
29            PremiseSlot::new("target", "The person being attacked", SlotRole::Agent),
30            PremiseSlot::new("flaw", "The character flaw alleged", SlotRole::Property),
31            PremiseSlot::new(
32                "claim",
33                "The claim being challenged via the attack",
34                SlotRole::Proposition,
35            ),
36        ],
37        conclusion: ConclusionTemplate::negated(
38            "?claim should be rejected because ?target has ?flaw",
39            "?claim",
40        ),
41        critical_questions: vec![
42            CriticalQuestion::new(
43                1,
44                "Does ?target really have ?flaw?",
45                Challenge::PremiseTruth("flaw".into()),
46            ),
47            CriticalQuestion::new(
48                2,
49                "Does ?flaw actually bear on the credibility of ?claim?",
50                Challenge::Proportionality,
51            ),
52            CriticalQuestion::new(
53                3,
54                "Is the attack on ?target proportionate to ?flaw?",
55                Challenge::Proportionality,
56            ),
57        ],
58        metadata: SchemeMetadata {
59            citation: "Walton 2008 p.141".into(),
60            domain_tags: vec!["source".into(), "attack".into()],
61            presumptive: true,
62            strength: SchemeStrength::Weak,
63        },
64    }
65}
66
67/// Ad Hominem — circumstantial (Walton 2008 p.143).
68///
69/// Negated-conclusion scheme.
70pub fn ad_hominem_circumstantial() -> SchemeSpec {
71    SchemeSpec {
72        id: SchemeId(SOURCE_ID_OFFSET + 1),
73        name: "Ad Hominem Circumstantial".into(),
74        category: SchemeCategory::SourceBased,
75        premises: vec![
76            PremiseSlot::new(
77                "target",
78                "The person whose circumstances are cited",
79                SlotRole::Agent,
80            ),
81            PremiseSlot::new(
82                "inconsistency",
83                "How target's circumstances conflict with the claim",
84                SlotRole::Property,
85            ),
86            PremiseSlot::new("claim", "The claim being undermined", SlotRole::Proposition),
87        ],
88        conclusion: ConclusionTemplate::negated(
89            "?claim is undermined because ?target's circumstances (?inconsistency) are inconsistent with it",
90            "?claim",
91        ),
92        critical_questions: vec![
93            CriticalQuestion::new(
94                1,
95                "Does ?target actually have the alleged ?inconsistency?",
96                Challenge::PremiseTruth("inconsistency".into()),
97            ),
98            CriticalQuestion::new(
99                2,
100                "Is the inconsistency relevant to ?claim?",
101                Challenge::Proportionality,
102            ),
103            CriticalQuestion::new(
104                3,
105                "Could ?target's ?claim still be valid despite the inconsistency?",
106                Challenge::RuleValidity,
107            ),
108        ],
109        metadata: SchemeMetadata {
110            citation: "Walton 2008 p.143".into(),
111            domain_tags: vec!["source".into(), "attack".into(), "hypocrisy".into()],
112            presumptive: true,
113            strength: SchemeStrength::Weak,
114        },
115    }
116}
117
118/// Argument from Bias (Walton 2008 p.340).
119///
120/// Negated-conclusion scheme.
121pub fn argument_from_bias() -> SchemeSpec {
122    SchemeSpec {
123        id: SchemeId(SOURCE_ID_OFFSET + 2),
124        name: "Argument from Bias".into(),
125        category: SchemeCategory::SourceBased,
126        premises: vec![
127            PremiseSlot::new("source", "The biased source", SlotRole::Agent),
128            PremiseSlot::new("bias", "The alleged bias", SlotRole::Property),
129            PremiseSlot::new(
130                "claim",
131                "The claim made by the biased source",
132                SlotRole::Proposition,
133            ),
134        ],
135        conclusion: ConclusionTemplate::negated(
136            "?claim should be treated with suspicion because ?source has ?bias",
137            "?claim",
138        ),
139        critical_questions: vec![
140            CriticalQuestion::new(
141                1,
142                "Does ?source actually have the alleged ?bias?",
143                Challenge::PremiseTruth("bias".into()),
144            ),
145            CriticalQuestion::new(
146                2,
147                "Does ?bias actually affect ?source's assertion of ?claim?",
148                Challenge::RuleValidity,
149            ),
150            CriticalQuestion::new(
151                3,
152                "Even if ?source is biased, might ?claim still be true?",
153                Challenge::AlternativeCause,
154            ),
155        ],
156        metadata: SchemeMetadata {
157            citation: "Walton 2008 p.340".into(),
158            domain_tags: vec!["source".into(), "attack".into()],
159            presumptive: true,
160            strength: SchemeStrength::Weak,
161        },
162    }
163}
164
165/// Ethotic Argument — positive (Walton 2008 p.146).
166pub fn ethotic_argument() -> SchemeSpec {
167    SchemeSpec {
168        id: SchemeId(SOURCE_ID_OFFSET + 3),
169        name: "Ethotic Argument".into(),
170        category: SchemeCategory::SourceBased,
171        premises: vec![
172            PremiseSlot::new(
173                "person",
174                "The person whose character is cited",
175                SlotRole::Agent,
176            ),
177            PremiseSlot::new(
178                "good_character",
179                "The positive character trait",
180                SlotRole::Property,
181            ),
182            PremiseSlot::new(
183                "claim",
184                "The claim bolstered by good character",
185                SlotRole::Proposition,
186            ),
187        ],
188        conclusion: ConclusionTemplate::positive(
189            "?claim is more plausible because ?person has ?good_character",
190            "?claim",
191        ),
192        critical_questions: vec![
193            CriticalQuestion::new(
194                1,
195                "Does ?person actually have ?good_character?",
196                Challenge::PremiseTruth("good_character".into()),
197            ),
198            CriticalQuestion::new(
199                2,
200                "Does ?good_character make ?claim more plausible?",
201                Challenge::RuleValidity,
202            ),
203        ],
204        metadata: SchemeMetadata {
205            citation: "Walton 2008 p.146".into(),
206            domain_tags: vec!["source".into(), "support".into()],
207            presumptive: true,
208            strength: SchemeStrength::Weak,
209        },
210    }
211}
212
213#[cfg(test)]
214mod tests {
215    use super::*;
216
217    #[test]
218    fn all_returns_four_source_schemes() {
219        assert_eq!(all().len(), 4);
220    }
221
222    #[test]
223    fn ad_hominem_has_negated_conclusion() {
224        assert!(
225            ad_hominem().conclusion.is_negated,
226            "ad hominem must conclude ¬claim"
227        );
228    }
229
230    #[test]
231    fn ad_hominem_circumstantial_has_negated_conclusion() {
232        assert!(ad_hominem_circumstantial().conclusion.is_negated);
233    }
234
235    #[test]
236    fn bias_has_negated_conclusion() {
237        assert!(argument_from_bias().conclusion.is_negated);
238    }
239
240    #[test]
241    fn ethotic_has_positive_conclusion() {
242        assert!(!ethotic_argument().conclusion.is_negated);
243    }
244
245    #[test]
246    fn source_ids_are_in_offset_range() {
247        for s in all() {
248            assert!(s.id.0 >= SOURCE_ID_OFFSET);
249            assert!(s.id.0 < SOURCE_ID_OFFSET + 100);
250        }
251    }
252}