【问题标题】:Clips rules - conditional firings of rulesClips 规则 - 有条件地触发规则
【发布时间】:2020-07-27 11:00:13
【问题描述】:

我正在尝试将规则用于基于农业的系统

例如,

基于位置 --> 列出作物 --> 基于所选作物 --> 选择种子

这是一个正向链接问题

我只能静态定义规则。意思是,为每个可能的场景定义规则

有没有办法编码,比如说如果我选择一个位置,我会得到所有作物的列表,当用户选择作物时,我会得到种子列表

如何确保规则是根据前一条规则的输出触发的?

【问题讨论】:

    标签: rules rule-engine clips


    【解决方案1】:

    您可以采取的一种方法是将问题表示为事实,然后编写处理这些事实的一般规则。首先定义一些 deftemplates 来表示问题,根据用户的响应从一个问题分支到另一个问题,以及用户的响应。

    (deftemplate question
       (slot name)
       (slot text)
       (slot display-answers (allowed-values yes no))
       (slot last-question (default none)))
    
    (deftemplate branch
       (slot question)
       (slot answer)
       (slot next-question)
       (multislot next-answers))
    
    (deftemplate response
       (slot question)
       (slot answer))
    

    接下来,定义你的问题以及它们之间的分支:

    (deffacts questions
       (question (name location)
                 (text "Country")
                 (display-answers no)
                 (last-question none))
       (question (name crop-type)
                 (text "Crop Type")
                 (display-answers yes)
                 (last-question location))
       (question (name seed)
                 (text "Seed")
                 (display-answers yes)
                 (last-question crop-type)))
    
    (deffacts locations
       (branch (question location)
               (answer "United States")
               (next-question crop-type)
               (next-answers food fiber))
       (branch (question location)
               (answer "India")
               (next-question crop-type)
               (next-answers food fiber))
       (branch (question location)
               (answer "China")
               (next-question crop-type)
               (next-answers food fiber))
       (branch (question location)
               (answer "Brazil")
               (next-question crop-type)
               (next-answers food fiber))
       (branch (question location)
               (answer "Pakistan")
               (next-question crop-type)
               (next-answers fiber)))
    
    (deffacts crop-types
       (branch (question crop-type)
               (answer fiber)
               (next-question seed)
               (next-answers cotton hemp flax))
       (branch (question crop-type)
               (answer food)
               (next-question seed)
               (next-answers corn wheat rice)))
    

    定义一些用于处理用户响应的实用程序 deffunctions。这些将允许程序忽略用户响应中字母大小写的差异。

    (deffunction lenient-eq (?v1 ?v2)
       (if (eq ?v1 ?v2)
          then
          (return TRUE))
       (if (eq (lowcase (str-cat ?v1)) (lowcase (str-cat ?v2)))
          then
          (return TRUE))
       (return FALSE))   
          
    (deffunction lenient-member$ (?value $?allowed-values)
       (loop-for-count (?i (length$ ?allowed-values))
          (bind ?v (nth$ ?i ?allowed-values))
          (if (lenient-eq ?value ?v)
             then
             (return ?i)))
       (return FALSE)) 
     
    (deffunction ask-question (?question $?allowed-values)
       (printout t ?question)
       (bind ?answer (lowcase (readline)))
       (while (not (lenient-member$ ?answer ?allowed-values)) do
          (printout t ?question)
          (bind ?answer (lowcase (readline))))
       ?answer)
    

    添加一些规则来处理提问时有效答案列表不显示的情况(因为可能很多)。

    ;;; Ask question without valid answers displayed or checked
    
    (defrule ask-question-without-answers
    
       ;; There is a question that should be 
       ;; displayed without valid answers.
    
       (question (name ?question)
                 (text ?text)
                 (display-answers no)
                 (last-question ?last-question))
    
       ;; There is no prior question or
       ;; the prior question has a response.
    
       (or (test (eq ?last-question none))
           (response (question ?last-question)))
    
       ;; There is no response to the question.
       
       (not (response (question ?question)))
    
       =>
       
       ;; Ask the question
       
       (printout t ?text ": ")
       
       ;; Assert a response with the question and answer. 
       
       (assert (response (question ?question)
                         (answer (lowcase (readline))))))
    
    ;;; Check for valid response to a question
    
    (defrule bad-answer-to-question
    
       ;; There is a question that should be 
       ;; displayed without valid answers.
    
       (question (name ?question)
                 (display-answers no))
                 
       ;; There is a response to the question.
            
       ?r <- (response (question ?question)
                       (answer ?answer))
       
       ;; The response to the question does
       ;; not branch to another question.
                       
       (not (branch (question ?question) 
                    (answer ?a&:(lenient-eq ?a ?answer))))
       =>
       
       ;; Print the list of valid answers for the question.
       
       (printout t "Valid answers are:" crlf)
       (do-for-all-facts ((?b branch))
                         (eq ?b:question ?question)
          (printout t "   " ?b:answer crlf))
          
       ;; Retract the response so that the
       ;; question will be asked again.
       
       (retract ?r))
    

    最后,添加一条规则来处理这样的情况,即提出问题并显示有效答案列表并立即由 ask-question deffunction 检查。

    ;;; Ask questions with valid answers displayed and checked
    
    (defrule ask-question-with-answers
    
       ;; There is a question that should be 
       ;; displayed including valid answers.
       
       (question (name ?question)
                 (text ?text)
                 (display-answers yes)
                 (last-question ?last-question))
       
       ;; The preceding question has been answered.
       
       (response (question ?last-question)
                 (answer ?last-answer))
                 
       ;; There is a branch from the preceding question
       ;; and its answer to this question and the allowed
       ;; values for the answer.
                  
       (branch (answer ?a&:(lenient-eq ?a ?last-answer)) 
               (next-question ?question)
               (next-answers $?next-answers))
       =>  
       
       ;; Construct the question text including the possible answers.
        
       (bind ?text (str-cat ?text " [" (implode$ ?next-answers) "]: "))
    
       ;; Ask the question.
       
       (bind ?answer (ask-question ?text ?next-answers))
    
       ;; Assert a response fact with the question and answer.
       
       (assert (response (question ?question) (answer ?answer))))
    

    这个程序运行时的输出:

             CLIPS (6.31 6/12/19)
    CLIPS> (load "seeds.clp")
    %%%$$$!!!***
    TRUE
    CLIPS> (reset)
    CLIPS> (run)
    Country: Sweden
    Valid answers are:
       United States
       India
       China
       Brazil
       Pakistan
    Country: China
    Crop Type [food fiber]: food
    Seed [corn wheat rice]: wheat
    CLIPS> 
    

    要让第一个问题显示有效答案,请重新定义问题 deffacts 以包含一个已经回答的初始问题:

    (deffacts questions
       (question (name location)
                 (text "Country")
                 (display-answers yes)
                 (last-question start-program))
       (question (name crop-type)
                 (text "Crop Type")
                 (display-answers yes)
                 (last-question location))
       (question (name seed)
                 (text "Seed")
                 (display-answers yes)
                 (last-question crop-type))
       (response (question start-program)
                 (answer yes))
       (branch (question start-program)
               (answer yes)
               (next-question location)
               (next-answers "United States" "India" "China" "Brazil" "Pakistan")))
    

    然后输出将如下所示:

    CLIPS> (run)
    Country ["United States" "India" "China" "Brazil" "Pakistan"]: Sweden
    Country ["United States" "India" "China" "Brazil" "Pakistan"]: China
    Crop Type [food fiber]: food
    Seed [corn wheat rice]: wheat
    CLIPS>
    

    【讨论】:

    • 太棒了!!谢谢加里..我只有一个问题..剪辑是基于前向链接的,上述解决方案如何满足前向链接要求?
    • 在反向链接系统中,您将从选择种子的目标开始,然后向后移动以确定您在进行选择时需要提出的问题。在这种情况下,您从要问的初始问题开始,然后在回答问题时沿着每条有效路径进行。
    • 谢谢加里。对延迟回复表示歉意。最后一个问题,我应该在 Clips 中为特定用例编写所有可能的场景吗?
    • 我不太确定我是否理解您的意思,因为关于您是否必须处理每种情况,这似乎是您的程序要求的一部分。如果您有一个事实表明所需的最终响应(例如种子),您可以编写一个低显着性规则,如果未找到最终响应则触发。由于问题以事实表示,您还可以编写一些元规则来分析它们以确定是否有任何问题无法解决。
    猜你喜欢
    • 1970-01-01
    • 2017-04-05
    • 1970-01-01
    • 2015-01-04
    • 1970-01-01
    • 1970-01-01
    • 2020-09-16
    • 2021-02-26
    • 1970-01-01
    相关资源
    最近更新 更多