Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionLast revisionBoth sides next revision | ||
tutorials:intermediate:json_prolog [2019/04/24 11:01] – [prolog-simple] gkazhoya | tutorials:intermediate:json_prolog [2022/01/17 13:00] – [Prerequisites] gkazhoya | ||
---|---|---|---|
Line 9: | Line 9: | ||
This tutorial requires CRAM, roslisp_repl and ROS to have already been installed. Go through the previous tutorials and the installation page if you don't have CRAM installed yet. | This tutorial requires CRAM, roslisp_repl and ROS to have already been installed. Go through the previous tutorials and the installation page if you don't have CRAM installed yet. | ||
Make sure you have **Java 8** and **Gradle 5.1** already installed. Otherwise you won't be able to build KnowRob. Other versions could work, but have not been tested yet, so use them at your own risk! | Make sure you have **Java 8** and **Gradle 5.1** already installed. Otherwise you won't be able to build KnowRob. Other versions could work, but have not been tested yet, so use them at your own risk! | ||
- | |||
=== Installation === | === Installation === | ||
Line 28: | Line 27: | ||
=== Launch === | === Launch === | ||
- | In addition to a **roscore** and the **roslisp_repl** you need to launch **json_prolog** in a Terminal with the following command: | + | In addition to a **roscore** and the **roslisp_repl** you need to launch **json_prolog** in a Terminal with the following command: |
+ | <code bash> | ||
+ | $ roslaunch rosprolog rosprolog | ||
+ | </ | ||
+ | or if you're using an older version of KnowRob, then the following command: | ||
<code bash> | <code bash> | ||
$ roslaunch json_prolog json_prolog.launch | $ roslaunch json_prolog json_prolog.launch | ||
Line 66: | Line 69: | ||
X being the variable we asked Prolog to fill with a value. Whenever Prolog returns a value for a variable, the variable name gets prefixed with a question mark. " | X being the variable we asked Prolog to fill with a value. Whenever Prolog returns a value for a variable, the variable name gets prefixed with a question mark. " | ||
In a [[json_prolog# | In a [[json_prolog# | ||
+ | |||
+ | Why do we get ''? | ||
+ | What does the second bracket do? | ||
+ | Let's add another variable to the query -- the variable ''? | ||
+ | <code lisp> | ||
+ | CL-USER> (json-prolog: | ||
+ | </ | ||
+ | This binds ''? | ||
+ | The result of the query is | ||
+ | <code lisp> | ||
+ | (((?X . 1) (?Y . 1))) | ||
+ | </ | ||
+ | Therefore, the second bracket makes a list of bindings for each variable in the query: | ||
+ | <code lisp> | ||
+ | ((?X . 1) (?Y . 1)) | ||
+ | </ | ||
+ | is a list of bindings for variable ''? | ||
+ | |||
+ | The last outer bracket is explained next. | ||
==== prolog-simple ==== | ==== prolog-simple ==== | ||
Line 77: | Line 99: | ||
</ | </ | ||
| | ||
- | The result is basically still the same, but it looks a little bit more complex on the first glance. What we get is a list which contains two elements. The first one is a list in a list with two elements which we already know from the previous call with '' | + | The result is basically still the same, but it looks a little bit more complex on the first glance. What we get is a list which contains two elements. The first one is a list in a list with two elements which we already know from the previous call with '' |
- | {1005F52FAB}> | + | {1005F52FAB}> |
==== lazy lists ==== | ==== lazy lists ==== | ||
The results we obtain from the queries are stored in lazy lists, meaning the information is loaded on demand, resulting in us seeing only one solution of the query. If we want to see all the results, we can expand the list and force LISP to show all of them to us, for example, by using: | The results we obtain from the queries are stored in lazy lists, meaning the information is loaded on demand, resulting in us seeing only one solution of the query. If we want to see all the results, we can expand the list and force LISP to show all of them to us, for example, by using: | ||
<code lisp> | <code lisp> | ||
- | CL-USER> (setq *our-list* (json-prolog: | + | |
+ | | ||
(((?X . 1)) | (((?X . 1)) | ||
. # | . # | ||
Line 95: | Line 117: | ||
We save our list in a variable for convenience purposes. This allows us also to expand the so stored list, and we can see all the possible values Prolog found for the variable ''? | We save our list in a variable for convenience purposes. This allows us also to expand the so stored list, and we can see all the possible values Prolog found for the variable ''? | ||
- | If we do the same with '' | + | Now we see why we need the outer bracket: the result of the query is a (lazy) list of all possible bindings for the query variables. Let us add another variable to the query again: |
<code lisp> | <code lisp> | ||
- | | + | CL-USER> (cut:force-ll (json-prolog: |
- | (((?X . 1))) | + | (((?X . 1) (?Y . 1)) ((?X . 2) (?Y . 2)) ((?X . 3) (?Y . 3))) |
- | CL-USER> | + | |
- | | + | |
</ | </ | ||
+ | We get a list of all possible bindings of the query variables, where the bindings is itself a list with one element for each variable. | ||
+ | |||
+ | If we evaluate our original '' | ||
+ | <code lisp> | ||
+ | CL-USER> (cut: | ||
+ | (((?X . 1)) ((?X . 2)) ((?X . 3))) | ||
+ | CL-USER> (cut: | ||
+ | (((?X . 1))) | ||
+ | </ | ||
+ | |||
+ | In the first case, meaning '' | ||
- | In the first case, meaning | + | One peculiarity of Prolog is that it can return an infinite number of bindings for a variable. |
+ | In that case, using '' | ||
+ | This is why lazy lists are useful when working with Prolog | ||
| | ||
==== Accessing data from Prolog ==== | ==== Accessing data from Prolog ==== | ||
Now that we have a lazy list with interesting information, | Now that we have a lazy list with interesting information, | ||
| | ||
- | We can use '' | + | We can use '' |
<code lisp> | <code lisp> | ||
- | | + | CL-USER> (cut:lazy-car (json-prolog: |
- | | + | ((?X . 1)) |
- | | + | </ |
- | </ | + | Same goes for '' |
+ | <code lisp> | ||
+ | CL-USER> | ||
+ | (((?X . 2)) | ||
+ | . # | ||
+ | :GENERATOR #< | ||
+ | | ||
+ | </ | ||
- | This gives us the lazy list. Then we can use '' | + | When we have one element of the lazy list, we can use '' |
<code lisp> | <code lisp> | ||
- | | + | CL-USER> (cut: |
- | | + | 1 |
</ | </ | ||
- | Gives us the result '' | + | Gives us the result '' |
That way, one can extract the necessary information, | That way, one can extract the necessary information, | ||
Line 134: | Line 175: | ||
<code lisp> | <code lisp> | ||
- | |||
CL-USER> (json-prolog: | CL-USER> (json-prolog: | ||
- | (NIL | + | (NIL) |
- | . # | + | |
- | : | + | |
- | {1006444B3B}> | + | |
- | | + | |
</ | </ | ||
+ | |||
+ | In JSON Prolog '' | ||
| | ||
- | This allows us to use the **knowrob_common** package, which allows us to access many utility functions and also the most commonly used queries of KnowRob. | + | This allows us to use the '' |
With this imported package we could now do the following: | With this imported package we could now do the following: | ||
<code lisp> | <code lisp> | ||
- | + | | |
- | | + | (((?RESULT |
- | (((|?Result| | + | |
. # | . # | ||
:GENERATOR #< | :GENERATOR #< | ||
Line 156: | Line 193: | ||
</ | </ | ||
- | This query converts the first elements upper case letters into lower case, and stores the obtained result in the '' | + | This query converts the first elements upper case letters into lower case, and stores the obtained result in the '' |
- | An overview of the currently available packages and their queries can be found [[http:// | + | An overview of the currently available packages and their queries can be found [[http:// |
<code bash> | <code bash> | ||
| | ||
Line 167: | Line 204: | ||
| | ||
<code lisp> | <code lisp> | ||
- | |||
Prolog query failed: PrologException: | Prolog query failed: PrologException: | ||
[Condition of type SIMPLE-ERROR] | [Condition of type SIMPLE-ERROR] | ||
- | | ||
</ | </ | ||
| | ||
- | and if you check your terminal, in which the **json_prolog** node is running, there will be a huge java print as well, basically explaining the same thing. | + | and if you check your terminal, in which the '' |
| | ||
- | | + | |
- | ==== Some more information about Prolog in LISP ==== | + | ==== Case-sensitive variable names ==== |
+ | |||
+ | In the former query we got a weird result from Prolog which looked like this: | ||
+ | <code lisp> | ||
+ | |'' | ||
+ | </ | ||
+ | What do the pipes stand for in this case? | ||
+ | |||
+ | Lisp is case-insensitive, | ||
+ | |||
+ | <code lisp> | ||
+ | CL-USER> (eq 'hello ' | ||
+ | T | ||
+ | CL-USER> (eq 'hello ' | ||
+ | T | ||
+ | </ | ||
+ | |||
+ | Prolog, on the other hand, is case-sensitive. | ||
+ | And in some cases, one would like to have a case-sensitive variable in Lisp as well. | ||
+ | This is where the pipes come into play: | ||
+ | <code lisp> | ||
+ | CL-USER> (intern " | ||
+ | HELLO | ||
+ | :INTERNAL | ||
+ | CL-USER> (intern " | ||
+ | |Hello| | ||
+ | NIL | ||
+ | </ | ||
+ | The function '' | ||
+ | If the string is all capital, we get a normal usual symbol, in the other case we get the pipes. | ||
+ | |||
+ | The same is with Prolog, if your variable or any other symbol is not all caps, you will get a symbol in Lisp which has pipes around it: | ||
+ | |||
+ | <code lisp> | ||
+ | CL-USER> (json-prolog: | ||
+ | (((?X . 1))) | ||
+ | CL-USER> (json-prolog: | ||
+ | (((?MYVAR . 1))) | ||
+ | CL-USER> (json-prolog: | ||
+ | (((?MY_VAR . 1))) | ||
+ | CL-USER> (json-prolog: | ||
+ | (((|? | ||
+ | </ | ||
+ | |||
+ | In that case, to get the value of the variable you should also use pipes: | ||
+ | |||
+ | <code lisp> | ||
+ | CL-USER> (cut: | ||
+ | (car (json-prolog: | ||
+ | 1 | ||
+ | </ | ||
+ | |||
+ | Please note that in Prolog, all variables have to start with a capital letter and cannot contain dashes: | ||
+ | <code lisp> | ||
+ | CL-USER> (json-prolog: | ||
+ | NIL | ||
+ | CL-USER> (json-prolog: | ||
+ | NIL | ||
+ | </ | ||
+ | ==== (NIL) vs NIL ==== | ||
| | ||
If we want to check, if a certain number is member of the list, we must declare the variable accordingly. e.g. | If we want to check, if a certain number is member of the list, we must declare the variable accordingly. e.g. |