Progress Meter:
- [WIP] Knowledge-Representation Improvements
- [X] Better syntax, cleaner API & refactoring
- [~] Meta info in slots
- [ ] Advice
- [X] Change predicates
- [ ] Multi-Methods (value-based)
- [WIP] Constraint Management Improvements
- [X] Better syntax & some refactoring
- [W] Parameterized pointer variables
- [X] Advice (for constraints)
- [X] Store constraints as KR objects
- [ ] Async execution
- 2D Graphics
- [ ] Linear Algebra and Geometry additions
- [ ] 2D API for geometry + Backend (via SDL)
- [ ] Event objects + Backend (via SDL)
- [ ] Text API + Backend (via Pango)
- [ ] Cells
- [ ] Configurations
- [ ] Some demo (after everything else)
---
August sucked progress-wise and so did most of September. Just like did
all of the summer, really. There were a few reasons for the long break,
but the facts are still the facts: not much progress in those 4.5 months
or so.
In the future, I will try not to raise people's hopes for quick
short-term progress, it will probably be best I only show something once
actually done or right in the works.
In any case, I have been back to working on the project over this past
month, and there's some decent news:
*** Schema creation has been revised to be more straightforward and
without overhead. ***
Instead of doing
(Ξ (:init-options '(:inheritance :static
:ht-args (:test #'equalp)))
(a 10))
now one would do this instead:
(Ξ (test #'equalp)
(inheritance :static)
(a 10))
The new approach manages to do more work at compile time, and is quite
simpler than before, both in implementation and in usage.
*** Ditched the /constraints as schemas/ way. ***
Constraints being schemas worked, but after some thinking, I figured
there won't be that much practical benefit to that approach after all. I
thought that was unavoidable for ergonomics, but I don't think that
anymore. As long as constraints (1) can be schema-like and (2) provide a
way of customization, things should be quite fine. The former is now
accomplished via struct-slot access over the typical schema read/write
operations. The solution to the latter was simply to allow storing a
custom object within a constraint and allow inheritance for it (simply
via a user-supplied function).
What's good about the new approach is that it doesn't incur additional
costs -- those were around 25% both in terms of creation speed and
memory consumption. And while that may be not that much, what the hell,
right? Constraints are used for inheritance, which means there's a
constraint for every slot in an object, so that was implying a certain
tangible cost for every object created with a dynamic inheritance
option. Not an entirely pressing cost, but still.
But the more general motivation behind the initial work was to allow any
struct to derive from `schema', at first only get initialized
minimially, and then, if necessary, upgrade to a full schema status at
runtime. This yields a kind of object that becomes powerful on demand
(either at creation or at runtime). And while I still feel it's an
interesting idea, it would perhaps make most sense for a rather more
general-purpose object system. And I don't feel like the current
foundations I am using allow for accomplishing that in a good way.
And so I rolled that stuff back, "until further notice".
Oh, well, the new constraints can be named and may be inherited with an
option to redefine the path of any input/output variable. For example,
the following constraint keeps a history of a given slot value (here in
the 'in slot) by writing to the ring-buffer contained in the 'out slot,
via mutation:
(ζ history# (in out)
(:= out (rb/add out in) out)) ; rb refers to a ring-buffer
Now, to derive the constraint for a custom slot, one need only redefine
the paths (in, out or both):
(ζ ((in (>> 'x))
(out (>> 'x-history)))
(is-a history#))
Partial path redefinition is possible just as well, of course. And
storing custom information is done via a 'sub slot:
(ζ () (sub (make-some-custom-data ...)) ...)
So, this here probably is as complicated as it needs to be.
*** Currently I am working on parameterized pointer variables. ***
I think I have a pretty good idea of what they are going to work out
like in the end.
(ζ (Q (>> * 'q)))
Here (>> * 'q) is a path, * is a wild card, 'q is a slot of every schema
that matches the wild card in the current object.
One will then be able to define a method that uses Q in one of the
following ways:
(:= Q (+ p 2)) ; define the 'q slot of every matching schema to equal (+ p 2)
(:= p (apply #'+ (all Q))) ; other direction: define p as a function of the Q set
(:= P (+ Q 2)) ; one-to-one match, where both P and Q use wildcards; maybe
The wildcard matching will have a filtering and recursion depth
option. Multiple wild cards will be allowed to appear in a single path.
PS The long break did have some benefits. For one, it let me take a
fresh look at KR, I guess. But generally I just want to thank people
who are supporting me for sticking it through with the project over
the few stale months : )
Yours,
-- Dmitrii Korobeinikov