Хранение фактов для логических вопросов


Я пишу программу сырой искусственного интеллекта. Я рад возможности моей программы спиливать новое слово в способах, которые позволят логику, чтобы быть сделано о них. Прежде чем я начну расширить логические способности программы я переписал его в то, что я понимаю функциональное программирование. Я хочу прочную основу, прежде чем я двигаться вперед. Любая критика или понимание будет высоко оценен потому, что я верю в хорошее Программирование. Я переписал это в точку, что я с косыми глазами, но в данный момент он работает.

Каждое слово хранится в глобальном Словарь Список как слово. некоторые слова используются как глаголы или слова отношения храниться в слова в ДОЦ массивов. Слова-это предметы, которые помещаются в ДОЦ массивы вложенных в слово массивов. В (УНК) слова просто заполнителей до фактической слово помещается в массив.

; This program is used on an SBCL REPL 
 ; this program recieves three word phrases via the LEARN function 
 ; and stores them in symbols aranged in nested assoc arrays 
 ; so that logical questions can be asked using the function ASK.
 ; The LEARN function can take lists as arguments to proces many As Bs or Cs.
 ; the A word is the subject. The B word is the verb or relationship and the C is the object.
 ; For every ABC phrase the recipical phrase is also recorded. 
 ; If the b word does not yet have a recipical a user prompt is given.
 ; Synonyms are also disambiguated to one tearm to allow abreviated input and to eliminate words meaning the same thing.



(setf *vocab* '()) ; all words live here

(defun with-branch (word)  (cons word (cons (list '(unk) (cons '(unk) nil))nil)))

