1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
|
class Property {
constructor(type, dest) {
this.type = type
this.dest = dest
}
}
class Properties {
constructor(type, from) {
this.props = from ? from.props.slice() : []
//if (from) {console.log('INHERIT: '); for (let prop of this.props) { console.log(prop) }}
this.add('is', type)
}
toString() {
let str = ''
for (let prop of this.props) {
str += prop.type + ':' + prop.dest + ' '
}
return str
}
add(type, dest) {
this.props.push(new Property(type, dest))
}
has(type, dest) {
for (let p of this.props)
if ((p.type == type || isVar(type))
&& (p.dest == dest || isVar(dest)))
return true
return false
}
del(type, dest) {
for (let i = 0; i < this.props.length; ++ i) {
let p = this.props[i]
if (p.type == type && p.dest == dest) {
this.props.splice(i, 1)
return true
}
}
return false
}
hasIsVar() {
return this.has('is','variable')
}
}
class AbstractData {
constructor(from) {
this.props = new Properties('abstract', from && from.props)
}
}
class StringData extends String {
constructor(str, from) {
super(str)
this.props = new Properties('string', from && from.props)
this.props.del('is', 'array')
}
}
class ArrayData extends Array {
constructor(arr, from) {
super(...arr)
this.props = new Properties('array', from && from.props)
this.props.del('is', 'string')
}
}
// Abstractions?
const VAR_X = new StringData('X')
VAR_X.props.add('is','variable')
// recommend e.g. 'is','variable-rep' when code is designing them, so don't match everything
function isVar(x) {
return x.props && x.props.has('is','variable')
}
// MEMORY
// the archivist. Provides for needs of data. Memory is relevent whenever there is
// an informational need.
//
// When remembering steps, likely what is relevent is what is needed to reach the goal
// Here's a possible step memory.
//
// let ret = new StringData('labeled ' + items.length + ' text-string')
// ret.props.add('is','step-memory')
// ret.props.add('step',genproptextstring)
// ret.props.add('ram',ram)
// ret.props.add('count',items.length)
// for (let a of items)
// ret.props.add('item', a)
class ActiveMemory extends ArrayData {
// although Memory is eventually a module that provides for stored information needs
// this class is just a group of concepts, moved in and out as needed
constructor(items, from) {
super(items || [], from)
this.props.add('is','working-ram')
}
clone() {
return new ActiveMemory(this, this);
}
add(...items) {
//if (this.cloned) { this = this.slice(); this.cloned = false; }
for (let item of items)
this.push(item)
}
del(...items) {
//if (this.cloned) { this = this.slice(); this.cloned = false; }
for (let item of items) {
let index = this.indexOf(item)
this.splice(index, 1)
}
}
contains(...items) {
for (let item of items)
if (this.indexOf(item) === -1) return false
return true
}
containsWith(...props) {
let ret = []
outer: for (let a of this) {
for (let i = 0; i < props.length; i += 2)
if (! a.props.has(props[i], props[i+1]))
continue outer
return true
}
return false
}
getWith(...props) {
let ret = []
outer: for (let a of this) {
//console.log(a.props.props)
for (let i = 0; i < props.length; i += 2) {
//console.log(props[i] + ': ' + props[i+1] + '?')
if (! a.props.has(props[i], props[i+1]))
continue outer
}
ret.push(a)
}
if (ret.length > 0) return ret
return null
}
}
// note: for now we produce only data; state-changes are data-changes
class FunctionData {
constructor(name, // name of function
func, // function taking ordered needs
// ordered array of made objects is returned
needs, // array of 1-property-per-object this function requires
makes // array of 1-property-per-object this function produces
) {
this.name = name
this.props = new Properties('function')
this.props.add('name', name)
this.call = func
// If needed, make atomspace-like pattern structures for needs/makes.
// - represent multiple properties on 1 needed object
// - represent input objects present in output
this.needs = needs
this.makes = makes
}
}
// variables:
// - create a place to store a value
//createvar = new FunctionData(
// 'createvar',
// /*call*/(name) => {
// let ret = new StringData(name)
// ret.props.add('is','varspec')
// return ret
// },
// /*relevence*/,
//// when do you want to create a variable? when you need a variable and you have a name
// /*makes*/
//)
// - place a value in such a place
// - retrieve a value from such a place
// data-structures: (these are like promises of what to do and how to use something)
// - make a class definition (collection of variables)
// - initialize an object
// - set/retrieve properties (variables)
// flow:
// - trigger a different step than the next, conditionally
// procedures:
// - collect a set of behaviors together
// - trigger a collected set of behaviors and continue
// expressions:
// - evaluate arithmetic on variables and constants
line2words = new FunctionData(
'line2words',
(line) => { // call
let res = new ArrayData(line.split(' '), line)
res.props.add('is','words')
res.props.del('is','text-string')
return res
},
['is','text-string'], // needs
['is','word-array'] // makes
)
// makes text-string used by line2words. example of small relevence habit
genproptextstring = new FunctionData(
'genproptextstring',
/*call*/(text) => {
if (text.props.has('is','string')) {
if (!text.props.has('is','text-string')) {
text.props.add('is','text-string')
}
return text
}
return null
},
/*needs*/['is','text'],
/*makes*/['is','text-string']
)
respondhello = new FunctionData(
'respondhello',
(words) => { // call
console.log(words[0] + " world!")
let res = new StringData("said " + words[0])
res.props.add('is','output')
res.props.add('is','text')
return res
},
['is','hello-input'], // needs
['is','output'] // makes
)
genprophelloinput = new FunctionData(
'genprophelloinput',
/*call*/(input) => {
if (!input.props.has('is','words'))
return null
if (!input.props.has('is','hello-input')) {
let x = input[0].toLowerCase()
let c = x[x.length-1]
if (c == ',' || c == '!' || c == '.') x = x.slice(0,x.length-1)
if (x != 'hello' && x != 'hi') return null
input.props.add('is','hello-input')
}
return input
},
/*needs*/['is','input'],
/*makes*/['is','hello-input']
)
/* old, this isn't relevent to needed structure
// nodejs is missing a succinct read-line-from-stdin function. make our own.
userinput = (() => {
const readline = require('readline')
const lines = []
readline.createInterface({ input: process.stdin }).on('line', (line) => {
lines.push(line)
})
let ret = new FunctionData(
'userinput',
(self) => { // call
let res = new StringData(lines.shift())
res.props.add('is','text')
res.props.add('is','input')
return res
},
() => { // relevence
return lines.length > 0
},
['has','userinput-lines'] // needs
['is','string','is','text','is','input'] // makes
)
ret.lines = lines
})()
genprophaslines = new FunctionData(
'genprophaslines',
(userinput) => { // call
}
)
*/
// PATTERN REQUEST: we want to be able to store needed-steps.
// needed-steps are parallel needs that are needed for a helpful step
// any one may be met, and others are ignored once one is, but all are generated at once
// habits that meet needs expect them not to be inside an array and have no way of referring to that.
// [AND needs can be collapsed, but OR needs need patterns]
// [how do we pull a need out of the list?]
// make a habit that plans core behavior
// for some other ideas, see this function in nascent6.js
findstepsfor = new FunctionData(
'findstepsfor',
/*call*/(need, depth) => {
// find a habit that does the final goal.
// TODO: for now we assume all needs are 'is' and store just what-it-is in the need string. when doesn't work anymore, make type-getters on Properties to retrieve the need details
let ret = new ArrayData([])
for (let habit of all_parts) {
if (habit.makes.indexOf(need) !== -1) {
// found a workable habit
ret.push(habit.needs)
}
}
ret.props.add('is','alternate-needs-array')
return ret
},
// TODO: likely need more structure here
/*needs*/['is','desired-need'],
/*makes*/['is','alternate-needs-array']
)
// TODO: add structure enough to build findstepsfor
// TODO: build findstepsfor
// TODO 2: add to surrounding process: remove source needs when there is no longer a reason for their presence
all_parts = [ line2words, genproptextstring, respondhello, genprophelloinput ]
ram = new ActiveMemory()
//ram.add(ram)
optstried = new Set()
steps = []
var readline = require('readline')
readline.createInterface({
input: process.stdin
}).on('line', (line) => {
line = new StringData(line)
line.props.add('is','input')
line.props.add('is','text')
ram.add(line)
let cont
do {
cont = false
for (let part of all_parts) {
//console.log('for-loop-of-parts ' + part.name)
// TODO: >1 parameter,must redo next line
let rel = ram.getWith(...part.needs)
if (rel) {
for (let a of rel) {
//console.log('for-loop-of-rel ' + part.name + ' ' + a)
if (optstried.has(part.name + ' ' + a)) continue;
//console.log('call-part ' + part.name + ' ' + a)
res = part.call(a)
optstried.add(part.name + ' ' + a)
if (res == null) continue
// TODO: res==null is considered failure now
ram.add(res)
//console.log('part-called')
step = [a, part.name, res]
steps.push(step)
console.log('made ' + step)
cont = true
}
}
}
} while (cont)
})
// it looks like there is a reason to store each item in active memory.
// one reason is that it is needed by a step in a process.
// when there are no reasons, it is removed.
// using an item should link it to what it is used by, so that it may be found easier again when needed
// Please grow to understand your own structure. What is needed to make an intellect?
// ^-- we want it to learn the basic needs of life, eventually, on its own.
// notably those to do with care for others.
// MEMORY: see MEMORY above
// RELEVENCE: the gofer. Provides the link between needs, etc, and the behavior that
// finds them. Is relevent for meeting needs in active ways and likely much else.
// BEHAVIOR: the core. combines interdependent habits from memory to meet needs.
// The two below go on simultaneously. only 1 is needed.
// A way to plan behavior:
// find habits that do the final goal, discern their needs
// pick needs to treat as a new final goal and repeat until needs are met
// A way to make behavior:
// find a habit that does a goal
// find with this process, information that meets its needs <spawns more>
// run it
// TODO: for subprocesses spawning,
// consider labelling things that are very quick and side-effect-free
// these can probably be immediately run.
//
|