Conditional Inference Engine in TypeScript
This challenge asks you to build a flexible conditional inference engine in TypeScript. Such an engine is useful for rule-based systems, expert systems, and any application requiring dynamic decision-making based on a set of conditions and actions. You'll be designing a system that can evaluate conditions and trigger corresponding actions, handling complex logical combinations.
Problem Description
You need to implement a ConditionalInferenceEngine class in TypeScript. This engine will take a set of rules as input, where each rule consists of conditions and an action. The engine should then be able to evaluate these rules against a given context (an object containing data) and execute the action of the first rule whose conditions are met.
Key Requirements:
- Rule Definition: A rule should be represented as an object with
conditions(an array of functions that return boolean values based on the context) andaction(a function that takes the context as input and performs an action). - Condition Evaluation: The engine must evaluate the conditions of each rule in order. A condition is considered met if the function it represents returns
truewhen called with the context. - Logical AND: All conditions within a single rule must be met for the rule to be considered satisfied.
- First Match: The engine should stop evaluating rules after the first rule whose conditions are met is found and its action is executed.
- No Match: If no rule's conditions are met, the engine should return
false. - Context: The context is a plain JavaScript object. Conditions can access properties of this object.
Expected Behavior:
The ConditionalInferenceEngine class should have a constructor that accepts an array of rules. It should also have a method called execute that takes a context object as input and returns either the result of the executed action (if a rule matches) or false (if no rule matches).
Edge Cases to Consider:
- Empty rule set: The engine should return
falseif the rule set is empty. - Empty conditions array: A rule with an empty conditions array should always be considered to match.
- Conditions that throw errors: The engine should handle conditions that might throw errors gracefully (e.g., by catching the error and treating the condition as not met).
- Actions that throw errors: The engine should handle actions that might throw errors gracefully (e.g., by catching the error and logging it, but not crashing the engine).
Examples
Example 1:
Input:
rules = [
{
conditions: [
(context) => context.age >= 18,
(context) => context.isStudent === false
],
action: (context) => { console.log("Eligible for adult discount"); return "adult_discount"; }
},
{
conditions: [(context) => context.isStudent === true],
action: (context) => { console.log("Eligible for student discount"); return "student_discount"; }
}
]
context = { age: 20, isStudent: false };
Output:
"adult_discount"
Explanation: The first rule's conditions (age >= 18 and isStudent === false) are met, so its action is executed, and "adult_discount" is returned.
Example 2:
Input:
rules = [
{
conditions: [
(context) => context.score > 90
],
action: (context) => { console.log("Excellent!"); return "excellent"; }
},
{
conditions: [(context) => context.score >= 70],
action: (context) => { console.log("Good"); return "good"; }
}
]
context = { score: 80 };
Output:
"good"
Explanation: The first rule's condition (score > 90) is not met. The second rule's condition (score >= 70) *is* met, so its action is executed, and "good" is returned.
Example 3: (Edge Case - Empty Rules)
Input:
rules = [];
context = { name: "Alice" };
Output:
false
Explanation: The rule set is empty, so no rules can be matched, and `false` is returned.
Constraints
- The
conditionsarray in each rule can contain a maximum of 5 functions. - The context object can contain any number of properties of any type.
- The execution of an action should not take longer than 100ms. (This is a guideline, not a strict requirement, but consider performance when designing your solution).
- All conditions and actions must be pure functions (no side effects other than logging to the console).
Notes
- Consider using TypeScript's type system to define the structure of rules and contexts for better type safety.
- Think about how to handle errors gracefully within the condition evaluation and action execution processes.
- The order of rules matters. The first matching rule's action will be executed.
- You can use
try...catchblocks to handle potential errors in conditions and actions. - Focus on creating a clean, readable, and maintainable solution. Good error handling and clear code structure are important.