(setf sym '())
(defun learn (a b c)  ;user friendly ersion of ABCphrase to input phrases 
    (ABCphrase a b c "none"))


(defun ABCphrase (a b c origin) ;computer uses to input three word phrases or lists or A B and C words to build many phrases at once
    (cond
        ((listp a) 
            (loop for w in a do  
            (ABCphrase-b w b c origin))) ;origin is to keep track of what function called ABCphrase in ordert to prevent infite loops
        ((not (listp a)) 
            (ABCphrase-b a b c origin))))


(defun ABCphrase-b (a b c origin)  
        (cond 
            ((listp b) ;proceses the list if b is a list
                (loop for y in b do 
                    (ABCphrase-c a y c origin)))
            ((not (listp b)) 
                (ABCphrase-c a b c origin)))) 


(defun ABCphrase-c ( a b c origin)
    (cond
        ((listp c) ;proceses the list if  c is list
            (loop for z in c do 
                (add-and-place-ABCphrase-words a b z origin)))  
        ((not (listp c)) 
            (add-and-place-ABCphrase-words a b c origin)))) ;all words are eventualy processed throuf add-and-place-ABCphrase-words 

(defun add-and-place-ABCphrase-words (a b c origin) 
    (add-to-vocab-if-not a)(add-to-vocab-if-not b)
    (add-to-vocab-if-not c)
    (let ((a-resolved (word-or-synonym a b "a" ))
        (b-resolved (word-or-synonym b b "b" ))
        (c-resolved (word-or-synonym c b "c" )))
        (add-as-b-if-not a-resolved b-resolved c-resolved origin)
        (cond 
            ((equal b-resolved 'has-synonym) ;if b is has-synonym then don't resolve the synonym 
                (add-as-c-if-not a-resolved b-resolved c )) 
            ((not(equal b-resolved 'has-synonym))
                (add-as-c-if-not a-resolved b-resolved c-resolved )))))

(defun add-to-vocab-if-not (word) 
    (cond  
        ((not(member word *vocab*))  ;if already exists
            (push word *vocab*) ;add a as a a
            (setf (symbol-value word) sym))))   

(defun add-as-b-if-not (a b c origin) ;ads b to assoc array inside a (unless it is already there)
    (cond  
        ((not (assoc b (symbol-value a))); if not allready in lista 
            (cond
                ((equal (symbol-value a) sym)
                    (setf (symbol-value a) (cons (with-branch b) nil)) )
                ((not(equal (symbol-value a) sym))
                (push (with-branch b) (symbol-value a))))))     
    (cond
        ((not(equal origin "recipical")) ;this condition prevents an infint loop of flip flopping recipicals
            (process-recipical a b c)))) 
    ;                                                                           b                       recipical
(defun process-recipical (a b c)  ; create the backward phrase          frog is-colored green      green is-color-of frog
    (cond
        ((equal b 'is-recipical-of) ;this condition was necessary due to an error 
            (ABCphrase c 'is-recipical-of a "recipical")
            (return-from process-recipical b)
        ((not(assoc 'is-recipical-of (symbol-value b))) ; if b does not have repical then prompt user for recipical
            (format t "Please type recipical of: ") 
            (princ b) 
            (finish-output)
            (let ((rec-word (get-word a b c)))  
                (ABCphrase c rec-word a "recipical") ;creates the recipical phrase 
                (ABCphrase b 'is-recipical-of rec-word "recipical")  ;create prase stating recipical
                (ABCphrase rec-word 'is-recipical-of b "recipical"))) ;create recipical phrase stating recipical
        ((assoc 'is-recipical-of (symbol-value b)) ;if b has recipical
            (ABCphrase c (first(first(first(cdr (assoc 'is-recipical-of (symbol-value b)))))) a "recipical"))) ))

(defun get-word (a b c) 
    (let ((word (read-from-string (read-line))))  
        (add-to-vocab-if-not word)
        (return-from get-word  word)))
(defun add-as-c-if-not (a b c) 
    (cond
        ((not (assoc c (car (cdr(assoc b (symbol-value a)))))); if not in list b
            (push (with-branch c) (second(assoc b (symbol-value a)))))))    
(defun word-or-synonym (word b place)  
    (cond
        ((equal place "b")
            (return-from word-or-synonym (resolve-word word)))
        ((equal place "a")
            (cond
                ((equal b 'is-synonym)
                    (return-from word-or-synonym word))
                ((not(equal b 'is-synonym))
                    (return-from word-or-synonym (resolve-word word)))))
        ((equal place "c")
                (cond
                    ((equal b 'has-synonym)
                        (return-from word-or-synonym word))
                    ((not(equal b 'has-synonym))
                        (return-from word-or-synonym (resolve-word word)))))))
(defun resolve-word (word)
    (cond
        ((assoc 'is-synonym (symbol-value word)) 
            (return-from resolve-word (first(first(first(cdr (assoc 'is-synonym (symbol-value word)))))))))
    (return-from resolve-word word))

(defun ask (a b c)
    (add-to-vocab-if-not a)
    (add-to-vocab-if-not b)
    (add-to-vocab-if-not c)
    (let ((a-resolved (word-or-synonym a b "a" ))
        (b-resolved (word-or-synonym b b "b" ))
        (c-resolved (word-or-synonym c b "c" )))
        (assoc c-resolved (cadr(assoc b-resolved (symbol-value a-resolved))))))




(learn 'is-recipical-of 'is-recipical-of 'is-recipical-of)
(learn 'is-synonym 'is-recipical-of 'has-synonym) 
(learn 'syn 'is-synonym 'is-synonym)
(learn 'rec 'syn 'is-recipical-of ) 

(learn 'teaches 'rec 'is-taught-by)
(learn 'is-located-in 'rec 'is-location-of)
(learn 'auburn 'is-location-of '(upstairs downstairs industrial-arts-building))
(learn 'loc-of 'syn 'is-location-of)
(learn 'loc-in 'syn 'is-located-in)
(learn 'upstairs 'loc-of '(CNT-room ISS-room APM-room testing-room fish-bowl TPP-room ISTEM))


Комментарии
1 ответ

Читабельность

Трудно выразить, как это важно - мы пишем программы для чтения людьми, и только порой с помощью машин. Языки программирования были разработаны людьми и для людей, не для машин. И ваша ответственность-это не только писать код, который работает (почему-то), но самое главное - код, который является наиболее понятным и простым, чтобы прочитать описание ваших намерений для других читателей (и для себя в будущем).

Именования

Это не хорошая идея, чтобы использовать такие имена, как a, b, c и т. д. Это ничего не сказать. И вы должны были описать в комментариях свои смыслы. Называйте их как они есть, т. е:


а слово-предмет. Слово является глаголом или отношения и является объектом.

Почему бы не назвать их subject-word, verb-word и object-word?

Также имена функций, как ABCphrase, ABCphrase-b, ABCphrase-c не очень описательные. Позже вы используете некоторые длинные, описательные имена функций, почему не здесь?

Форматирование

Пожалуйста, сделайте некоторое пространство между определениями функций.
Не:

(defun get-word (a b c) 
(let ((word (read-from-string (read-line))))
(add-to-vocab-if-not word)
(return-from get-word word)))
(defun add-as-c-if-not (a b c)
(cond
((not (assoc c (car (cdr(assoc b (symbol-value a)))))); if not in list b
(push (with-branch c) (second(assoc b (symbol-value a)))))))
(defun word-or-synonym (word b place)

Сделать:

(defun get-word (a b c) 
(let ((word (read-from-string (read-line))))
(add-to-vocab-if-not word)
(return-from get-word word)))

(defun add-as-c-if-not (a b c)
(cond
((not (assoc c (car (cdr(assoc b (symbol-value a)))))); if not in list b
(push (with-branch c) (second(assoc b (symbol-value a)))))))

(defun word-or-synonym (word b place)

Не ставить дополнительные пробелы в списках.
Не:

(defun ABCphrase-c ( a b c origin)

Сделать:

(defun ABCphrase-c (a b c origin)

Используйте как минимум один пробел (белый символ) между элементами списка.
Не:

((not(member 

Сделать:

((not (member

Отступ ваш код правильно. Неправильные отступы в общий Лисп является, например, размещение точек и запятых в неположенных местах на естественном языке. Если вам трудно сосредоточиться, вы все еще можете попытаться выяснить, что Вы читаете, но это приводит к ошибкам и болезненно.
Если вы используете IDE, созданные с учетом требований сюсюкать в виду (т. е. в Emacs), то отступ ваш код правильно, а также каждый раз, когда вы видите код не выравнивая правильно - это явный признак что-то не так с выражением.
Не:

(let ((a-resolved (word-or-synonym a b "a" ))
(b-resolved (word-or-synonym b b "b" ))
(c-resolved (word-or-synonym c b "c" )))
(add-as-b-if-not a-resolved b-resolved c-resolved origin)

Сделать:

(let ((a-resolved (word-or-synonym a b "a" ))
(b-resolved (word-or-synonym b b "b" ))
(c-resolved (word-or-synonym c b "c" )))
(add-as-b-if-not a-resolved b-resolved c-resolved origin)

Описание

У вас много комментариев, и это хорошо. Однако в общий Лисп вы можете включить их в свой код, и относятся к ним в программный способ.

В глобальной функции и определение переменной можно добавить строку с описанием. Позже вы можете сделать эти описания с помощью describe. Так, например, если вы измените learn функции:

(defun learn (a b c)
"user friendly ersion of ABCphrase to input phrases."
(ABCphrase a b c "none"))

позднее вы можете попросить описание на ОТВ:

(describe #'learn)

Же идет глобальная переменная/определения параметров.

Снизу Вверх

При первом определении функции верхней части, а позже перейти к определению функции нижнего уровня, заставить читателя пропустить сверху какой-то случайной детали. Если я читаю learn функция, это тело не скажет мне. Он ссылается на некоторые другие функции, которые я еще не читал. Было бы легче читать, если вы разместите проще функции сверху. Поэтому прежде чем определить learnсначала определите функции, на которые ссылается, поэтому ABCphrase. И так ABCphrase ссылки ABCphrase-bопределите его первым. И так далее...

Техник

глобальные переменные

Вы можете не чтения то, чего не существует! Это ошибка. Использовать defparameter или defvar вместо. И всегда *mark* глобальные переменные правильно.
Не:

(setf *vocab* '()) ; all words live here

(setf sym '())

Сделать:

(defvar *vocab* '()
"all words live here.")

(defvar *sym* '())

вернуться

В общий Лисп вы не должны использовать return-from в моде, похожими на return является обязательным. В общем функция возвращает результат сюсюкать вычисления последнего выражения. Как правило большого пальца - если вы собираетесь писать return-from, остановитесь и подумайте, вы перемудрили что-то.
Не:

(defun get-word (a b c) 
(let ((word (read-from-string (read-line))))
(add-to-vocab-if-not word)
(return-from get-word word)))

Сделать:

(defun get-word (a b c) 
(let ((word (read-from-string (read-line))))
(add-to-vocab-if-not word)
word)))

Также если add-to-vocab-if-not возвращает wordвам не нужна последняя строка вообще.
А не:

(defun resolve-word (word)
(cond
((assoc 'is-synonym (symbol-value word))
(return-from resolve-word (first(first(first(cdr (assoc 'is-synonym (symbol-value word)))))))))
(return-from resolve-word word))

Сделать:

(defun resolve-word (word)
(cond
((assoc 'is-synonym (symbol-value word))
(first(first(first(cdr (assoc 'is-synonym (symbol-value word)))))))
(t word)))

первая хорошая, машина еще лучше

В начале, first выглядит и читается гораздо лучше car. Но вы можете сеть car и cdr красиво. Так что используйте (caar вместо (first (first и т. д.:

(defun resolve-word (word)
(cond
((assoc 'is-synonym (symbol-value word))
(caaadr (assoc 'is-synonym (symbol-value word))))
(t word)))

если Конд

cond допустим, тяжелые. Во многих случаях код читается лучше, если вы используете if (если вам нужны оба действия, ибо истинные и ложные). А еще лучше, когда вы можете использовать when (когда вам не нужно ложных действий) :)

(defun resolve-word (word)
(if (assoc 'is-synonym (symbol-value word))
(caaadr (assoc 'is-synonym (symbol-value word)))
word))

формат

Вы смешиваете format и princпочему? Я могу понять, что вам не нравится format и предпочитаю princ и т. д. Но будьте последовательны.

равенство

equal это лишь один из многих равенства проверяет. В коде было бы лучше использовать eq или string= во многих местах.

функциональное программирование

петли

loop макрос для итерационного программирования, а не для функционала. В функциональном программировании вы используете recurence. "Маленькая интриганка" - это отличный, практичный читал на эту тему.

глобальные переменные

В сущности, каждый раз, когда вы вызываете функцию с теми же параметрами, то она должна возвращать одинаковый результат. Однако в вашей функции вы используете очень часто глобальные переменные, поэтому поведение функции изменения во времени. Это не функционально.

есть...

...гораздо больше проблем с вашим кодом. Но для начала я надеюсь, что мои предложения окажутся полезными. Удачи вам с вашим приложением!

2
ответ дан 19 февраля 2018 в 09:02 Источник Поделиться