summaryrefslogtreecommitdiff
path: root/intellect-framework-from-internet/starts/bagel/nascent6.js
blob: d7241ba0f93e8fc64f0643fea2fc7c64229f2be8 (plain)
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
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
// This file was WIP, two prongs were being pursued at once when work was halted.

// Meaning Representation
class Property {
	constructor(type, dest) {
		this.type = type
		this.dest = dest
	}
}
class Properties {
	// members are all Usage Simplification defining Promise Spec
	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))
	}
	// recommend hoisting variables when designing them, so they don't match everything
	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
	}
	get(type) {
		let result = null
		for (let i = 0; i < this.props.length; ++ i) {
			let p = this.props[i]
			if (p.type == type) {
				if (result) throw new Error('get on multiply defined property')
				result = p.dest
			}
		}
		return result
	}
	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')
	}
}

// Meaning Representation
class Var extends StringData {
	constructor(name){
		super(name)
		props.add('is','variable')
	}
	// recommend e.g. 'is','variable-rep' when code is designing them, so don't match everything
	// opencog uses a 'quote' wrapper to cause this, sounds more general
}
function isVar(x) {
	return x.props && x.props.has('is','variable')
}
const ONE = StringData('one')
const MANY = StringData('many')
const VAR_X = new Var('X')

// 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
// TODO: this class has methods.  turn them into promise-meeting-habits.  a promise is a spec for behavior, e.g. how data is stored.  this spec can be interpeted by a more general habit.
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
	}
	makesFrom(ram) { // what we make with the ram
		// match needs

		// TODO: improve from just picking 1.  preferably with relevence.
		for (let i = 0; i < this.needs.length; i += 2) {
			if (isVar(this.needs[i]) || isVar(this.needs[i+1])) {
				// iterate all other options with this? just pick 1?
				// STUB
			} else {
				if (!ram.containsWith(this.needs[i], this.needs[i+1]))
					return []
			}
		}
		// fill variables STUB
	}
	// say I want would-meet apple
	// and I have needs apple
	// the easiest way to find this is to fill the needs in with what I have
}

// 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

// sometimes how we get what we need depends on what we have
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?]

// is it useful to use as a need the memory generated by a habit?

// make a habit that plans core behavior
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
	// warning: MANY adds surrounding code complexity.  please put makes-interpretation in a habit if MANY is used. <- let's just put this in the class constructor for now
	/*needs*/['needs', VAR_X],
	/*makes*/[MANY, 'would-meet', VAR_X]
		// really we are usually met due to the need to meet a goal
		// and the need to have steps to meet that particular goal
		// how do we write a need that supports another need
		//
		// propose relevence is a list of reasons each with a strength, and greatest sum is chosen
		// HABIT/ACTIVE BEHAVIOR wants relevent-met-habits, to act on
		// PLANNING/GOAL BEHAVIOR wants relevent-unmet-needs to backtrace them towards relevent-met-needs
		//
		// we can meet any need with behavior, but it takes time.
		// 	[we are ignoring most of karl's needs]
		// 	[the reason is that an AI can meet them all]
		// 	AI meets some needs
		// 	AI is ongoing
		// 	therefore we are working on meeting 
		// ONE: we have a need for actively pursuing relevent needs
		// TWO: we need appropriate multitasking
		// 	AI is long term, so would happen after [quickly-]meetable-needs are met.
		//
		// make popcorn
		// need: made-popcorn
		// 1. identify that we need unmade popcorn and a microwave
		// ^-- made-popcorn is how? we can meet any need with behavior
		// 		what is substep of find-path-to-need
		// 			find path-part-to-need
		//
		// need: to meet needs
		// need: some-need
		// makestepsfor makes: some-other-need tagged makes: some-need
		//
		// when we push some-need we want to stimulate pushing some-other-need.
		//
		// use a variable as the link target, and use e.g. met-need
		// as the link type
)

// 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.
//