Computer Science › Software + Distributed Computing

Programming Languages

0 of 18
  1. Operational Semantics and Small-Step Evaluation

    Before building an interpreter, a language needs a precise, on-paper definition of what each expression actually evaluates to — small-step operational semantics gives exactly that, one inference rule at a time, on a language small enough to write every rule down in full.

    Read →6 sections9 min
  2. The Untyped Lambda Calculus

    Three constructs — a variable, a function, and a function call — turn out to be enough to build every programming language construct that exists; the lambda calculus is that minimal core, stripped of everything else so its evaluation rules can be studied directly.

    Read →6 sections9 min
  3. Beta Reduction and Evaluation Strategies

    Beta reduction — substituting an argument for a bound variable — is the lambda calculus's one and only computation rule; the real design choice is WHEN to apply it, and call-by-value vs. call-by-name is that choice, made concrete on a term that behaves differently under each.

    Read →6 sections9 min
  4. The Lambda Calculus as a Model of Computation

    Church encodings show that booleans, numbers, and even recursion can be built from nothing but functions — real evidence for the Church-Turing thesis's claim that the lambda calculus, despite having no built-in data types at all, computes exactly what a Turing machine computes.

    Read →6 sections9 min
  5. Lexical Analysis: Scanning Source into Tokens

    The first step from raw source text to a running program: a scanner walks the character stream once, left to right, and groups characters into tokens — numbers, identifiers, operators — the smallest units a parser is willing to work with.

    Read →6 sections8 min
  6. Parsing Expressions into an Abstract Syntax Tree

    A parser takes the token stream and recovers its grammatical structure — literally applying the context-free grammar derivations already covered, but now building a tree instead of just deciding accept-or-reject.

    Read →6 sections9 min
  7. Evaluating an AST: A Tree-Walking Interpreter

    An `eval` function that recurses over the AST, one node type at a time, is small-step operational semantics made runnable — every evaluation rule written on paper earlier becomes one case of a real function here.

    Read →6 sections8 min
  8. Environments and Variable Scope

    A variable name is not the value it holds — an environment is the runtime data structure (a chain of mappings) that actually connects the two, and lexical vs. dynamic scope is a real design choice about which environment a variable resolves against.

    Read →6 sections9 min
  9. Implementing Closures: The Environment That Outlives Its Frame

    Closures were already shown as a language FEATURE — a function that keeps working after its enclosing scope returns. Here is the implementation underneath: a function value is a pair of its code and the environment it was created in, kept alive by that pairing alone.

    Read →6 sections9 min
  10. Control Flow and Statements in an Interpreter

    An `if` or a `while` is not a special magic case for an interpreter — it is one more AST node type whose evaluation rule decides which of its children to evaluate, and how many times, entirely in terms of machinery already built.

    Read →6 sections8 min
  11. Functions and the Call Stack at Runtime

    The interpreter's own call stack (tree-walk recursion calling itself for a function call) and the real hardware call stack already covered are the same idea at two different levels: one frame per active call, torn down on return either way.

    Read →6 sections9 min
  12. Static vs. Dynamic Typing

    A static type system rejects some programs before they ever run; a dynamic one only discovers a type error the moment it happens at runtime — the same tradeoff (caught early vs. more flexible) that shows up in every real language's design.

    Read →6 sections10 min
  13. Type Checking: Progress and Preservation

    "Well-typed programs don't go wrong" is not a slogan — it is exactly two provable properties: progress (a well-typed term is either done or can still take a step) and preservation (taking a step never changes a term's type).

    Read →6 sections9 min
  14. The Simply Typed Lambda Calculus

    Adding one typing rule per lambda-calculus construct turns the untyped calculus into a small, real type system — a typing judgment written directly under a function, checked against a context, exactly like the progress/preservation properties it's designed to satisfy.

    Read →6 sections10 min
  15. Type Inference and the Need for Unification

    Writing every type annotation by hand gets tedious fast — type inference recovers the same typing judgments without them, by generating constraints between unknown types and solving those constraints by unification.

    Read →6 sections9 min
  16. Automatic Memory Management: Reference Counting and Tracing GC

    Manual heap management already showed exactly how a leak or a dangling pointer happens — a language runtime with automatic memory management exists specifically to make that entire bug class structurally impossible, at the cost of runtime work a C program never pays.

    Read →6 sections9 min
  17. Capstone: Assembling a Complete Tree-Walking Interpreter

    Every piece built in this discipline — scanner, parser, AST, environment, closures, control flow, a type checker — wired together into one small, working interpreter, mirroring how the CPU discipline's own capstone assembled gates and a datapath into a working machine.

    Read →6 sections10 min

Programming Languages

Part of the Computer Science curriculum.

Sort
1

Language Implementation vs. Language Features

Programming Paradigms compared what languages let you SAY — OOP vs. functional vs. logic, as features you choose between. This discipline asks a different question: once a language exists on paper, how does a machine actually make a program written in it run?

2

Operational Semantics and Small-Step Evaluation

Before building an interpreter, a language needs a precise, on-paper definition of what each expression actually evaluates to — small-step operational semantics gives exactly that, one inference rule at a time, on a language small enough to write every rule down in full.

3

The Untyped Lambda Calculus

Three constructs — a variable, a function, and a function call — turn out to be enough to build every programming language construct that exists; the lambda calculus is that minimal core, stripped of everything else so its evaluation rules can be studied directly.

4

Beta Reduction and Evaluation Strategies

Beta reduction — substituting an argument for a bound variable — is the lambda calculus's one and only computation rule; the real design choice is WHEN to apply it, and call-by-value vs. call-by-name is that choice, made concrete on a term that behaves differently under each.

5

The Lambda Calculus as a Model of Computation

Church encodings show that booleans, numbers, and even recursion can be built from nothing but functions — real evidence for the Church-Turing thesis's claim that the lambda calculus, despite having no built-in data types at all, computes exactly what a Turing machine computes.

6

Lexical Analysis: Scanning Source into Tokens

The first step from raw source text to a running program: a scanner walks the character stream once, left to right, and groups characters into tokens — numbers, identifiers, operators — the smallest units a parser is willing to work with.

7

Parsing Expressions into an Abstract Syntax Tree

A parser takes the token stream and recovers its grammatical structure — literally applying the context-free grammar derivations already covered, but now building a tree instead of just deciding accept-or-reject.

8

Evaluating an AST: A Tree-Walking Interpreter

An `eval` function that recurses over the AST, one node type at a time, is small-step operational semantics made runnable — every evaluation rule written on paper earlier becomes one case of a real function here.

9

Environments and Variable Scope

A variable name is not the value it holds — an environment is the runtime data structure (a chain of mappings) that actually connects the two, and lexical vs. dynamic scope is a real design choice about which environment a variable resolves against.

10

Implementing Closures: The Environment That Outlives Its Frame

Closures were already shown as a language FEATURE — a function that keeps working after its enclosing scope returns. Here is the implementation underneath: a function value is a pair of its code and the environment it was created in, kept alive by that pairing alone.

11

Control Flow and Statements in an Interpreter

An `if` or a `while` is not a special magic case for an interpreter — it is one more AST node type whose evaluation rule decides which of its children to evaluate, and how many times, entirely in terms of machinery already built.

12

Functions and the Call Stack at Runtime

The interpreter's own call stack (tree-walk recursion calling itself for a function call) and the real hardware call stack already covered are the same idea at two different levels: one frame per active call, torn down on return either way.

13

Static vs. Dynamic Typing

A static type system rejects some programs before they ever run; a dynamic one only discovers a type error the moment it happens at runtime — the same tradeoff (caught early vs. more flexible) that shows up in every real language's design.

14

Type Checking: Progress and Preservation

"Well-typed programs don't go wrong" is not a slogan — it is exactly two provable properties: progress (a well-typed term is either done or can still take a step) and preservation (taking a step never changes a term's type).

15

The Simply Typed Lambda Calculus

Adding one typing rule per lambda-calculus construct turns the untyped calculus into a small, real type system — a typing judgment written directly under a function, checked against a context, exactly like the progress/preservation properties it's designed to satisfy.

16

Type Inference and the Need for Unification

Writing every type annotation by hand gets tedious fast — type inference recovers the same typing judgments without them, by generating constraints between unknown types and solving those constraints by unification.

17

Automatic Memory Management: Reference Counting and Tracing GC

Manual heap management already showed exactly how a leak or a dangling pointer happens — a language runtime with automatic memory management exists specifically to make that entire bug class structurally impossible, at the cost of runtime work a C program never pays.

18

Capstone: Assembling a Complete Tree-Walking Interpreter

Every piece built in this discipline — scanner, parser, AST, environment, closures, control flow, a type checker — wired together into one small, working interpreter, mirroring how the CPU discipline's own capstone assembled gates and a datapath into a working machine.