Skip to content

Instantly share code, notes, and snippets.

@LFReD
Created December 18, 2019 10:35
Show Gist options
  • Save LFReD/53f4054e264773796f578b47017d442b to your computer and use it in GitHub Desktop.
Save LFReD/53f4054e264773796f578b47017d442b to your computer and use it in GitHub Desktop.
Atomica for Ren-C
Rebol [
Title: "Atomica for Ren-C"
Author: "Terry Brownell"
File: %atomica.r
Version: 0.0.1
Rights: "Copyright (C) 2019 Terry W. Brownell"
License: {
Distributed under the Apache 2 License
See https://www.apache.org/licenses/LICENSE-2.0
}
]
if not exists? %data/atomica.db [make-dir %data write %data/atomica.db ""]
saveit: does [
dbsave: to block! atomica
save/all %data/atomica.db dbsave
dbsave: copy []
]
loadit: does [
atomica: load %data/atomica.db
atomica: to-hash atomica
]
cleanit: func [s1 p1][trim replace/all s1 " " "" trim replace/all p1 " " ""]
atomexists?: func [s1 p1 v1][
cleanit s1 p1
v1: trim to-string v1
if find/skip atomica reduce [s1 p1 v1] 3[return true]
return false
]
; --- Insert Atom - creates or updates a unique predicate eg: insertatom "bob" "firstname" "Robert"
insertatom: func [s1 p1 v1 /local updated? i i2][
atomica: head atomica
cleanit s1 p1
updated?: false
v1: trim v1
if series? i: find atomica reduce[s1 p1][i2: index? i i2: i2 + 2 atomica/:i2: v1 updated?: true]
if updated? = false [append atomica reduce [s1 p1 v1]]
saveit
]
; --- Insert Atoms - use this for multiple predicates eg: insertaoms "bob" "haspet" "Fido"
insertatoms: func [s1 p1 v1 /local is?][
atomica: head atomica
cleanit s1 p1
v1: trim to-string v1
is?: atomexists? s1 p1 v1
if is? = false [append atomica reduce [s1 p1 v1] saveit]
]
; --- Single Value - Returns value of subject and predicate
singlev: func [s1 p1 /local sub pred][
atomica: head atomica
cleanit s1 p1
if error? try [return third find/skip atomica reduce [s1 p1] 3][return none]
]
; --- Value of Subject and Predicate
vofsandp: func [s1 p1 /local output][
atomica: head atomica
cleanit s1 p1
output: copy []
while [not tail? atomica][if all [atomica/1 = s1 atomica/2 = p1 ][append output atomica/3] atomica: skip atomica 3]
return output
]
; --- Subject of Predicate and Value - Returns unique block of all subjects of specific pred and val
sofpandv: func [p1 v1 /local output][
atomica: head atomica
p1: trim replace/all p1 " " ""
v1: trim v1
output: copy []
while [not tail? atomica][if all [atomica/2 = p1 atomica/3 = v1 ][append output atomica/1] atomica: skip atomica 3]
return output
]
; --- Subject of Predicate - Returns block of unique subjects
sofp: func [p1 /local output][
atomica: head atomica
p1: trim p1: trim replace/all p1 " " ""
output: copy []
while [not tail? atomica][if atomica/2 = p1 [append output atomica/1] atomica: skip atomica 3]
output: unique output
return output
]
; --- Value of Predicate - Returns block of unique values
vofp: func [p1 /local output][
atomica: head atomica
p1: trim p1: trim replace/all p1 " " ""
output: copy []
while [not tail? atomica][if atomica/2 = p1 [append output atomica/3] atomica: skip atomica 3]
output: unique output
return output
]
; --- Delete atom requires the subject, predicate and value of atom to delete.
deleteatom: func [s1 p1 v1 /local flagit][
atomica: head atomica
cleanit s1 p1
v1: trim to-string v1
flagit: false
while [not tail? atomica][if all [atomica/1 = s1 atomica/2 = p1 atomica/3 = v1] [remove/part atomica 3 flagit: true] atomica: skip atomica 3]
if flagit = true [atomica: head atomica saveit]
]
loadit
@LFReD
Copy link
Author

LFReD commented Dec 18, 2019

Atomica for Ren-C Getting Started

Atomica for Ren-C is a flat-file semantic network DBMS

ITo get a clearer understanding of what we're trying to achieve, have a read of this Wikipedia article on Semantic Networks https://en.wikipedia.org/wiki/Semantic_network

Features

Runs in memory for blazing performance.
Eight simple functions perform 95% of database interaction.
Strong Semantic Network / Graphing capabilities
Dead simple to learn.
100% Rebol code, no dependencies.
4kb in size
Maps to SQL DBs with ease, using the same functions. No need to learn SQL
CRUD - Create, Retrieve, Update and Delete is at the core of Atomica

DRY - Don’t Repeat Yourself

“Every piece of knowledge must have a single, unambiguous, authoritative representation within a system”

