Karuta — subsystem

← All subsystems

Karuta

Logic programming on the BEAM

Facts · rules · questions · compiles to BEAM

karuta-lang.org ↗

A relational programming language for the BEAM, in the line of Prolog and miniKanren. State facts, write rules, ask questions. The compiler, written in OCaml, emits BEAM assembly, and a small runtime gives Erlang logic variables and backtracking.

append[[], [], []].
append[[], [H | T], [H | T]].
append[[H | T], [], [H | T]].
append[[H | Tail], [HS | TS], [H | Mid]] :-
    append[Tail, [HS | TS], Mid].

append[[1, 2], [3, 4], Out]?

Facts, rules, questions

A predicate is written with square brackets. A clause with :- is a rule, a clause without one is a fact, and a line ending in ? is a question, whose answer binds the variables it names. Conjunction is a comma, and the builtins live in the karuta module.

minus[InL, InR, Out] :-
    karuta:neg[InR, MinusInR],
    karuta:plus[InL, MinusInR, Out].

minus[4, -2, Out], karuta:plus[First, 2, Out]?

Quoted atoms make readable names for helper predicates:

reverse[In, Out] :- 'reverse loop'[In, Out, [], Out].

'reverse loop'[[], [], Out, Out].
'reverse loop'[[Head | Tail], [Last | Init], Acc, Out] :-
  'reverse loop'[Tail, Init, [Head | Acc], Out].

Relations that persist

Karuta's own facts live in the BEAM. Relations that should outlive a node are declared to Sakura, inside a module, and queried like any other predicate:

:- module[public] {
  :- sakura:persisted {
    relation[Name].
    attribute[Relation_name, Attr_name, Domain_name].
  }.
}.
:- import[db].

db:public:attribute['public:function_predicate', Attr, Domain]?

In the same runtime

A persisted relation is a kernel object like any other. It has a path in RNT’s tree, so the tuples a Karuta program asserts are the tuples pureSQL selects and Forth reads with OPEN-RELATION, and the other way around: a Karuta rule can range over the shipments pureSQL serves or the stack of a running Forth.

Predicates are relations too. Once the shared Generative protocol lands, a Karuta predicate with a bound mode is something pureSQL can call in a select list, and a pureSQL routine is something a Karuta rule can ask.

The road there, from Karuta’s side: AST nodes and directives for Sakura, runtime support for talking to the database, and folding several queries into a single predicate body.

Where to go next

The language has its own home at karuta-lang.org, with the story behind its name told in karuta cards. The source is at github.com/dont-rely-on-nulls/karuta.