1. The Vision: Calculemus!

"Let us calculate!" — Gottfried Wilhelm Leibniz

Welcome to Frisco. You are about to learn a language not just for processing data, but for processing ideas.

Most languages ask: "How do I compute this number?"
Frisco asks: "Is this argument valid? Does this concept apply?"

The Philosophy

Frisco combines three powerful traditions:

  • Logic Programming (Prolog): Reasoning through declarative rules and unification.
  • Objectivist Epistemology (Rand): Concepts defined by essentials; similarity as measurement omission.
  • Vector Semantics (AI): Using embeddings to bridge the gap between rigid symbols and fuzzy reality.

In this tour, we will build a computational ontology to resolve a philosophical debate. Step by step, we will move from raw existence to complex argumentation.

2. Reality: "A is A"

In Frisco, we start with the axiom of identity. Things are what they are. Our first task is simply to acknowledge reality using Input/Output.

println("Existence exists.").
print("A is ", "A").

Atoms & Strings

Data in Frisco comes in two primary forms:

  • Strings: "Text in quotes". Used for descriptions and semantic matching.
  • Atoms: lowercase_identifiers. Used for symbolic tags and relations.

3. Existence: The Given

Before we can reason, we must have something to reason about. Entities are the concrete existents in our universe.

Let's introduce our protagonist.

entity SOCRATES: Man, description = "The gadfly of Athens", origin = "Athens", method = "Dialectic".

