From www.rebol.org, by Allen Kamp:
(Back to the main NIALL page, then)
REBOL [
Title: "RNILL - REBOL Non Intelligent Language Learner"
Author: "Allen Kamp"
Email: allenk@powerup.com.au
Date: 7-Aug-1999
File: %rnill.r
Version: 1.0.0
Purpose: {
RNILL a REBOL implementation of a non intelligent language learner
inspired by NIALL (Non Intelligent Amos Language Learner by
Mathew Peck 1990).
}
Comment: {
RNILL is a fun chatter-bot:
Just type what ever comes into your head, RNILL learns sentence structure
from what you type. RNILL starts off knowing nothing (unlike Melissa
or Eliza), so at first he may just repeat your sentences.
Type in jokes, stories, obscure comments, whatever you like, or use the
read command to read in texts.
But be warned sometimes RNILL's replies will be spookily accurate.
}
Category: [games]
]
Comment {RNILL - REBOL Non Intelligent Language Learner
I spent hours chatting to the original NIALL on my Amiga. The concept
of a language learner fascinated me, always wanted a version for my PC,
so I've made my own. RNILL is my implementation based on my memory and
understanding of the concepts in NIALL. (It is nearly 9 years since I've
seen NIALL or its AMOS source). Please don't write me and tell me it is
different, I didn't set out to write a clone.
How RNILL works...
How RNILL Learns:
RNILL Analyses each sentence in a 2 pass process
Step 1 - Build Dictionary - Add new words or increment count for known
words
Step 2 - Build Relationships - Add new relations or increment count for
known relations
How RNILL Replies:
Begining with the start of sentence marker (always word 1 "-|"). RNILL
chooses the next word from the relations list. (words that RNILL has learnt
can follow the current word) The choice is weighted by how common that link
has been. This recurses until an end of sentence is chosen ("-1")
RNILL Tips.
Multiple sentences may be typed in at a time. Don't worry about case.
Punctuation - !.? are recognised for end of sentence punctuation. They
are only needed to separate multiple sentences. Commas are stripped from
sentences.
RNILL stores its dictionary as RNILLData.txt, this will be created if it
doesn't exist. You can fix typos and spelling errors in this file, however
do not delete or add an entry, as the dictionary is a relational database.
RNILL Commands
QUIT - RNILL saves on exit when you use the RNILL command Quit.
? - Shows current Dictionary Stats.
READ - To read a text file for RNILL to learn from
To save duplication RNILL generally saves words as lowercase.
When generating replies capitalises the first letter of a sentence.
Preformated-Words
Contains a list words that have a fixed case.
eg. "I" "I'd" in the English Language.
RNILL will not make these lowercase.
}
;---Constants and Switches
begin-sentence: "|- "
data-file: %RNILLData.txt
;---Turn on or of welcome text and getting user name.
welcome-on: true
Preformatted-Words: make hash! [
"I" "I'll" "I'd" "I'm" "RNILL" "REBOL" "PC" "UNIX" "Amiga" "HTML"
"Australia" "UK" "USA" "Japan"
]
;---End Constants and Switches
;---Init Tables
Dictionary: make hash! 1000
Stats: make block! 1000
Relations: make block! 1000
;---Load Tables
if exists? %RNILLData.txt [
last-chat: modified? data-file
Data: load %RNILLData.txt
Dictionary: to-hash copy Data/1
Stats: copy Data/2
Relations: copy Data/3
unset 'data
]
welcome-user: func [
/local sentence
][
;---Welcoming sentences, also fed into RNILL learning process.
user: ask {Hello my name RNILL, what is your name? }
append preformatted-words user ; retain name formatting.
user-prompt: rejoin [user " > "]
sentence: rejoin ["Hello " user]
print ["RNILL >" sentence]
;---may as well learn this sentence too
RNILL-learns sentence
either not exists? data-file [
sentence: {Please tell me something about yourself}
][
sentence: {It is good to talk to someone again}
]
print ["RNILL >" sentence]
;---may as well learn this sentence too
RNILL-learns sentence ]
input-loop: func [] [
while [true] [
sentence: ask user-prompt
switch/default sentence [
"Quit" [
;Save RNILL Data on exit
print [newline "Goodbye" User
{it has been nice chatting with you.}]
RNILL-info/stats
data: []
insert/only tail data to-block dictionary
insert/only tail data stats
insert/only tail data relations
save data-file data
break ;quit out of loop/end program
]
"?" [RNILL-info]
"Read" [
file: to-file ask {> Read Filename ? }
try [either exists? file [sentence: read file]
[Print "Read File Error..." sentence: ""]]
if (sentence <> "") [
Prin {Reading File...}
RNILL-Learns sentence
Print "Done"
]
]
][
;---Default evaluate and build dictionary
RNILL-Learns sentence
prin "RNILL > "
RNILL-replies 1
prin newline
]
]
exit
]
;---Process Sentences
RNILL-Learns: func [
paragraph [string!] {Sentence string to learn from}
/local sentence words
][
;---Prepare Block of Ordered Words
;---Paragraph -> Block of Sentences -> Block of words
foreach sentence parse/all paragraph {.?!}[
trim/with sentence "," ;remove comma
trim sentence ; remove beginning or trailing spaces
;---Add Sentence Begin Marker
sentence: join begin-sentence [sentence]
words: parse sentence none
;--- Assess Word block
build-dictionary words
build-relationships words
]
exit
]
build-dictionary: func [
sentence-blk
/local word-id counter found
] [
foreach word sentence-blk [
either found? found: find Dictionary word [
;---Update Known word, increment # times used
word-id: index? found
counter: pick Stats word-id
poke Stats word-id (counter + 1)
][
;---Add New Word
append Dictionary format-word word
append Stats 1 ; Word Usage Count
;---Insert empty series, to be
;---filled later by build-relations
insert/only tail Relations make block! []
]
]
exit
]
build-relationships: func [sentence][
repeat i count: length? sentence [
preword: pick sentence i
postword: pick sentence (i + 1)
;---Use index as ID
preword-ID: index? found: find dictionary preword
;---find relations entry block for preword
relation-blk: pick relations preword-ID
either postword <> none [
;---Get PostWord-ID
postword-ID: index? found: find dictionary postword
][
postword-ID: -1 ; End of Sentence ID
]
either found? relation-stat: select relation-blk postword-ID [
;---Increment Relation count
count: relation-stat/1
change relation-stat (count + 1)
][
;---Add New Relation Entry
append relation-blk Postword-ID ; relation entry id
;---Set Relation Count to 1
insert/only tail relation-blk make block! [1]
]
]
Exit
]
format-word: func [string [any-string!]] [
/local str: to-string ""
either found? str: find preformatted-words string [
return (string: copy first str)
] [
return (lowercase copy string)
]
exit
]
;---End Process Sentences
;--RNILL Reply Functions
RNILL-replies: func[
{Creates and prints RNILL reply sentence}
word-Id [integer!]
/local word-used-count roll relation-blk loop-max
weighting chosen-word i word-str relation-count
][
word-used-count: pick stats word-id
roll: random word-used-count
relation-blk: pick relations word-id
weighting: 0
chosen-word: -1 ; End of Sentence as default.
loop-max: length? relation-blk
for i 1 loop-max 2 [
relation-count: first pick relation-blk (i + 1)
weighting: weighting + relation-count
if (weighting >= roll) [
chosen-word: pick relation-blk i
break
]
]
if chosen-word <> -1 [
word-str: pick dictionary chosen-word
;---Capitalise first-letter-first-word.
if word-id = 1 [word-str: uppercase/part copy word-str 1]
prin join word-str [" "]
RNILL-Replies chosen-word ;recurse
]
exit
]
;---End RNILL Repy Functions
;--RNILL Stat Functions
count-words: func[
{Returns the total number of words in RNILL's dictionary}
/local count
][
;---Remove start sentence maker from count
count: (length? stats) - 1
if count < 0 [count: 0]
return count
]
count-sentences: func[
{Returns the total number of sentences RNILL has analysed}
/local count
][
count: pick stats 1
if count = none [count: 0]
return count
]
count-relationships: func[
{Returns the total number of word relationships in RNILL's dictionary}
/local count stat
][
count: 0
foreach stat stats [count: count + stat]
return count
]
RNILL-info: func [{Shows RNILL Info}
/stats {Shows only Stats part of the info}
][
;---Header
if not stats [
;prin "^(page)"
print ""
print {+------------------------------------------------------+}
print {| RNILL - The REBOL Non-Intelligent Language Learner |}
print {+------------------------------------------------------+}
]
;---Stats
print ""
print {======================Statistics=======================+}
print [{ Sentences |} count-sentences]
print [{ Words |} count-words]
print [{ Relationships |} count-relationships]
print {+------------------------------------------------------+}
print ""
;---Footer
if not stats [
print {+------------------------------------------------------+}
print {| To Exit: enter Quit | To View Stats: enter ? |}
print {| | |}
print {| To learn a text file: enter Read (and follow prompt) |}
print {+------------------------------------------------------+}
]
]
;--End RNILL stat Functions
;---Begin---
random/seed now
prin "^(page)"
RNILL-info
either welcome-on [welcome-user] [user-prompt: {User > } user: ""]
input-loop