Search code examples
javainformation-retrievaldata-handling

it it possible to make a function return true, false or a list of objects?


Introduction to the program

I'm working on a program which stores data like the following:

- Facts: A combination of a list of properties (or just one) and a true/false value(called the "truth" value). For example:

parent('John' , 'John jr') , true

where the property of John being a parent of John jr is true. The code I use for storing a fact:

public class Fact implements Serializable{
    private boolean truth;
    private ArrayList<Property> properties;

    public Fact(){
        truth = false;
        properties = new ArrayList<Property>();
    }

    //more constructors, getters, setters and other functions  which are not important for this question...

- Rules: Used to obtain information from facts. They work by having a fact (which I call the derivative fact) imply another fact (which I call the impliant fact):

parent('x' , 'y') => child('y', 'x')

This means that by applying the rule to the fact above we can determine that John jr is a child of John.

Properties of rules:

negativity:

Rules can be either "positive" (if the derivative is true, the impliant is true):

parent('x' , 'y') => child('y', 'x')

or "negative" (if the derivative is true, the impliant is false):

parent('x' , 'y') => not child('y', 'x')

reversitivity:

they can also be "reversive" (if the derivative is false, the impliant is true/false):

not parent('x' , 'y') => child('y', 'x')

or (if also negative):

not parent('x' , 'y') => not child('y', 'x')

or "non-reversive" (if the derivative is false, the impliant is unknown):

not parent('x' , 'y') => (unknown)

The code I use to store rules looks like this:

public class Rule implements Serializable{
    private Property derivative;
    private Property impliant;
    private boolean negative;
    private boolean reversive;

    public Rule(Property derivative, Property impliant) throws InvalidPropertyException{
        if(!this.validRuleProperty(derivative) || !this.validRuleProperty(impliant))
            throw new InvalidPropertyException("One or more properties are invalid");
        this.derivative = derivative;
        this.impliant = impliant;
        negative = false;
        reversive = false;
    }

    //again more constructors, getters, setters and other functions  which are not important for this question...

InformationSets

facts and rules are stored in InformationSets which bundle these facts and rules together so the user can "question" the information inside. This can be done in 2 different ways:

1.Fact Check: Check if a fact is true. This will, given a fact, will return either true or false based on the truth value of that fact. for example the user can ask:

parent('John' , 'John jr')?

and the program will return true while:

parent('John jr' , 'John jr')?

will return false.

The question mark indicates the user want to ask a 'fact check' question.

1.Impliant Check: This will, for a given fact(called the question-fact), return a list of facts for each rule which can be applied to the question-fact. For example:

parent('John' , 'John jr')=>

this will return:

child('John jr', 'John')

The arrow indicates the user want to ask a 'Impliant check' question.

Questions are coded like this:

public class Question {
    Fact questionFact;
    String operator;

    public Question(Fact questionFact, String operator) throws InvalidOperatorException{
        if(!validOperator(operator))
            throw new InvalidOperatorException("The operator is invalid");
        this.questionFact = questionFact;
        this.operator = operator;
    }

Inside the Operator field I store ? or => according to which kind of question the user want to ask.

The Problem

I'm currently at the point where I need to write the method that will ask questions to a given informationSet. So I would need a method that given a question and an informationset returns either true, false or a list of facts. As far as I know this is not possible in java.

I tried to make a separate method for each question which kinda works but this also causes a problem as I would like to be able to write something like:

informationSet.ask(question);

and have the ask() method deal with both types of question so I don't have to check which kind of question the user is asking on inside the user-interface code but rather have the back end of the program work it out.

What could be a good way to do this?


Solution

  • So, the most obvious solution would be to implement your custom response class.


    Another idea would be to consider using Either from Vavr which is a solution designed to hold either (pun intended!) values of type A or B exclusively.

    So, it could look like:

    Either<Boolean, List<Fact>> result = foo();
    

    Then, you can leverage FP Optional/Stream API-like for manipulating the result:

    If you want to access the left side:

    result.left()
      .map(...)
      .filter(...)
      // ...
    

    If you want to access the right side:

    result.right()
      .map(...)
      .filter(...)
      // ...