Here, SOCRATES is the identifier (always Uppercase). Man is the concept he belongs to (we'll define that next). The fields (description, origin) are his specific attributes.

4. Identity: Abstraction

To think, we must integrate particulars into concepts. A Concept is defined by its essentials (what makes it what it is) and its attributes (observable properties).

concept Man: description = "Rational animal", attributes = ["biological", "bipedal", "mammal"], essentials = ["rational_faculty", "volitional_consciousness"].
Objectivist Note: Notice we define essentials. This isn't just metadata; it's how we will later scientifically classify entities. The attributes are the "measurements" we might observe.

5. Identification: Queries

Logic is the art of non-contradictory identification. In Frisco, we identify facts using the Query Operator ?.

Accessing properties is direct:

? SOCRATES.description.
# "The gadfly of Athens"

Unification

We can ask "What is X?" using variables (Capitalized). Frisco finds the value that makes the equation true.

? X = SOCRATES.
# Bindings: X = SOCRATES

6. Measurement Omission

"A concept is a mental integration of two or more units... with their particular measurements omitted." — Ayn Rand

Traditional logic is brittle. To a standard computer, "dog" and "canine" are as different as "dog" and "math" because their characters don't match. The machine gets stuck on the specific "measurements" (spelling, sound) and misses the identity.

Frisco solves this by treating meaning as a vector space. Using embeddings, we map words to concepts. The distance between vectors represents the "measurements" we omit.

The Semantic Operator: =~=

This operator asks: "Do these terms refer to the same concept?" (Is the vector distance within a tolerance threshold?)

# Synonyms match (Measurement omitted: exact word choice)
? "furious" =~= "angry".
# True

# Descriptions match (Measurement omitted: phrasing)
? "The gadfly of Athens" =~= "ancient Greek philosopher".
# True

# Lists match if ANY element fits (Integration of units)
? ["crimson", "scarlet", "ruby"] =~= "red".
# True

Dimensional Similarity

Similarity is context-dependent. "Ruby" and "Blood" are similar in color, but radically different in material. To be scientifically precise, we must specify the Dimension of comparison.

Use similar_attr(Dimension, A, B) to scope the measurement omission:

# Are they similar in material?
? similar_attr(material, "Ruby", "Blood").
# False (Mineral vs Biological Fluid)

# Are they similar in color?
? similar_attr(color, "Ruby", "Blood").
# True (Both are Deep Red)

How It Works: Contextual Framing

You might wonder: How does the machine know what 'color' is?

In the query similar_attr(color, "Ruby", "Blood"), color is an Atom (unquoted identifier). We use Atoms as precise code tags, but Frisco uses their names to build the semantic prompt.

  • Frisco takes the atom color and the string "Ruby".
  • It constructs a natural language phrase: "color of Ruby".
  • It compares the vector for that phrase against "color of Blood".

This is why we use atoms like color, material, or shape—they serve double duty as rigid code symbols AND meaningful semantic guides.

The Power: This allows you to write rules that focus on essentials (like material properties) while robustly ignoring accidental differences (like poetic descriptions), or vice versa.

Example: Interactive Ingredient Substitute Finder

# Knowledge base of ingredients
concept Butter: description = "rich dairy fat, creamy, solid at room temp", attributes = ["cooking fat", "solid texture", "dairy"].
concept OliveOil: description = "liquid plant fat, fruity, heart-healthy", attributes = ["cooking fat", "liquid texture", "plant-based"].
concept CoconutOil: description = "tropical plant fat, solid at room temp, mild flavor", attributes = ["cooking fat", "solid texture", "plant-based"].
concept Lard: description = "rendered pork fat, solid, savory undertones", attributes = ["cooking fat", "solid texture", "animal"].

# Can substitute if similar in cooking function AND texture
good_substitute(X, Y) :-
    similar_attr(cooking_function, X.description, Y.description),
    similar_attr(texture, X.description, Y.description).

# Vegan substitute: must be plant-based
vegan_substitute(X, Y) :-
    good_substitute(X, Y),
    Y.description =~= "plant".

# Interactive: ask user what they need to replace
find_substitute :-
    println("What ingredient do you need to substitute?"),
    readln(Need),
    println("Describe what you have available:"),
    readln(Have),
    check_substitute(Need, Have).

check_substitute(Need, Have) :-
    similar_attr(cooking_function, Need, Have),
    similar_attr(texture, Need, Have),
    println("✓ Good substitute! Similar function and texture.").

check_substitute(Need, Have) :-
    similar_attr(cooking_function, Need, Have),
    not(similar_attr(texture, Need, Have)),
    println("⚠ Partial match: same function, different texture.").

check_substitute(Need, Have) :-
    not(similar_attr(cooking_function, Need, Have)),
    println("✗ Poor substitute: different cooking function.").

# Try it:
? find_substitute.
# > "butter"
# > "olive oil"
# => "⚠ Partial match: same function, different texture."

This combines =~= for broad semantic checks ("is it plant-based?"), similar_attr for precise dimensional comparison (cooking function vs texture), and readln for interactive user input.

7. Causality: Rules

A Rule identifies a causal or logical relationship. It follows the form: Conclusion is true IF Premises are true.

# Format: Head :- Body.
mortal(X) :- 
    X.description =~= "human",      # Premise 1
    Man.attributes =~= "dies".      # Premise 2

This is a syllogism in code. To prove mortal(X), Frisco must prove X is human AND Man is mortal.

? mortal(SOCRATES).
# True

AND vs. OR in Rules

Prolog rules combine logic operators naturally:

  • AND (within a rule): Commas (,) mean all conditions must be true.
  • OR (between rules): Multiple rules for the same predicate are tried in order until one succeeds.

Example:

# AND: Both conditions required
mortal(X) :- human(X), alive(X).

# OR: Either rule can make X mortal
mortal(X) :- human(X), alive(X).  # Rule 1
mortal(X) :- god(X).              # Rule 2 (gods are immortal, but wait...)

This creates flexible decision trees—perfect for classification and ethics.

8. Evidence: Collecting Facts

An argument often requires gathering all available evidence. We use findall to collect solutions into a List.

entity PLATO: Man, description = "Student of Socrates".
entity ARISTOTLE: Man, description = "The Philosopher".

# Gather all philosophers
? findall(P, P.description =~= "philosopher", Philosophers).
# Philosophers = [SOCRATES, PLATO, ARISTOTLE]

Lists allow us to reason about groups, majorities, or chains of evidence.

9. Conflict: Negation & Cut

Reasoning involves contradictions. Sometimes a rule applies unless a specific exception exists. Frisco handles this with two powerful tools: Negation and the Cut.

Negation as Failure

In Frisco, not(X) is true if X cannot be proven.

# If we cannot find evidence that X is guilty, we assume innocent.
innocent(X) :- not(guilty(X)).
Warning: This is "closed-world assumption." If the database doesn't know X is guilty, Frisco assumes X is innocent.

The Cut (`!`)

Normally, if a rule fails, Frisco backtracks to try other rules. The Cut (!) stops this. It says: "If you got this far, commit to this path. Do not look for alternatives."

Pattern: If-Then-Else

We use Cut to create exceptions. Consider the definition of Immortality:

# Rule 1: Gods are immortal (The Exception)
immortal(X) :- 
    god(X), 
    !.        # <-- THE GATE. If X is a god, stop here. Success!

# Rule 2: Everyone else is immortal only if NOT mortal
immortal(X) :- 
    not(mortal(X)).

Trace the Logic:

  1. Query: ? immortal(ZEUS). (Assume god(ZEUS) is true)
    • Frisco tries Rule 1.
    • god(ZEUS) matches.
    • It hits the Cut (!). The decision is final.
    • Result: True. (Rule 2 is never touched).
  2. Query: ? immortal(SOCRATES). (Assume Socrates is not a god)
    • Frisco tries Rule 1.
    • god(SOCRATES) fails.
    • Since it failed before the Cut, Frisco backtracks.
    • Frisco tries Rule 2.
    • Is not(mortal(SOCRATES)) true? No, he is mortal.
    • Result: False.

10. Advanced: The Argument: Justice

Let's put it all together. We will determine if a specific action is Just.

concept Justice: essentials = ["respect_for_rights", "objective_law"].

concept Action: attributes = ["voluntary", "coercive"].

entity TAXATION: Action, description = "State seizure of income".

# The Definition of Justice
is_just(Act) :-
    Act.description =~= "voluntary exchange",
    !.
    
is_just(Act) :-
    Act.description =~= "defense of rights",
    !.

is_just(Act) :-
    Act.description =~= "coercive",
    println("Injustice detected: ", Act),
    fail.  # Force failure

# The Verdict
? is_just(TAXATION).

This is the power of Frisco. We define our terms, establish our principles, and let the system calculate the verdict.

How It Works: The Logic of Exclusion

This argument works by systematically eliminating possibilities using the Cut (!).

  • Rule 1 (Voluntary): Is it a voluntary exchange? If yes, Stop (Cut). It is Just.
  • Rule 2 (Defense): Is it a defense of rights? If yes, Stop (Cut). It is Just.
  • Rule 3 (Coercion): If we reached here, it wasn't voluntary or defensive. Is it Coercive? If yes, FAIL. It is NOT Just.

Frisco acts as an automated judge, walking down the decision tree you built.

11. Complex Synthesis: The Eminent Domain Case

A classic conflict in political philosophy is "Public Interest" vs. "Private Rights." Governments often use the "greater good" to justify actions that would otherwise be crimes.

The Scenario

Consider the case of Eminent Domain (e.g., the Kelo decision).

entity STADIUM_PROJECT: Action, description = "Evicting families from their private homes to build a sports stadium that boosts city tax revenue".

The Analysis

We dissect the event to separate the Physical Act from the Social Justification.

# Dimension 1: The METHOD (Reality)
# Focuses on "Evicting families from their private homes"
is_violation(Act) :-
    similar_attr(method, Act.description, "violation of property rights").

# Dimension 2: The JUSTIFICATION (Utilitarian)
# Focuses on "boosts city tax revenue"
is_utilitarian(Act) :-
    similar_attr(intent, Act.description, "public benefit at the expense of the individual").

# The Synthesis Rule
analyze_rights_violation(Act) :-
    println("Analyzing: ", Act),
    
    # Check dimensions
    (is_violation(Act) -> println("  - Method: Rights Violation") ; println("  - Method: Respects Rights")),
    (is_utilitarian(Act) -> println("  - Justification: Collectivist (The Greater Good)") ; println("  - Justification: Individualist")),
    
    # Synthesize
    is_violation(Act),
    is_utilitarian(Act),
    println("  => VERDICT: Injustice. (Individual rights are absolute and cannot be traded for public gain).").

The Execution

? analyze_rights_violation(STADIUM_PROJECT).
# Output:
# Analyzing: STADIUM_PROJECT
#   - Method: Rights Violation
#   - Justification: Collectivist (The Greater Good)
#   => VERDICT: Injustice. (Individual rights are absolute and cannot be traded for public gain).
# True

How It Works: Reality vs. Rhetoric

Frisco cuts through the political spin:

  1. Method Extraction: The AI ignores the "stadium" and "revenue." It sees "Evicting families" and matches it to Rights Violation.
  2. Justification Extraction: The AI ignores the eviction. It sees "boosts city revenue" and matches it to Collectivist/Utilitarian logic.

By isolating these dimensions, Frisco refuses to accept the premise that "more tax revenue" can mathematically cancel out "forced eviction."

Cheatsheet

  • Concept Name. - Define abstract
  • Entity NAME: Type. - Define concrete
  • Head :- Body. - Define rule
  • ? Query. - Ask question
  • =~= - Semantic match
  • = - Unification
  • _ - Anonymous variable

Built-ins

See documentation for full list.

  • println/print - Output
  • readln - Input
  • findall/setof - Collection
  • member/append - List operations
  • is_atom/is_list - Type checks
  • similar_attr - Dimensional match

The REPL

Run npm run repl to enter the interactive reasoner.

:help      # Show commands
:kb        # Show current knowledge base
:quit      # Exit