Memelang v7
Memelang is an AI-optimized language for querying structured data, knowledge graphs, and retrieval-augmented generation pipelines.
Memes
Meme
- Comprises key-value pairs
key=value
- Pairs must be separated by whitespaces
\s+
- First pair always identifies the meme
m=<id>
- Must terminate with semicolon
;
Key
- Is an alphanumeric string
movie
Value
- Either integer
-123
- or float
45.6
- or unquoted alphanumeric string
Leia
- or CSV-style double quoted string
"John ""Jack"" Kennedy"
Comment
- Prefixed with double forward slashes
//
- Terminated with newline
\n
Example Memes
m=100 actor="Mark Hamill" role="Luke Skywalker" movie="Star Wars" rating=4.5;
m=101 actor="Harrison Ford" role="Han Solo" movie="Star Wars" rating=4.6;
m=102 actor="Carrie Fisher" role=Leia movie="Star Wars" rating=4.2;
m=110 actor="Mark Hamill" role=Joker movie="Batman: Mask of the Phantasm" rating=4.7;
m=111 actor="Harrison Ford" role="Indiana Jones" movie="Raiders of the Lost Ark" rating=4.8;
m=112 actor="Carrie Fisher" role=Marie movie="When Harry Met Sally" rating=4.3;
m=200 person="Mark Hamill" birthyear=1951 birthplace="Oakland, CA";
m=201 person="Harrison Ford" birthyear=1942 birthplace="Chicago, IL";
m=202 person="Carrie Fisher" birthyear=1956 birthplace="Burbank, CA";
m=300 place="Oakland, CA" population=433000 climate=Mediterranean foundedyear=1852;
m=301 place="Chicago, IL" population=2740000 climate="Humid Continental" foundedyear=1833;
m=302 place="Burbank, CA" population=105000 climate=Mediterranean foundedyear=1887;
EBNF Memes
The EBNF below is a machine-readable description of stored memes.
(* Memelang v7 *)
memelang ::= { meme } ;
meme ::= mid { WS+ pair } WS* ';' ( WS | comment )* ;
mid ::= 'm' '=' id ;
pair ::= key '=' value ;
key ::= ALNUM+ ;
id ::= DIGIT+ ;
value ::= ['-'] DIGIT+ ['.' DIGIT+]? | ALNUM+ | quoted ;
quoted ::= '"' ( CHAR | '""' )* '"' ;
comment ::= '//' CHAR* ( '\n' | EOF ) ;
ALNUM ::= 'A'..'Z' | 'a'..'z' | DIGIT | '_' ;
DIGIT ::= '0'..'9' ;
WS ::= ' ' | '\t' | '\r' | '\n' ;
CHAR ::= ? any Unicode character except '"' or '\n' ? ;
Queries
Queries are memes with uncertainty. The meme pair format key=value
is a special certainty case of the more general query pair format <keyopr><keys><valopr><values>
. Each query pair returns at least one certainty pair in the result.
Key Operator (keyopr)
- (none) matches the listed keys
K1=V1
!
matches any except the listed keys!K1=V1
Keys
- Single key matches exactly
K1=V1
- Wildcard matches any key for given values
*=V1
- Comma-separated list of keys matches any listed key
K1,K2=V1
- Variable (explained below)
Value Operator (valopr)
=
!=
>
>=
<
<=
Values
- Single value matches exactly
K1=V1
- Wildcard matches any value for given keys
K1=*
- Comma-separated list of values matches any listed value
K1=V1,V2
- Variable (explained below)
Example Queries
// Query for all movies with Mark Hamill as an actor
actor="Mark Hamill" movie=* role=*;
// Response
m=100 actor="Mark Hamill" movie="Star Wars" role="Luke Skywalker";
m=110 actor="Mark Hamill" movie="Batman: Mask of the Phantasm" role=Joker;
// Query for all relations and values from all memes relating to Mark Hamill
// All pairs in the meme match for *=*
*="Mark Hamill" *=*;
// Query for value inequalities
population>100000 place=*;
rating>=4.3 rating<=4.7 actor=* role=*;
Example OR/Negation Queries
!
key operator negates all keys in the list!=
value operator negates all values in the list
// OR–list semantics in set notation
K1,K2=V1,V2; // (key ∈ {K1,K2}) ∧ (value ∈ {V1,V2})
K1,K2!=V1,V2; // (key ∈ {K1,K2}) ∧ (value ∉ {V1,V2})
!K1,K2=V1,V2; // (key ∉ {K1,K2}) ∧ (value ∈ {V1,V2})
!K1,K2!=V1,V2; // (key ∉ {K1,K2}) ∧ (value ∉ {V1,V2})
!K1,K2>V1; // (key ∉ {K1,K2}) ∧ (value > V1)
// Query for (actor OR role) = ("Luke Skywalker" OR "Mark Hamill")
actor,role="Luke Skywalker","Mark Hamill" movie=*;
// Query for actors who are not Mark Hamill or Carrie Fisher
actor!="Mark Hamill","Carrie Fisher" role=* movie=*;
// Query for Mark Hamill for all keys except actor and role
!actor,role="Mark Hamill" movie=*;
Example Failure Queries
K1=V1=V2; // Error: cannot chain values
K1=*K2=*K3=X; // Error: missing spaces between pairs
K1=*,V1,V2; // Error: cannot mix wildcard and commas
actor="*"; // Warning: wildcard inside quotes is literal "*"
EBNF Queries
The continued EBNF below is a machine-readable description of query pairs.
(* Memelang v7 reuse grammar above *)
qmemelang ::= { qmeme } ;
qmeme ::= qpair { WS+ qpair } WS* ';' ( WS | comment )* ;
qpair ::= pair | qkv ;
qkv ::= [keyopr] keys valopr values;
keys ::= '*' | qkey {',' qkey} ;
values ::= '*' | qvalue {',' qvalue} ;
keyopr ::= '!' ;
valopr ::= '!=' | '<=' | '>=' | '<' | '>' | '=';
qkey ::= key | var ;
qvalue ::= value | var ;
var ::= ('@' | '@@' | '#' | '##') NZDIGIT DIGIT* | ('@' | '#') ALNUM+ [ ':' NZDIGIT DIGIT* ];
NZDIGIT ::= '1'..'9' ;
Variables
Variables let later pairs retrieve the keys (list of strings) and values (list of integers/floats/strings) returned from prior pairs.
- Variables cannot be assigned.
- Variables cannot forward-reference.
- Variables cannot reference objects or properties.
- Variables cannot be inside quotes.
Variable Arrays
Simplified variable model in python:
variables = {'K':[],'V':[]}
def array_add(keys: list, values: list):
variables['K'].append(keys)
variables['V'].append(values)
if len(keys)==1: variables.setdefault(keys[0].lower(), []).append(values)
def index_get(n: str) -> int:
if len(n)<1: return 1
return int(n)
def var_get(tok):
for sigil, mult, offset in (('#',1,-1), ('@',-1,0)):
if tok.startswith(sigil):
if tok.startswith(sigil+sigil): return variables['K'][mult*index_get(tok[2:])+offset]
if tok[1:].isdigit(): return variables['V'][mult*index_get(tok[1:])+offset]
name, _, p = tok[1:].partition(':')
return variables[name.lower()][mult*index_get(p)+offset]
How the variable arrays grow while processing the query:
movie="Star Wars" // 𝑝=1; variables={'K': [['movie']], 'V': [['Star Wars']], 'movie': [['Star Wars']]}
role=* // 𝑝=2; variables={'K': [['movie'], ['role']], 'V': [['Star Wars'], [V1, V2, …]], 'movie': [['Star Wars']], 'role': [[V1, V2, …]]}
*>4.5; // 𝑝=3; variables={'K': [['movie'], ['role'], [K1, K2, …]], 'V': [['Star Wars'], [V1, V2, …], [4.5]], 'movie': [['Star Wars']], 'role': [[V1, V2, …]]}
Forward-Indexes
- Variables prefixed with
#
use absolute forward-index numbering 𝑝 - Forward-index 𝑝 is a pair's absolute left-to-right query position
- Easy for AIs to count, hard for humans to maintain
- 𝑝=0 at
;
(or BOF) - 𝑝++ for every query pair (including
m
pairs below) - 𝑝=1 is the first pair
- 𝑝=2 is the second pair
Forward-Index Values
#
(single hash) sigils retrieve values with forward-indexing#𝑝
retrieves the values from the 𝑝th pair#1
retrieves the values from the first pair#2
retrieves the values from the second pair
Forward-Index Keys
##
(double hash) sigils retrieve keys with forward-indexing##𝑝
retrieves the keys from the 𝑝th pair##1
retrieves the keys from the first pair##2
retrieves the keys from the second pair
Forward-Index Keynames
#keyname:𝑝
retrieves the values from the 𝑝thkeyname
pair#keyname
and#keyname:1
retrieve the values from the firstkeyname
pair- Only populates when query keys is a single string (no
*
!
,
) - Case-insensitive
Backward-Indexes
- Variables prefixed with
@
use relative backward-index numbering 𝑞 - Backward-index 𝑞 counts backward from the current pair's query position 𝑞 = 𝑝₂ − 𝑝₁
- Harder for AIs to count, easier for humans to maintain
- 𝑞=0 is current pair (illegal)
- 𝑞++ for every query pair back (including
m
pairs below) - 𝑞=1 is the first pair back
- 𝑞=2 is the second pair back
Backward-Index Values
@
(single at-sign) sigils retrieve values with backward-indexing@𝑞
retrieves the values from the 𝑞th pair back@1
retrieves the values from the first pair back@2
retrieves the values from the second pair back
Backward-Index Keys
@@
(double at-sign) sigils retrieve keys with backward-indexing@@𝑞
retrieves the keys from the 𝑞th pair back@@1
retrieves the keys from the first pair back@@2
retrieves the keys from the second pair back
Backward-Index Keynames
@keyname:𝑞
retrieves the values from the 𝑞th priorkeyname
pair@keyname
and@keyname:1
retrieve the values from the lastkeyname
pair- Only populates when query keys is a single string (no
*
!
,
) - Case-insensitive
Example Variables
Variables are primarily used in joins (section below). However, variables occasionally retrieve a pair from the current meme (expert only, avoid).
// Query for titular roles whose value equals the movie title
// Every variable retrieves role=*
role=* actor=* movie=@role;
role=* actor=* movie=#role;
role=* actor=* movie=@2;
role=* actor=* movie=#1;
actor=* role=* movie=@role;
actor=* role=* movie=#role;
actor=* role=* movie=@1;
actor=* role=* movie=#2;
// Variables may be used in comma lists
role=* movie=@1,"Star Wars";
// Variables may swap value into key name
K1=* @1=V2; // @1 must be alphanumeric
K1=* @K1=V2;
// Variables may swap key name into value
*=V1 K2=@@1;
// FAILURE
person=* m!=@m actor="@person"; // Warning: variable inside quotes
person=* m!=@m actor=@person; // Likely meant
Joins
Distinct items (actors, movies, etc.) usually occupy distinct memes with unique m=id
identifiers. By default, a pair stays within the current meme. A join query matches multiple memes by specifying a pair with key m
, allowing the next pair to match a different meme.
m
key in a pair specifies which memes to join next@m
is automatically populated with the currentm=<id>
m=@m
andm=@m:1
stay in current meme (implicit default)m!=@m
join to a different memem=*
join to any meme (current or different)
Join Variables
Always after an m
pair, the following pair retrieves an uncertain pair from the prior meme.
- Generally using
@keyname
is preferred - When
@keyname
is unpopulated, the correct value variable is generally@2
- When
@K1
is used in the second meme,K1
must be a key in the first meme - For
K2=@K1
,K1
andK2
must have semantically similar values, such as person↔person or year↔year, not person↔year m!=@m
joins to distinct memes, so trailing distinct conditionals likeactor!=@actor
are generally redundant
// The most common join is distinct
K1=* // pair in first meme
m!=@m // next pair must match a distinct meme
K2=@K1; // pair in second meme, where K2 and K1 share a value
// Wildcard m allows the current meme in the second joined meme
K1=* // pair in first meme
m=* // next pair may match any meme
K2=@K1; // pair in second meme, where K2 and K1 share a value
// Wildcards in keys
*=* // every pair in first meme
m!=@m // next pair must match a distinct meme
*=@2; // pair in second meme, any key has value from first meme
Example Joins
// Query for all of Mark Hamill's costars - see how variables retrieve movie=* in their respective queries
actor="Mark Hamill" movie=* m!=@m movie=@movie actor=*;
movie=* actor="Mark Hamill" m!=@m movie=@movie actor=*;
actor="Mark Hamill" movie=* m!=@m movie=@2 actor=*; // @2 retrieves movie=*
movie=* actor="Mark Hamill" m!=@m movie=@3 actor=*; // @3 retrieves movie=*
actor="Mark Hamill" movie=* m!=@m movie=#2 actor=*; // #2 retrieves movie=*
movie=* actor="Mark Hamill" m!=@m movie=#1 actor=*; // #1 retrieves movie=*
// Response - join queries return combined memes, each pair belongs to the preceding m=<id>
m=100 actor="Mark Hamill" movie="Star Wars" m=101 movie="Star Wars" actor="Harrison Ford";
m=100 actor="Mark Hamill" movie="Star Wars" m=102 movie="Star Wars" actor="Carrie Fisher";
// Query for people born in the year their birthplace was founded - join on int birthyear is year = foundedyear is year
person=* birthyear=* m!=@m foundedyear=@birthyear place=*;
person=* birthyear=* m!=@m foundedyear=@2 place=*;
// Query for every meme related to any value related to Mark Hamill - wild join keys (expert, avoid)
actor="Mark Hamill" *=* m!=@m *=@2 *=*;
Example Multi-joins
// Query for the other movies Mark Hamill's costars have acted in - multi join
actor="Mark Hamill" movie=* m!=@m movie=@movie actor=* m!=@m actor=@actor movie=*;
actor="Mark Hamill" movie=* m!=@m movie=@2 actor=* m!=@m actor=@2 movie=*;
// Query for the population of the birthplace of the Star Wars cast
movie="Star Wars" actor=* m!=@m person=@actor birthplace=* m!=@m place=@birthplace population=*;
movie="Star Wars" actor=* m!=@m person=@2 birthplace=* m!=@m place=@2 population=*;
// Query for cities older than Burbank and with larger populations - inequality join
place="Burbank, CA" foundedyear=* population=* m!=@m population>@population foundedyear<@foundedyear place=*;
place="Burbank, CA" foundedyear=* population=* m!=@m population>@2 foundedyear<@4 place=*; // @4 = 1887 (Burbank foundedyear)
Failure Joins
movie=* movie=@1; // Warning: missing m= pair in join
movie=* m!=@m movie=@2; // Likely meant
movie=* m!=@m actor=*; // Warning: missing retrieved variable
movie=* m!=@m movie=@2 actor=*; // Likely meant
movie=* m!=@m movie=@1; // Warning: wrong index - @1 retrieves m!=@m pair
movie=* m!=@m movie=@2; // Likely meant
birthplace=* person=* m!=@m actor=@birthplace; // Warning: joined dissimilar values - actor != birthplace
person=* m!=@m actor=@person birthplace=*; // Likely meant
movie=* m!=@m actor=@director; // Semantic Error: undefined variable @director
director=* movie=* m!=@m actor=@director; // Likely meant
director=* movie=* m!=@m actor=@director:2; // Semantic Error: undefined variable @director:2 - wrong index
director=* movie=* m!=@m actor=@director; // Likely meant
Credits
Bri Holt · Patents Pending · ©2025 HOLTWORK LLC