特别库
只有一个“特别的”知识库,名叫 special。
特别知识库里装的是各种辅助性知识,以有趣的形式,确定陈述是否真实。
特别库里的知识项是 Python 函数,在程序运行中做些“特别”的事情。
这些“特别”的函数是:
- 函数 claim_goal
- 函数 check_command
- 函数 command
- 函数 general_command
函数 Claim_goal
函数 claim_goal 没有参数。
special.claim_goal()
它的行为方式,像是 Prolog 的 cut 操作。
一般有多个规则,用于尝试证明目标(结论)是否成立。规则应用的顺序,按其在 .krb 文件中的排列,逐一尝试。一个规则失败,就接着试下一个。规则全部失败,则目标失败。
示例
假设我要把数字 N 解释成“N 只狗”,就用到以下规则:
one_dog use n_dogs(1, '1 dog') n_dogs use n_dogs($n, $phrase) when $phrase = "%d dogs" % $n
程序的逻辑有问题。当 n 等于 1 时,两个规则都要用到,但第二个规则不能正确适用。这时,函数 special.claim_goal() 可以解决这个问题:
one_dog use n_dogs(1, '1 dog') when special.claim_goal() n_dogs use n_dogs($n, $phrase) when $phrase = "%d dogs" % $n
在 n 等于 1 时,special.claim_goal() 阻止适用第二个规则。
说明
规则 when 子句里调用函数 special.claim_goal() 时,其余的规则不再参与证明原目标。于是,如果 special.claim_goal() 引起回溯,目标立即失败,不再试用别的规则。
这种结束的方式,就像 if-then-else 结构中的“else”的作用。只有当规则 when 子句中的前提条件真实正确时,才能在其后使用 special.claim_goal()
你不必在其后适用的规则中,添加额外的前提条件,去确保它们没有发生。
如果上例中没有函数 special.claim_goal(),你只好这样写:
one_dog use n_dogs(1, '1 dog') n_dogs use n_dogs($n, $phrase) when check $n != 1 $phrase = "%d dogs" % $n
这个简单的例子,很容易在第二个规则中,加入命令 check。不过,一般地说,检查以前出现的条件是很困难的,尤其如果涉及到多个规则,并且它们有各自的条件。
运行命令
其余三个函数,在你的 Pyke 程序运行时,以命令运行处理其他程序。这三个函数执行后,有不同的输出结果。
这三个函数,都使用 Python 标准库函数 subprocess.Popen。
这三个函数,都有以下三个参数,传递给 subprocess.Popen:
- 必须的参数 $command。
- 它是个元组,告诉程序按照参数的值运行,例如 (ls, '-l')。
- 可选的参数 $cwd。
- 指定程序当前运行的硬盘目录。
- 如果未设值,或设为 None,则当前工作目录保持不变。
- 可选的参数 $stdin。
- 是个字符串,指明程序的标准输入。
- 如果程序的输入有多行,$stdin 必须包括嵌入的新行,如:“line 1/nline 2/n”。
- 如果未设值,或设为 None,则该程序没有标准输入。
- 是个字符串,指明程序的标准输入。
如果发生回溯,这些函数全部失败。
函数 Check_command
special.check_command($command [, $cwd [, $stdin]])
如果 $command 程序运行返回 0,它适用成功;返回其他值,失败。程序向 stdout 和 stderr 的输出,无意义。
>>> from pyke import knowledge_engine >>> engine = knowledge_engine.engine() >>> engine.prove_1_goal('special.check_command((true))') ({}, None) >>> engine.prove_1_goal('special.check_command((false))') Traceback (most recent call last): ... CanNotProve: Can not prove special.check_command((false))
函数 Command
special.command($stdout, $command [, $cwd [, $stdin]])
它输出到 stdout。$command 程序向 stderr 的输出,无意义。
$stdout 是包含多行内容的元组,行尾的换行符都删除了。
如果程序返回值不是 0,则引发意外 subprocess.CalledProcessError。
>>> from __future__ import with_statement >>> from pyke import pattern, contexts >>> def run_command(entity, command, cwd=None, stdin=None): ... with engine.prove_goal( ... 'special.%s($output, $command, $cwd, $stdin)' % entity, ... command=command, ... cwd=cwd, ... stdin=stdin) / ... as gen: ... for vars, no_plan in gen: ... print vars['output'] >>> 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) {}', ' ', '', '', '', '', '==> standard input <==', 'stdin: line 1', 'stdin: line 2', 'stdin: line 3') >>> run_command('command', ('false',)) Traceback (most recent call last): ... CalledProcessError: Command 'false' returned non-zero exit status 1
special.general_command($output, $command [, $cwd [, $stdin]])
$command 程序给你全部输出的最一般的形式。
$output 是有三个成员的元组:(exit_status, stdout, stderr)。stdout 和 stderr 都是有换行符的字符串。
>>> 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")