-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
622 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#Program Structure | ||
|
||
##Predicates and rules | ||
|
||
A Brachylog program is constituted of *predicates*, each predicate being constituted of *rules*. Each predicate corresponds to one line of code: | ||
|
||
predicate0 | ||
predicate1 | ||
predicate2 | ||
... | ||
|
||
Each predicate has a number, starting from 0, which is based on its order of apparition in the code (reading from left to right and top to bottom). The first predicate, written on the first line (so it has number 0), is called the *main predicate*, and it is the predicate you query to run your code. | ||
|
||
A new rule can be added to any predicate using the symbol `|`: | ||
|
||
rule0_pred0|rule1_pred0|rule2_pred0 | ||
rule0_pred1 | ||
... | ||
|
||
Brachylog is built on Prolog, and as such rules in Brachylog behave as you would expect in Prolog. That is, if you query say predicate i, it will attempt to satisfy rule 0 of this predicate, and if unsuccessful attempt to satisfy rule 1 (if it exists), etc., until a rule is satisfied or none can be satisfied. | ||
|
||
Each predicate has two arguments: the *Input* and the *Output*. The Input is represented by `?` in the code, and the Output by `.`. At the beginning of each rule, the Input is implicitely the current variable. At the end of each rule, the Output is implicitely here too. | ||
|
||
##Syntax and our first Brachylog program | ||
|
||
Brachylog, like Prolog, uses *unification* and *backtracking* as basic mechanisms. Once a Brachylog variable is unified with something, it cannot be changed, unless backtracking occurs. | ||
|
||
In a rule definition, things get processed from left to right and each built-in predicate will use the variable to its left as Input, and the variable to its right as Output. In Brachylog, logical conjunction (i.e. logical *and*) is *implicit* inside a rule definition. Unification is also implicit. To illustrate this, Let's examine this short Brachylog code containing only a main predicate, which unifies its Output with the reverse of its Input minus the first element: | ||
|
||
br | ||
|
||
As said before, the Input is implicitely available at the beginning of a rule. Thus, the built-in predicate `b - Behead ` will use the Input of the rule as its own input. There is no variable between `b` and `r - Reverse`, therefore an implicit one is used as output for `b`, and reused as input for `r`. The Output is implicitely the last variable of at the end of a rule, therefore `r` will use the Output of this rule as its own Output. | ||
|
||
Overall, this predicate will be satisfied if and only if an implicit variable can be unified with the Input minus its first element, and then the Output can be unified with the reverse of this implicit variable. This predicate will return `false`otherwise. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#Types and Variables | ||
|
||
##Variables | ||
|
||
Any uppercase latin letter is a variable identifier, initially not unified to anything. There are thus 26 available variable names. These variables and their possible values are not shared between rules. | ||
|
||
`?` and `.` are special variables which are the Input and the Output of the current rule they are in. | ||
|
||
Variables can be unified by using them as inputs or outputs to predicates or by direcly unifying them with other variables. For example, `IJ` will unify `I` with `J` (or fail if they cannot be unified). | ||
|
||
##Lists | ||
|
||
Lists are noted in between square brackets `[...]` and elements of a list are separated using `:`. One can also construct a list using `:`. For example, `:2:3.` will unify the Output with the list `[Input:2:3]`. However, `2:3` will not unify the Input with the list `[2:3]` ; it will instead unify the Input with 2 and then construct the list `[2:3]` (`[2:3]` would have unified the Input with `[2:3]`). | ||
|
||
`[]` denotes the empty list. | ||
|
||
##Strings | ||
|
||
Strings are opened and closed with double quotes `"..."`. `\` will escape double quotes. | ||
|
||
##Integers and Floats | ||
|
||
Integers and floats are written using the numbers 0 to 9 as expected. The decimal separator is `.`. A floating point number must have at least one digit before and after the decimal separator. | ||
|
||
Negative numbers are written using an underscore `_` preceeding the number. This underscore is called the *low minus* in Brachylog. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#Execution Control | ||
|
||
##`,` - Logical *and* | ||
|
||
Logical and is implicit in Brachylog. The comma is thus used mostly to *break implicit unification*. | ||
|
||
For instance, `42` unifies both the Input and the Output with 42, whereas `,42` will only unify the Output with 42. | ||
|
||
##`;` - Logical *or* | ||
|
||
As its name suggest, `;` is used to denote logical or. Unlike `|` (to create a new rule, which is also a disjunction), the Input is not implicitely available after it. In fact, `;` breaks implicit unification like `,`. | ||
|
||
##`( )` - Parentheses | ||
|
||
Parentheses are used to group logical assertions together. The variable preceeding the opening parenthesis is implicitly available after it. | ||
|
||
Parentheses are not used in arithmetic expressions. | ||
|
||
##`\` - Backtrack | ||
|
||
`\` is false, and will therefore trigger backtracking. | ||
|
||
##`!` - Cut | ||
|
||
Ignore all preceeding choice point, which will thus not get explored when backtracking is triggered. This is equivalent to [Prolog's cut (`!`)](http://www.swi-prolog.org/pldoc/doc_for?object=!/0). | ||
|
||
##`` ` `` - Soft cut | ||
|
||
Allows the construct ``<if>`<then>;<else>``. If `<if>` is true, then `<then>` is chosen and `<else>` is discarded, meaning you will at this point not reach `<else>` even when backtracking. You will however be able to backtrack on `<if>` and `<then>`. This is equivalent to [Prolog's soft cut (`*->`)](http://www.swi-prolog.org/pldoc/doc_for?object=(*-%3E)/2). | ||
|
||
##`'` - Not Provable | ||
|
||
True if the following assertion (a built-in predicate, or predicates contained in parentheses, or a predicate definition, or another variable which would unify with the current one) cannot be proven. This is equivalent to Prolog's `\+`. | ||
|
||
##`~` - Reverse Arguments | ||
|
||
The next predicate will be called with the variable to its left as Output and the variable to its right as Input. | ||
|
||
For example, `l` will unify the Output with the length of the Input, whereas `~l` will unify the Output with a list of N elements, if Input = N. |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
#Inline Predicates and Calling Predicates | ||
|
||
##Inline Predicates | ||
|
||
One can define and call a predicate directly inside another predicate using curvy brackets `{...}`. For example: | ||
|
||
predicate0{predicate1} | ||
predicate2 | ||
... | ||
|
||
As you can see, since the inline predicate appears before the predicate on the second line, it has a smaller number. | ||
|
||
Multiple rules can be written inside an inline predicate just like normal predicates. Inline predicates can contain other inline predicates. | ||
|
||
An inline predicate will be queried with the variable to the left of the opening `{` as Input and the variable to the right of the closing `}` as Output. | ||
|
||
An inline predicate can be declared inside a list (i.e. just after a colon `:`). In that case, it is defined and numbered as normal, but does not get queried. | ||
|
||
##Calling Predicates | ||
|
||
The main predicate is the one you query to run your program. To call other predicates, you must use the built-in predicate `& - Call predicate`, which takes as Input a list containing your arguments and the number of the predicate you want to call in the last position. If the last element cannot be used as a predicate number, then this will call the predicate you are currently in. | ||
|
||
The output of the predicate you called will be unified with the output of `&`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#Integers and Constraints | ||
|
||
By default, and unlike Prolog, all integer operations use the [Constraint Logic Programming on Finite Domains (CLPFD) library of SWI-Prolog](https://github.com/triska/clpfd). | ||
|
||
This allows for instance to write something like this (`$r` being square root): | ||
|
||
,25$r | ||
|
||
which makes it so that the Output is either `5` or `-5`, without assigning it a value yet. | ||
|
||
Variables with constraints that get in "contact" with floating point numbers (e.g. adding an integer to a float) will cause the constrained variable to get labeled before the operation. | ||
|
||
Floating point operations do not use CLPFD. | ||
|
||
You can force labelization of a variable or a list of variables using the built-in `=` - equals. | ||
|
||
##Infinite Domains | ||
|
||
Unlike the standard CLP(FD) library of SWI-Prolog, Brachylog's labeling predicate `=` works on infinite sets. | ||
|
||
For example: | ||
|
||
?- run_from_atom('<.=', 0, Z). | ||
Z = 1 ; | ||
Z = 2 ; | ||
Z = 3 ; | ||
Z = 4 ; | ||
Z = 5 ; | ||
... | ||
|
||
With the standard CLP(FD), you would get the following error: | ||
|
||
?- Z #> 0, indomain(Z). | ||
ERROR: Arguments are not sufficiently instantiated | ||
|
||
A variable with both `inf` as lower bound and `sup` as upper bound will get unified as such: | ||
|
||
?- run_from_atom('<~+.=',7,Z). % Output's absolute value is bigger than 7 | ||
Z = 8 ; | ||
Z = -8 ; | ||
Z = 9 ; | ||
Z = -9 ; | ||
Z = 10 ; | ||
Z = -10 ; | ||
Z = 11 ; | ||
Z = -11 ; | ||
Z = 12 ; | ||
... | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
#Standard Built-Ins | ||
|
||
Below are the standard built-in predicates of Brachylog. All of them have one Input and one Output, denoted respectively by `?` and `.` in each of the predicate's description. | ||
|
||
|Symbol|Name| Description| | ||
|:----:|:--------------:|:---------------------------------------------------------------------------------------- | ||
| `a` | Apply | Applies the last element of `?` (i.e. a predicate name) to each element of `?` but the last. If `?` contains only one element beside the predicate name, and it is a list, it will apply on each element of this list. `.` will be unified with the list of the outputs of the application of the predicate to each element. | ||
| `b` | Behead | <ul><li>On lists: unifies `.` with `?` minus its first element</li><li>On strings: unifies `.` with `?` minus the first character</li><li>On numbers: unifies `.` with `?` minus its first digit</li></ul> | ||
| `c` | Concatenate | Unifies `.` with the concatenation of all elements of `?`. All elements must be of the same type. Works on lists of strings/integers/lists. | ||
| `d` | Duplicates | Unifies `.` with `?` where only the first occurence of each element is kept. Works on lists, strings, numbers. | ||
| `e` | Enumerate | <ul><li>`?` is a string: unifies `.` with a character of `?`. Backtracking on this predicate will produce each character of `?` from left to right</li><li>`?` is an integer: unifies `.` with a digit of `?`. Backtracking on this predicate will produce each digit of `?` from left to right</li><li>`?` is a list: unifies `.` with an element of `?`. Backtracking on this predicate will produce each element of `?` from left to right</li></ul> | ||
| `f` | Findall | `? = [Arg1:...:ArgN:PredName]. `Unifies `.` with a list of all possible variable bindings which satisfy a predicate `P` with this binding as output. `?`. | ||
| `g` | Group | Unifies `.` with `[?]` | ||
| `h` | Head | <ul><li>On lists: unifies `.` with the first element of `?`</li><li>On strings: unifies `.` with the first character of `?`</li><li>On numbers: unifies `.` with the first digit of `?`</li></ul> | ||
| `i` | Iterate | `? = [Arg1:...:ArgN:I:Pred]`. Calls `Pred` with `[Arg1:...:ArgN]` as input. Then, calls `Pred` with the output of the previous call as input, etc. This is done `I` times, after which `.` is unified with the output of the last call of `Pred`. | ||
| `j` | Juxtapose | `? = [A:I]`. Unifies `.` with `A` concatenated `I` times to itself. | ||
| `k` | Knife | <ul><li>On lists: unifies `.` with `?` minus its last element</li><li>On strings: unifies `.` with `?` minus the last character</li><li>On numbers: unifies `.` with `?` minus its last digit</li></ul> | ||
| `l` | Length | Unifies `.` with the length of `?` (number of elements / number of characters / number of digits). | ||
| `m` | Member | `? = [A:I]`. Unify `.` with the `I`th element of `A`. | ||
| `n` | | | ||
| `o` | Order | Unifies `.` with `?` sorted in ascending order, according to the standard order of terms in Prolog. If the last element of `?` is a predicate name (either directly a built-in or using `{…}`), then the list is sorted in ascending order based on the output of that predicate for each element of `?` minus the predicate name. | ||
| `p` | Permute | Unifies `.` with a permutation of `?` (elements / characters / digits). Backtracking on this predicate will produce each possible permutation exactly once | ||
| `q` | | | ||
| `r` | Reverse | Unifies `.` with the reverse of `?` | ||
| `s` | Subset | Unifies `.` with a subset of `?` (elements / characters / digits). Only the subsets that have the same ordering as `?` are valid. Backtracking on this predicate will produce each one of those subsets exactly once | ||
| `t` | Tail | <ul><li>On lists: unifies `.` with the last element of `?`</li><li>On strings: unifies `.` with the last character of `?`</li><li>On numbers: unifies `.` with the last digit of `?`</li></ul> | ||
| `u` | | | ||
| `v` | Void | True if `?` is either `[]`, `""`, `0` or `0.0`. `.` is an anonymous variable which will unify with anything. | ||
| `w` | Write | Write `?` to `STDOUT`. If `?` has more than one element and the last one is a string, then this string is used to format the rest of the input (See [`format/2`](http://www.swi-prolog.org/pldoc/doc_for?object=format/2)) | ||
| `x` | Xterminate | `? = [X:Y]`. `.` is `X` with `Y` removed (e.g. `"test":"te"x` gives `"st"`). If `Y` is a list, removes all elements of `Y` from `X`. **Note: this is not implemented for numbers yet**. | ||
| `y` | Yield | <ul><li>On integers: unifies `.` with the list of all integers between `0` and `?`</li><li>`? = ["I":"J"]`, where I and J are any character. Unifies `.` with all 1-length strings of characters between `I` and `J` (based on character codes).</li><li>`? = [Arg1:...:ArgN:I:Pred]`. Unify `.` with the first `I` solutions of `Pred` given `[Arg1:...:ArgN]` as input.</li></ul> | ||
| `z` | Zip | `.` is a list of lists where the `I`th sublist contains the `I`th elements of each element of `?`. This will wrap around for elements of `?` which are shorter in length than the longest element of `?`. | ||
| `&` | Call Predicate | Calls the `I`th predicate with `[Arg1:...:ArgN]` as input, assuming that `? = [Arg1:...:ArgN:I]`. If the last element of `?` is not an integer, then the current predicate is recursively called. `.` Is unified with the output of that predicate call. | ||
| `+` | Plus | <ul><li>On one number: unifies `.` with `? + 1` (or adds a constraint if it's an integer)</li><li>On integers: applies the constraint `. = A + B + ...`, where `? = [A:B:...]`</li><li>When one float is involved: does normal summing without constraints. Labelizes integers if needed</li></ul> | ||
| `-` | Minus | <ul><li>On one number: unifies `.` with `? - 1` (or adds a constraint if it's an integer)</li><li>On integers: applies the constraint `. = A - B`, where `? = [A:B]`</li><li>When one float is involved: does normal subtraction without constraints. Labelizes integers if needed</li></ul> | ||
| `*` | Multiply | <ul><li>On one number: unifies `.` with `2×?` (or adds a constraint if it's an integer)</li><li>On integers: applies the constraint `. = A * B * ...`, where `? = [A:B:...]`</li><li>When one float is involved: does normal multiplication without constraints. Labelizes integers if needed</li></ul> | ||
| `/` | Divide | <ul><li>On one number: unifies `.` with the inverse of `?`</li><li>On integers: applies the constraint `. = A // B`, where `? = [A:B]`</li><li>When one float is involved: does normal division without constraints. Labelizes integers if needed</li></ul> | ||
| `^` | Power | <ul><li>On one number: unifies `.` with the square of `?` (or adds a constraint if it's an integer)</li><li>On integers: applies the constraint `. = A ^ B`, where `? = [A:B]`</li><li>When one float is involved: does normal powering without constraints. Labelizes integers if needed</li></ul> | ||
| `%` | Modulus | Unifies `.` with `A mod B` where `? = [A:B]`. Only works on integers. | ||
| `=` | Equal | Labelizes `?` or the elements of `?` if it's a list. Unifies `.` with `?`. | ||
| `<` | Less | True if `? < .`. For integers, it adds a constraint. When one is an integer an the other is a float, this will labelize the integer. | ||
| `>` | Greater | True if `? > .`. For integers, it adds a constraint. When one is an integer an the other is a float, this will labelize the integer. | ||
| `<=` | Less-equal | True if `? <= .`. For integers, it adds a constraint. When one is an integer an the other is a float, this will labelize the integer. | ||
| `>=` | Greater-equal | True if `? >= .`. For integers, it adds a constraint. When one is an integer an the other is a float, this will labelize the integer. | ||
|
||
|
Oops, something went wrong.