[efe1d1]: doc / source / knowledge_bases / special.txt Maximize Restore History

Download this file

special.txt    269 lines (206 with data), 8.8 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
.. $Id$
..
.. Copyright Š 2007-2008 Bruce Frederiksen
..
.. Permission is hereby granted, free of charge, to any person obtaining a copy
.. of this software and associated documentation files (the "Software"), to deal
.. in the Software without restriction, including without limitation the rights
.. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
.. copies of the Software, and to permit persons to whom the Software is
.. furnished to do so, subject to the following conditions:
..
.. The above copyright notice and this permission notice shall be included in
.. all copies or substantial portions of the Software.
..
.. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
.. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
.. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
.. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
.. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
.. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
.. THE SOFTWARE.
restindex
crumb: Special
page-description:
Explanation of the ``special`` knowledge base.
/description
format: rest
encoding: utf8
output-encoding: utf8
include: yes
initialheaderlevel: 2
/restindex
uservalues
filedate: $Id$
/uservalues
=======
Special
=======
There is only one instance of this 'special' knowledge base, called
``special``.
The ``special`` knowledge base is a collection of miscellaneous helper
*knowledge entities* that determine whether a statement is true or not in
various interesting ways.
Thus, each entity in this `knowledge base`_ is a Python function that does
something "special" when run.
The ``special`` functions are:
- claim_goal_
- check_command_
- command_
- general_command_
Claim_goal
==========
The ``claim_goal`` function has no arguments::
special.claim_goal()
This acts like the Prolog_ `cut operator`_.
In general there are multiple rules_ that might be used to try to prove_ any
goal_. They are each tried in the order that they appear in the `.krb file`_.
If one rule fails, the next rule is tried. The goal itself doesn't fail
until all of the rules for it have failed.
Example
-------
Suppose I want to translate a number, N, into the phrase "N dogs". I could
use the following rules::
one_dog
use n_dogs(1, '1 dog')
n_dogs
use n_dogs($n, $phrase)
when
$phrase = "%d dogs" % $n
The problem here is that both rules might be used when ``n`` is 1, but the
second rule isn't appropriate in this case. ``Special.claim_goal()`` may
be used to fix this, as follows::
one_dog
use n_dogs(1, '1 dog')
when
special.claim_goal()
n_dogs
use n_dogs($n, $phrase)
when
$phrase = "%d dogs" % $n
The ``special.claim_goal()`` prevents the second rule from being used when
``n`` is 1.
Explanation
-----------
When a rule_ executes ``special.claim_goal()`` in its ``when``
clause, none of the rest of the rules will be tried for that goal_.
Thus, when ``special.claim_goal()`` is backtracked_ over, the goal fails
immediately without trying any more rules for it.
This ends up acting like an "else". You place it in the ``when`` clause
after the premises_ that show that this rule **must** be the correct one
to use. Then the subsequent rules will only be tried if these premises
fail, such that ``special.claim_goal()`` is never executed.
This means that you don't need to add extra premises in each subsequent rule
to make sure that these premises have **not** occurred.
Without the ``special.claim_goal()`` in the prior example, you would have to
write::
one_dog
use n_dogs(1, '1 dog')
n_dogs
use n_dogs($n, $phrase)
when
check $n != 1
$phrase = "%d dogs" % $n
This is a simple example where it is easy to add the check in the second
rule. But in general, it can be difficult to check for prior conditions,
especially when many rules are involved that each has its own condition.
Running Commands
================
The remaining three functions deal with running programs (commands) on the
host computer that is running your Pyke program. Their difference is in what
kind of output they provide from the command.
These functions all use the `subprocess.Popen`_ function from the standard
Python library.
Thus, each of these functions accept these three parameters that are passed
on to subprocess.Popen:
- The ``$command`` parameter (required).
- This is a tuple indicating the program to run along with its command
line arguments, such as ``(ls, '-l')``.
- The ``$cwd`` parameter (optional).
- This specifies the *current working directory* to run the command in.
- If omitted or ``None`` the current working directory is not changed.
- The ``$stdin`` parameter (optional).
- This is a string that is fed to the command as its stdin.
- If the command expects multiple lines of input, this string must
include embedded newlines (e.g., ``'line 1\nline 2\n'``).
- If omitted or ``None``, no stdin is provided to the command.
All of these functions fail on backtracking_.
Check_command
-------------
::
special.check_command($command [, $cwd [, $stdin]])
Succeeds if the command returns a zero exit status. Fails otherwise. Any
output from the command to stdout or stderr is unavailable.
>>> from pyke import knowledge_engine
>>> engine = knowledge_engine.engine()
>>> engine.prove_1('special', 'check_command', (('true',),), 0)
((), None)
>>> engine.prove_1('special', 'check_command', (('false',),), 0)
Traceback (most recent call last):
...
pyke.knowledge_engine.CanNotProve: Can not prove special.check_command((false))
Command
-------
::
special.command($stdout, $command [, $cwd [, $stdin]])
This just looks at the stdout of the command. Any output from the command
to stderr is unavailable.
The ``$stdout`` is a tuple of lines with the trailing newlines removed.
This raises `subprocess.CalledProcessError`_ if the command returns a non-zero
exit status.
>>> from __future__ import with_statement
>>> from pyke import pattern, contexts
>>> def run_command(entity, command, cwd=None, stdin=None):
... my_context = contexts.simple_context()
... output = contexts.variable('output')
... with engine.prove('special', entity, my_context,
... (output,
... pattern.pattern_literal(command),
... pattern.pattern_literal(cwd),
... pattern.pattern_literal(stdin))) \
... as gen:
... for no_plan in gen:
... print(output.as_data(my_context))
>>> run_command('command', ('echo', 'hi', 'mom'))
('hi mom',)
>>> run_command('command', ('ls',)) # doctest: +NORMALIZE_WHITESPACE
('fact_bases.txt', 'index.txt', 'links', 'question_bases.txt',
'rule_bases.txt', 'special.txt')
>>> run_command('command', ('ls', '-l', 'links')) # doctest: +ELLIPSIS
('-rw-r--r-- 1 ... links',)
>>> run_command('command', ('tail', '-n', '5', 'template.txt', '-'),
... '..', # cwd (doc/source)
... 'stdin: line 1\nstdin: line 2\nstdin: line 3\n')
... # doctest: +NORMALIZE_WHITESPACE
('==> template.txt <==',
' } catch(err) {}',
' </script>',
'</body>',
'</html>',
'',
'',
'==> standard input <==',
'stdin: line 1',
'stdin: line 2',
'stdin: line 3')
>>> run_command('command', ('false',))
Traceback (most recent call last):
...
subprocess.CalledProcessError: Command 'false' returned non-zero exit status 1
General_command
---------------
::
special.general_command($output, $command [, $cwd [, $stdin]])
This is the fully general form that gives you all output from the command.
The ``$output`` is a three tuple: (exit_status, stdout, stderr). Both stdout
and stderr are single strings (with embedded newlines).
>>> run_command('general_command', ('echo', 'hi', 'mom'))
(0, 'hi mom\n', '')
>>> run_command('general_command', ('cat', 'foobar'))
(1, '', 'cat: foobar: No such file or directory\n')
>>> run_command('general_command', ('tail', '-n', '5', '../../r2w.ini', 'foobar'))
... # doctest: +NORMALIZE_WHITESPACE
(1,
"==> ../../r2w.ini <==\ntarget_directory = 'html'\nmacros =
''\n\n[uservalues]\nversion = '0.2'\n",
"tail: cannot open `foobar' for reading: No such file or directory\n")