main loop:
$ echo bendscript
Permission denied
$ sudo !!
sudo echo bendscript
Password: *******
bendscript
the splitting and merging phrenia:
# benben includes phrenia, bend, fold, fork, and recu marcos
# where recu indicates recursive fields
import KernelShtf.BenBen
# here is a type of brain that can be defined
phrenia BinaryTree do
node(val, recu(left), recu(right))
leaf()
end
# other types of brains such as linked lists are possible
phrenia List do
cons(head, recu(tail))
null()
end
# as well as property graphs
phrenia PropGraph do
graph(vertex_map, recu(edge_list), metadata)
vertex(vertex_id, properties, recu(adjacency))
edge(source_id, target_id, edge_weight, edge_props)
empty()
end
# this one is without weights or properties
phrenia SimpleGraph do
graph(vertices, recu(edges))
edge(from, to)
empty()
end
# here is an example without recursion
phrenia Transaction do
pending(operations, timestamp)
committed(changes, timestamp)
rolled_back(reason, timestamp)
end
what is a BenBen tho?
a Benben is the only unique stone on a pyramid
that also happens to be the shape of a pyramid
and sits at the top dating back to ancient egypt.
it has similar magic to recursion because it is
also a repeated pattern with in a structure; as in
their shapes reoccur in a pattern when looping
over said struct similarly in style.
i also really like pyramids too.
i also really like 1 + 1 philosophy.
so BenBen it is!
when it comes to looping over the phrenia data type...
we have two methods:
- bend -> which is about recusive splitting and allocation using conditions
- fold -> which is about recusive merging and computation using cases
first, let's have a look at bend...
# Create recursive structures using a declarative approach:
bend val = 0 do
if val < 3 do
BinaryTree.node(val, fork(val + 1), fork(val + 1))
else
BinaryTree.leaf()
end
end
# And it also supports nested bends with different variable names:
bend i = 0 do
bend j = 0 do
i + j
end
end
second, let's have a look at fold...
# Stateless operation
sum = fold tree do
case node(val, left, right) -> val + recu(left) + recu(right)
case leaf() -> 0
end
# Stateful operation
{result, final_state} = fold list, with: 0 do
case cons(head, tail) ->
{tail_value, new_state} = recu(tail)
new_sum = head + tail_value
{head, new_sum}
case null() -> {0, state}
end
# It should properly expand to something like:
do_fold(list, 0, fn value, state ->
case value do
%{variant: :cons, head: head, tail: tail} ->
result = head + (
{tail_result, new_state} = do_fold(tail, state, value)
state = new_state
tail_result
)
{result, state}
%{variant: :null} ->
{0, state}
end
end)
as you can tell bend and fold are two powerful ways, along with phrenia, of defining/working-with any type of recursive data structure.
i got their inspiration from bendlang by Higher Order Co they also happen to be implemented in the Haskel programming language.
now, i am still new to Elixir but i am hoping to change that with a couple of projects. the main goal is still compsci but i'd like to fit in at least 2 big projects as stepping stones that will hopefully get me there.
- the first is, "DeJa: Video Ultra"
- the second is, "Thread & Burl"
i wont be registering official domain names for them to save money instead i'll just create seperate github repos and link to this main repo when i need to.
everything in bendscript will act as a singleton. i only have a one old xeon machine connected to the internet that will run BEAM.
when i need more machines i will just add them as soon as i can afford them but soon i'm hoping to save $200 a month for a couple of mini pcs or even try getting one of those new Ryzen 16 core CPUs.
when i say act as a singleton i mean when i add more machines they will all see each other and there will be no test or staging cluster only a single production cluster. all BEAM nodes.
so rather than using kubernetes i will have to figure out how to run multiple instances of the same application as well as different applications all on a single BEAM instance/cluster.
when i happen to find a lot of money i will use these machines as a test or staging and then use the cloud or find a nearby datacenter and colocate :)
the plus side is that i have a fiber connection at home and can run any kind of home setup up until i reach 5Gbps max speed connection but i am currently paying $60 month for 500Mbps.
besides a brain for a data structure the next most and equally important thing is memory and the ability to think or "Milestone" about on that said memory.
use KernelShtf.Mil
# Define initial state
magnetic do
%{count: 0}
end
# Define synchronous calls
force(:increment, [amount]) do
new_count = floppy.count + amount
%{floppy | count: new_count}
end
# Define asynchronous casts
spell(:reset, []) do
%{floppy | count: 0}
end
Key aspects of the Gov module demonstrated:
magnetic
- Defines the state structureforce
- Handles state callscast
- Handles state castsfloppy
- Gives access to data
the above is basically an elixir generic server with syntax that will make you feel like a wizard with a magic net when you code in it. in this case a floppy disk which contains state.
in the above example state and "magnetic floppy" mean the same thing and it can be used as memory for your phrenia recu data types. more on this later.
because before there were floppy disk drives there were magnetic spinning drum drives. they spun uncontrolably similar to steem/gas engines, planets, nuke pp, etc. and needed to be governed or they would spin out of control. let's code a simple traffic signal below to demonstrate Gov in action.
defmodule TrafficSignal do
use KernelShtf.Gov
require Logger
fabric TrafficSignal do
# Define initial state
def canvas(_) do
{:ok, %{memory: :red, rotate: %{timer: 0}}}
end
# Red light state
pattern :red do
weave :cycle do
Logger.info("Cycling from red to green")
weft(to: :green, drum: drum)
end
end
# Green light state
pattern :green do
weave :cycle do
Logger.info("Cycling from green to yellow")
weft(to: :yellow, drum: drum)
end
end
# Yellow light state
pattern :yellow do
weave :cycle do
Logger.info("Cycling from yellow to red")
weft(to: :red, drum: drum)
end
end
end
end
Key aspects of the Gov module demonstrated:
fabric
- Defines the state machine structurepattern
- Defines state handlersweave
- Pattern matches on eventsweft
- Handles state transitionwarp
- Handles state staydrum
- Allows state to be accesseddrum.memory
- Gives current machine statedrum.rotate.<stone>
- Gives access to machine data
checkout lib/abc_law/intersection_signal.ex
for 2 way traffic light example with timers.
checkout lib/abc_law/vending_machine.ex
for a simple coin and inventory system.
before we get into the 4th KernelShtf
module we are going to introduce character-driven reasoning.
# READ!!! sotries for a coninuation of this documentation :)
cat ./storeis/STORY1.md
cat ./storeis/STORY2.md
cat ./storeis/STORY3.md
note: stories seams like a great way to get the compsci juices flowing. let's further refine our characters.
(hand is to glove as foot is to sock)
Are "is to" statemnets more harmful than "go to" statements?
The "is to" -> Analogy Statement Table (AST):
kind | field+trait | attack | strength | defense |
---|---|---|---|---|
rabbit | electromagnetism | short | strong | distributed |
lion | gravity | long | weak | centralized |
dragon | magic | medium | medium | balanced |
# READ!!! where we unravel the above "is to" AST's mystories
cat ./resonance_patterns/INTRO.md
cat ./resonance_patterns/SYSTEM_UNDER_STRESS.md
cat ./resonance_patterns/EMERGENT_EVOLUTION.md
in the above pantheon we got 3 main characters:
- Echo
- Nexus
- Harmony
let's call them the founders of our LEAGUE who are going to detect and discover RACE. as they work together they will build RACE from scratch starting from themselves, the knowledge that they gained from their own "is to" -> Analogy Statement Table, and their combined resonance patterns.
so far we have intro/structured BenBen and Mil + Gov...
the above intro/structures AST pantheons called LEAGUES...
now we are going to intro/structure stage-based workflows aka checkpoint-based tracks called RACE...
RACE: Reward Achievement Checkpoint Engine
in Elixir this is known as GenStage, Flow, and Broadway however we are going to simplify and codify a better solution using macros.
here is how to define a track aka "pipeline" with checkpoints aka "producers"
use KernelShtf.Race
track TestTrack do
checkpoints(
module: DummyJumper,
checker_concurrency: 2,
batch_size: 50
)
end
quantifying DSL terminology:
- producer -> jumper
- consumer -> lander
- processor -> checker
let's define "DummyJumper" that was stated in our checkpoints module...
defmodule TestMessage do
defstruct [:data]
end
defmodule DummyJumper do
use GenStage
def start_link(opts \\ []) do
GenStage.start_link(__MODULE__, opts)
end
def init(counter: counter) do
{:jumper, counter}
end
def handle_demand(demand, counter) when demand > 0 do
events = Enum.map(counter..(counter + demand - 1), &%TestMessage{data: &1})
{:noreply, events, counter + demand}
end
end
here is the MAP checkpoints (jumps and landings)...
jump TestJump do
def handle_demand(demand, state) do
events = Enum.to_list(1..demand)
{:noreply, events, state}
end
end
land TestLand, [TestJump] do
def handle_events(events, _from, state) do
send(state.test_pid, {:events_received, events})
{:noreply, [], state}
end
end
here is how we can test this MAP and it's checkpoints...
describe "jump and land" do
test "producer-consumer communication" do
{:ok, jumper} = TestJump.start_link([])
{:ok, lander} = TestLand.start_link(%{test_pid: self()})
# Wait for events
assert_receive {:events_received, events}, 1000
assert length(events) > 0
assert Enum.all?(events, &is_integer/1)
end
end
In Elixir, GenStage, Flow, and Broadway are tools for working with concurrent, parallel, and distributed data processing. Here's a comparison chart:
Feature | GenStage | Flow | Broadway |
---|---|---|---|
Abstraction Level | Low-level primitives | Higher-level abstraction | High-level, production-ready framework |
Focus | Producer-consumer stages | Data transformation | External system integrations |
Built-in Adapters | No | No | Yes (e.g., SQS, RabbitMQ) |
Use Cases | Custom workflows | Parallel data processing | Scalable data pipelines |
conclusion:
- Use GenStage if you need fine-grained control over stage-based workflows.
- Use Flow for parallel data processing and stream transformations.
- Use Broadway for building robust, production-ready pipelines that integrate with external systems.
so far we have seen 4 modules from KernelShtf that are a key part to what we are about to add on top next which is abstract and concrete concepts and the ability to bridge between the two. we are also going to add domain driven design struct on top of that which looks something like the following in layers starting from the center and moving outward and wraped around (spherically layered graphically).
# layer -1 (myth)
import AbcLaw
# layer 0 (system)
import KernelShtf
# layer 1.A (mental)
import AbstractPov
# layer 1.B (physical)
import ConcreteIrl
# layer 2 (mind-body connection)
import BridgeImo
# layer 3 (core)
import XyzCore
# layer 3.X (applications)
import XyzApps.Api
import XyzApps.Web
checkout
./lib
for the full source code.
reflection: now that we have BenBen, Mil + Gov, and RACE kernel modules as well as three 10x developers (Echo, Nexus, and Harmony) let's see if we now generate better stories that have more solid foundation of our core values.
mix new bendscript
If available in Hex, the package can be installed
by adding bendscript
to your list of dependencies in mix.exs
:
def deps do
[
{:bendscript, "~> 0.1.0"}
]
end
Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/benben.
# test everything
mix test 2>&1 | tee test.stdout.txt
# test specific files
mix test test/abc_law/intersection_signal_test.exs 2>&1 | tee intersection_signal_test.stdout.txt
mix test test/abc_law/vending_machine_test.exs 2>&1 | tee vending_machine_test.stdout.txt
mix test test/kernel_shtf/race_test.exs 2>&1 | tee kernel_shft_race.stdout.txt
DEBUG_META_LEARNING=true mix test test/kernel_shtf/meta_learning/emergence_test.exs 2>&1 | tee kernel_shft_meta_learning_emergence_test.stdout.txt
mix test test/kernel_shtf/meta_learning/example_test.exs 2>&1 | tee kernel_shft_meta_learning_example_test.stdout.txt
mix test test/concrete_irl/graffiti_test.exs 2>&1 | tee concrete_irl_graffiti.stdout.txt
mix test test/abstract_pov/counter_test.exs 2>&1 | tee abstract_pov_counter.stdout.txt
mix test test/abstract_pov/chain_test.exs 2>&1 | tee abstract_pov_chain.stdout.txt
mix test test/abstract_pov/parents_test.exs 2>&1 | tee abstract_pov_parents.stdout.txt
mix test test/abstract_pov/prop_graph_test.exs 2>&1 | tee abstract_pov_prop_graph.stdout.txt
mix test test/abstract_pov/simple_graph_test.exs 2>&1 | tee abstract_pov_simple_graph.stdout.txt
mix test test/bridge_imo/mecha_cyph/spaceship_queries_test.exs 2>&1 | tee bridge_imo_spaceship_queries.stdout.txt
# test specific tests within a file
mix test test/abstract_pov/chain_test.exs --only run:true 2>&1 | tee abstract_pov_chain.stdout.txt
ai should:
- keep/add logging
- return only what needs to be updated
- when filling out case arguements for fold you cant use _ you must use the full variant name
- within bend and fold variable arguments must match the phrenia variable definitions