Single Source of Truth - "structuring information models such that the element is stored once and no more than a single row in a single table"

Atomica is built on the idea that all languages, including computer languages are built on two main principles.

All language is made up of only three types of sentences.

Declarations: Statements of facts eg: “The color of the dog is black” or “Bob went shopping.”
Queries: “What color is the dog?” “Where is Bob?”
Commands: “Give the dog to Bob”

That’s it! Everything you say falls under one of those categories. (<- That sentence is a declaration.)

A database is nothing more than a collection of declarations, and we access those declarations using queries.

B. All sentences are composed of three parts.

The Subject: The subject is the ‘thing’ being discussed eg: “dog” or “Bob”
The Predicate: The predicate is like the verb of a sentence eg: “has color” or “ current location”
The Object/Value: Although the official term is the “object”, we prefer to use “the value” for clarity eg: “black” or “shopping”

To store these declarations in the Atomica database, we simplify the sentences, and save them as subject, predicate and value.

For example, to save the declaration “John has brown hair.” We would save it as;

subject: “John”
predicate: “hair color”
value: “brown”

We call each of these declarations an ‘atom’ as it’s the absolute minimum amount of data to form a declarative sentence.

A few things to note….

Every subject must be unique. There can only ever be one “john”, and in reality there is only one John… that guy there.. that John! But the world is full of johns? How do with differentiate them from another?

To solve this issue, we give each John a unique id for a subject. For example to identify this John in question, we could use “John1” or “btrsd” .. it doesn’t matter as long as that ‘subject’ is unique to this John, and only associated with him.. So then we can add this John to our database with everything we may want to know.

subject: “john1” 
predicate: “is a”
value: “person”

subject: “john1”
predicate: “first name” 
value: “John”

Of course we could go on, and add “john1” “hair color” “brown” or “john1” “age” “42”

All predicates used must remain consistent. It won’t help if one time you use “hair color” as the predicate, and then “color of hair” the next.

To make these declarations in Atomica for Red, we use the insertatom and insertatoms (note the s) functions. There’s a difference between the two, and it’s important to understand.

Insert Atom
If we’re entering a value that there is only one of... like a person’s hair color or first name, then we use the insertatom function ;

insertatom(“john1” “age” “42”)

John only has one age. In the future if we want to update his age, we use the same function and it will change ‘42’ to whatever age we enter, RATHER than adding a new entry. We don’t want this in our database…

“john1” “age” “42”
“john1” “age” “43”

Insert Atoms
However there are some things that John might have multiples of, like ‘has pet”. In that case we use the insertatoms function;

insertatoms (“john1” “has pet” “Fido”)
insertatoms (“john1” “has pet “Whiskers”)
insertatoms (“john1” “is a” “client”)
insertatoms (“john1” “is a” “developer”)

Queries

To access the our new database of declarations, like any language, we use queries.

Single Value Query
For example, let's say we want to answer the question “What age is John?”. We determine that by “john” we mean “john1” (vs “john2” or any other subject!)

For this query we want the subject, which is “john1” and the predicate, which is “age”. In this case we use the “singlev” function. (v s and p are short for value, subject and predicate, so in this case, it’s the ‘single value” that we want. Single because John only has one age. So in Atomica for Red we enter the query as so.

theage: singlev “john1” “age”
This will set ‘theage” to “42”.

Value of Subject and Predicate

Sometimes we want a block of values, such as the pets that John owns. For this we use the vofsandp (short for value of subject and predicate.. you’ll get used to it :) function

johnspets: vofsandp “john1” “has pet”

which will return a block [“Fido” “Whiskers”]

Subject of Predicate and Value

Similar, we may want to know who owns the pet named “Fido”. In which case we use the sofpandv (subject of predicate and value)function.

whoisowner: sofpandv “has pet” “Fido”

which will return a block [“john1”]

Subject of Predicate

At time, you may want to know who all owns pets in the corporation, but don’t care about the pet’s name. In this case you would use the sofp function.. you want the ‘subject’ that have a particular predicate eg:

petowners: sofp “has pet”

which returns a block [“john1”]

Lets add Mary and her pets, then run the same query..

insertatoms “mary42” “has pet” “Smokey”
petowners: sofp “has pet”

returns [“john1” “mary42”]

Value of Predicate

Returns the values of a particular predicate. For example, if we want all the pet names.. we use the vofp function

petnames: vofp “has pet”

returns [“Fido” “Whiskers” “Smokey”]

Deleting Atoms

Naturally, there comes a time when we need to delete an entire atom.. For this we use the deleteatom function; In order to delete an atom, you need to know the subject, predicate and value. (There’s other methods that we’ll be adding shortly)

deleteatom “mary42” “has pet” “Smokey”

These eight functions are the lion’s share of functions used with Atomica, and a good start, however the real power of Atomica lies in its semantic and AI capabilities.

Over the next weeks, we’ll be adding additional functions and functionality, so be sure to check back often!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment