特別庫
只有一個“特別的”知識庫,名叫 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")