Future Directions

New Features

Evaluation

In a matching context the result of an evaluation expression is interpreted as a guard whose truthyness determines whether or not the matching process should continue.

company ~ {"employees": [*_, {"age": <<@ > 65>>}, *_]}

The ‘@’ character in the example above refers to the current focus (the value of “age”).

In a filling context the result of the evaluation expression is the value inserted into the structure

//
// Do a bit of math
//

{"numerator": x, "denominator": y} --> {"quotient": <<x/y>>}
>> jertl.transform('{"numerator": x, "denominator": y} --> {"quotient": <<x/y>>}', x=1.0, y=2.0).result
{'quotient': 0.5}

Inline Filters

//
// Find employees eligible for graduation
//

company ~ {"employees": [*_, employee<<{"age": <<@ > 65>>}>>, *_]}

The @ character in the example above refers to the current focus.

Aggregation

//
// Get list of employee names
//

{"employees": employees} --> <<map({"name": name} --> name, employees)>>

This will appear in the same release having Evaluation. The functions map, filter, and reduce, will be in the set of predefined functions.

Iteration

The jertl mini-language is ‘functional-first’ so iteration will not be available.

Disjunction

Eventually.

Ecosystem Improvements

  • Semantic analysis to identify potential issues beforehand.

  • Informative Exceptions (location in pattern where exception happened).

  • Editor support for .jertl source files.

  • Structure matching optimization.

  • “Eat our own dogfood” in AST generator and OpCode emitter.

  • Match debugger

Taking it to the Next Level

Compilation

>>> cat find_highest_paid_male_employee.jertl

module highest_paid_male
//
// Create a Python module with functions is_male, salary, and highest_paid_male_employee
//
matcher is_male:
    {"gender": "male"}

transform salary:
    {"salary": salary} --> salary

collate highest_paid_male_employee [company]:       \\ Input to this function is a list containing a `company` data structure
    company         ~  {"employees": employees}
    highest_salary :=  <<max(map(age, filter(is_male, employees)))>>
    employees       ~  [*_, employee<<{"salary": highest_salary}>>, *_]

>>> jertl find_highest_paid_male_employee.jertl -o generated_sources

Rule Sets and Chaining (Forward Inference)

Where we consider multiple inference rules simultaneously and can require there to be sequences of inferences in order for the rule to apply.

//
// Your classic ancestors problem
//
ruleset ancestors
    rule find_ancestors [person]:
        person ~ {"parents": [mother, father]}
      -->
        O=O=O ancestors [person, mother]    // `O=O=O`: chain to ancestors ruleset
        O=O=O ancestors [person, father]

    rule note_ancestry_and_look_deeper [person, ancestor]:
        person ~ {"name": person_name},
        ancestor ~ {"name": ancestor_name, "parents": [ancestors_mother, ancestors_father]}
      -->
        ancestry := {"person": person_name, "ancestor": ancestor_name}
        O=O=O ancestors [person, ancestors_mother]
        O=O=O ancestors [person, ancestors_father]

    rule no_more_birth_records [person, parent]:
        person ~ {"name": person_name},
        ancestor ~ {"name": ancestor_name, "parents": null}
      -->
        ancestry := {"person": person_name, "ancestor": ancestor_name}

Working Memory

Where working memory is a key/value store.

rule supervises [supervisor, employee]
    supervisor ~ {"name": supervisor_name, "underlings": [\*_, employee, \*_]}
    employee@  ~ {"name": underling_name}      // <-- `employee` is bound to string which points to data in working memory.
                                               //     The data is retrieved and the matching process continued.
    -->
    supervises := [supervisor_name, underling_name]

Moonshots

Data Stores

Where data is external to Python.

rule is_supervisor [supervisor, employee]
    supervisor@sql_employee_table ~ {"name": supervisor_name, "underlings": [\*_, employee, \*_]}
    employee@sql_employee_table   ~ {"name": underling_name}      // employee is key to data stored in a SQL table
    -->
    supervises := [supervisor_name, underling_name]

Mutation

Where we mutate a data structure using overlays. What is an overlay you ask? Good question! Overlays and how they work need to be formally defined.

rule record_change_of_supervisor [employee_id, previous_supervisor, new_supervisor]
  -->
    previous_supervisor :- {"underlings": [*_, employee_id, *_]}  // <-- remove portion of data structure matching overlay
    new_supervisor      :+ {"underlings": [*_, employee_id]}      // <-- add data described by overlay