Knowledge and Reasoning Language (KaRL) is a specialized scripting language for referencing and mutating knowledge in a MADARA knowledge base. There are several benefits to using KaRL.
1.) It is fast and efficient, generally with very predictable execution times
2.) It can be extended with user functions implemented in the host language
3.) It can be used to quickly prototype agent logic
4.) It can be connected to other knowledge bases
5.) It can be used to monitor status of other program such as those built in GAMS (http://jredmondson.github.io/gams/)
Just like any language, a KaRL script is a collection of constants, variables, functions and operations.However, the intent of KaRL was to manipulate knowledge and also to wait on knowledge to change state. Because of this, KaRL has some unique properties.
In KaRL, local variables start with a period ("."). These variables will not be disseminated over a network transport. Global variables that need to be disseminated after they are modified start with any letter.
knowledge.evaluate (" // local variables start with period .my_x = 10; .my_y = 20; /** * global variables start with alphabet characters. * these will be sent over the network when modified **/ my_state = 'waiting' ");
KaRL supports arrays of integers and doubles in an intuitive way.
knowledge.evaluate (" // Setup a position array with latitude, longitude and an altitude set to 3 .latitude = 42.0; .longitude = 70.1; position = [.latitude, .longitude, 3]; // change array values position = get_latitude(); position = get_longitude(); ");
KaRL features many operators that will feel very familiar but that work differently than how the operators are used in other languages. The biggest ones that need some explaining are the semicolon (;) and comma (,). In KaRL, these operators separate expressions, such as setting a variable to a value (e.g., "x = 11; y = 12") but they also return a value. For semicolons, the return value is the maximum value of the left and right hand side. So, "x = 11; y = 12" returns 12 (the maximum of 11 and 12). Conversely, "x = 11, y = 12" returns 11 (the minimum of 11 and 12).
For a listing of most of the supported operators, what they mean and how they are used, see the following powerpoint: http://sourceforge.net/projects/madara/files/presentations/KaRL_Primer.pptx/download
One of the more interesting operators is the choose-right operator ";>", a semi-colon followed by a greater-than. Like a semi-colon operator, this operator evaluates both the left and right hand side. However, the choose-right operator always returns the result of the right-hand side evaluation. This is incredibly useful when creating initialization knowledge while using a wait call on a knowledge base.
Consider the following KaRL snippet that showcases the choose-right operator.
knowledge.wait (" // use the choose-right operator to indicate not to return latitude and longitude latitude = 42 ;> longitude = 70 ;> is_gps_in_the_us (latitude, longitude)");
The above wait statement above would initialize latitude and longitude to 42 and 70, respectively. It would then return the value of
is_gps_in_the_us, which would be a custom function created by a user and attached to a knowledge base with the
define_function call. Contrast that to the following code example.
knowledge.wait (" // use the max operator to return maximum of 42, 70 and return value of function latitude = 42 ; longitude = 70 ; is_gps_in_the_us (latitude, longitude)");
The above code would return the maximum of latitude, longitude, and the return value of
is_gps_in_the_us which would almost certainly be a zero or one (false or true), meaning that the resulting evaluation would always be 70 (the longitude initialization), since the semi-colon operator returns the maximum of the left and right evaluations.
KaRL includes many built-in functions for accessing operating system capabilities like timestamps, printing, accessing operating system environment variables, and other similar functions. System calls begin with a "#" and can take zero or more arguments.
To see all utility functions and documentation for arguments, you can call "#print_system_calls()". This listing is also kept in the source code repo at: https://sourceforge.net/p/madara/code/ci/master/tree/docs/system_calls.txt
KaRL was originally intended to be called explicitly via the evaluate and wait calls on a Knowledge Base. Evaluate is used to evaluate a knowledge expression and then immediately return. A wait also evaluates a knowledge expression but does not return until either a timeout occurs or the results of the evaluation is true (non-zero).
MADARA includes a specialized tool called the karl interpreter inside the bin directory. The karl interpreter is invoked from the command line to evaluate one or more logics, similar to how you might call perl or java or any other type of interpreter. However, the karl interpreter has command line options for network transports, iteration and various other features.
As with most tools in MADARA, help for the tool can be invoked with the "-h" or "--help" option. An example of this help file can be found here: https://sourceforge.net/p/madara/code/ci/master/tree/docs/karl_help.txt
The karl interpreter has many unique features that can help quickly debug other running applications. First, are the network options. If your distributed application is using multicast, you can provide -m with the multicast IP and port, and the karl interpreter will listen for updates on this IP:port, and it will also send updates you make with the karl interpreter to other agents in the network listening to that same IP:port.
The next important option is the wait option (-w). The wait option turns the karl interpreter into a wait. This is useful for listening to the network transport for updates in order to evaluate KaRL expressions in response to knowledge that changes over time.
The wait option is often paired with the frequency option (-y) to indicate how frequently the KaRL expressions should be evaluated. The frequency is specified in hertz (evaluations per second). And if the evaluation result is important to your tests, you can specify the -c option, which will exit the karl interpreter if the evaluation is non-zero. An additional wait can be used (-wy), specified in seconds, which delays the evaluations until a certain amount of time has passed. This is useful to wait for an initialization period before evaluating. Pairing what we've learned so far, the following creates a simple karl interpreter call that runs for 60s and evaluates once per second, checking to see if "mission.failure" has been set to non-zero.
karl -m "220.127.116.11:4150" -c -y 1 -w 60 "mission.failure"
The above listens for multicast messages on 18.104.22.168:4150 for up to 60s or until mission.failure is non-zero, and checks for mission.failure every 1 second. However, one important thing is missing. This will not print knowledge or tell you what has been updated.
The karl interpreter has many debug features related to printing knowledge. First, is -k, which prints knowledge at its final state. The second option is -ky, which prints knowledge after each evaluation. The final debug option worth mentioning in regards to printing is --debug. This option prints uses the aggregate knowledge filter to print all knowledge received over the transport, exactly when it is received.
To perform the same evaluation as earlier but waiting 5 seconds and then printing knowledge after every evaluation, we can call the following:
karl -m "22.214.171.124:4150" -c -y 1 -ky -wy 5 -w 60 "mission.failure"
Other projects that use MADARA have used KaRL to do things like waiting on knowledge to reach a certain state or to monitor state in running distributed applications.