Layout Options
Which layout option do you want to use?
Wide
Boxed
Color Schemes
Which theme color do you want to use? Select from here.
Reset color
Reset Background
Forums
New posts
Trending
Random
What's new
New posts
Latest activity
Rules
Libraries
New Audios
New Comments
Search Profile Audios
Clubs
Public Events
Log in
Register
What's new
Search
Search
Search titles only
By:
New posts
Trending
Random
Menu
Log in
Register
Install the app
Install
JavaScript is disabled. For a better experience, please enable JavaScript in your browser before proceeding.
You are using an out of date browser. It may not display this or other websites correctly.
You should upgrade or use an
alternative browser
.
Reply to thread
Forums
Boards
/g/ - Technology
A Governed Model of Deterministic Program Execution
Message
<blockquote data-quote="deaf_judger" data-source="post: 68065" data-attributes="member: 390"><p><strong><span style="font-size: 22px">[PLAIN]Governed Model of Program Execution[/PLAIN]</span></strong></p><p> [PLAIN]Most introductory programming courses teach execution like: a program runs from top to bottom, performing calculations and occasionally interacting with the outside world—printing text, writing files, sending network requests. In many languages, calculation and action are interwoven. I propose a different structure. I will seperate calculation from action and insert a governing runtime between them. The result is a deterministic, auditable model of execution implemented in Haskell. To understand the design, it is helpful to clarify two importnat ideas:</p><p> [/PLAIN]</p><p></p><p> [PLAIN]A pure function is a function that only computes a result from its inputs. It does not modify files, read from the network, print to the screen, or depend on hidden global state. Given the same inputs, it always returns the same output. In contrast, an effect (short for “side effect”) is an action that changes or observes the external world such as writing a file, sleeping for a second, or printing a line.</p><p> [/PLAIN]</p><p></p><p> [PLAIN]Most programs mix these freely. I won't. Effects will be treated as descriptions of actions of possible actions, and actually performing them will be postponed until a later, controlled stage.</p><p> [/PLAIN]</p><p></p><p></p><p></p><p><strong><span style="font-size: 22px">[PLAIN]Separating Calculation from Action[/PLAIN]</span></strong></p><p> [PLAIN]My language evaluates expressions into values. Crucially, evaluating an effect does not perform it. It produces a value that describes it.</p><p> [/PLAIN]</p><p></p><p> [PLAIN]In the evaluator:</p><p> [/PLAIN]</p><p></p><p> [CODE=haskell]</p><p> evalExpr _ (Emit ed) = Right (VEffect ed)</p><p> [/CODE]</p><p></p><p> [PLAIN]When the program encounters something like “emit this effect,” the interpreter returns a VEffect value. It does not run the effect and the interpretator remains purely computational.</p><p> After evaluation finishes, the system collects all the effect descriptions that were produced:</p><p> [/PLAIN]</p><p></p><p> [CODE=haskell]</p><p> collectEffects :: [Value] -> [EffectDescription]</p><p> collectEffects [] = []</p><p> collectEffects (VEffect ed : vs) = ed : collectEffects vs</p><p> collectEffects (VList subVs : vs) = collectEffects subVs ++ collectEffects vs</p><p> collectEffects (_ : vs) = collectEffects vs</p><p> [/CODE]</p><p> [PLAIN]This function walks through the final values of the program and extracts the list of EffectDescription structures. Everything else is ignored. At this point, the program has not changed the world. It has only described the changes it would like to make.</p><p> [/PLAIN]</p><p></p><p></p><p></p><p><strong><span style="font-size: 22px">[PLAIN]Why Treat Effects as Data?[/PLAIN]</span></strong></p><p> [PLAIN]Treating effects as data provides several advantages:</p><p> [/PLAIN]</p><p></p><p> <ol> <li data-xf-list-type="ol">[PLAIN]Predictability: The interpreter is entirely deterministic. It only computes values.<br /> [/PLAIN]<br /> </li> <li data-xf-list-type="ol">[PLAIN]Inspectability: Before anything runs, the full set of requested actions is visible.<br /> [/PLAIN]<br /> </li> <li data-xf-list-type="ol">[PLAIN]Control: Another component can decide which actions should actually occur.<br /> [/PLAIN]<br /> </li> </ol><p> [PLAIN]The system assigns each effect a unique identifier derived from its content:</p><p> [/PLAIN]</p><p></p><p> [CODE=haskell]</p><p> EffectID = SHA256(canonicalEffectBytes)</p><p> [/CODE]</p><p> [PLAIN]An effect's identity depends on what it is. If two effect descriptions are structurally identical, they have the same ID. This makes effects content-addressed. Identity is not based on when they are created or where they appear in the program. It is based solely on structure.</p><p> [/PLAIN]</p><p></p><p></p><p></p><p><strong><span style="font-size: 22px">[PLAIN]Dependency Graphs and Deterministic Scheduling[/PLAIN]</span></strong></p><p> [PLAIN]Effects may depend on other effects. For example, “write to file B” might depend on “create directory A.” These dependencies are explicitly recorded. The runtime constructs a dependency graph and executes effects in layers. Effects with no unmet dependencies form a “wave” and may run in parallel:</p><p> [/PLAIN]</p><p></p><p> [CODE=haskell]</p><p> currentEntries <- mapConcurrently realizeTransition ready</p><p> return (sortOn heEffectID currentEntries ++ nextEntries)</p><p></p><p> [/CODE]</p><p> [PLAIN]All effects in a layer are executed concurrently. After execution, the results are sorted by [/PLAIN]`EffectID' [PLAIN]before being recorded. This ensures that, even though execution is parallel, the historical record is deterministic.</p><p> If some effects cannot run because their dependencies failed, they are rejected. Nothing is silently retried or implicitly reordered. </p><p> [/PLAIN]</p><p></p><p></p><p></p><p><strong><span style="font-size: 22px">[PLAIN]Authorization Before Execution[/PLAIN]</span></strong></p><p> [PLAIN]Before executing an effect, the runtime checks its historical record. If an identical effect (same [/PLAIN]`EffectID'[PLAIN]) has already succeeded, it is not executed again.</p><p> [/PLAIN]</p><p></p><p> [CODE=haskell]</p><p> governorAdmit :: History -> EffectDescription -> Decision</p><p> [/CODE]</p><p> [PLAIN]If the effect has already been completed successfully, the decision is “reject.” Otherwise, it may proceed.</p><p> This guarantees idempotence. The key architectural point here is that the component deciding whether an action may occur is different from the component that knows how to perform it.</p><p> [/PLAIN]</p><p></p><p></p><p></p><p><strong><span style="font-size: 22px">[PLAIN]Executing and Verifying Effects[/PLAIN]</span></strong></p><p> [PLAIN]Each type of effect has an associated specification:</p><p> [/PLAIN]</p><p></p><p> [CODE=haskell]</p><p> data EffectSpec = EffectSpec</p><p> { esRun :: EffectDescription -> IO Outcome</p><p> ,esVerify :: EffectDescription -> IO Outcome</p><p> }</p><p></p><p> [/CODE]</p><p></p><p> [PLAIN]The runtime:</p><p> [/PLAIN]</p><p></p><p> <ul> <li data-xf-list-type="ul">[PLAIN]Decides whether the effect is allowed.<br /> [/PLAIN]<br /> </li> <li data-xf-list-type="ul">[PLAIN]Runs it if permitted.<br /> [/PLAIN]<br /> </li> <li data-xf-list-type="ul">[PLAIN]Verifies the result.<br /> [/PLAIN]<br /> </li> <li data-xf-list-type="ul">[PLAIN]Records the outcome in a ledger.<br /> [/PLAIN]<br /> </li> </ul><p></p><p></p><p></p><p><strong><span style="font-size: 22px">[PLAIN]The Ledger[/PLAIN]</span></strong></p><p> [PLAIN]Every attempted effect is appended to a persistent ledger stored in SQLite.</p><p> Each entry records:</p><p> [/PLAIN]</p><p></p><p> <ul> <li data-xf-list-type="ul">[PLAIN]The time of execution<br /> [/PLAIN]<br /> </li> <li data-xf-list-type="ul">[PLAIN]The effect’s unique ID<br /> [/PLAIN]<br /> </li> <li data-xf-list-type="ul">[PLAIN]Its dependencies<br /> [/PLAIN]<br /> </li> <li data-xf-list-type="ul">[PLAIN]Whether it was admitted or rejected<br /> [/PLAIN]<br /> </li> <li data-xf-list-type="ul">[PLAIN]Whether it succeeded or failed<br /> [/PLAIN]<br /> </li> </ul><p> [PLAIN]The ledger is append-only. Past entries are never modified. This creates a durable audit trail of system behavior. The system also checks for “symmetry”: identical effect IDs should not receive inconsistent admission decisions across runs. If they do, the system can detect the inconsistency.</p><p> [/PLAIN]</p><p></p><p></p><p></p><p><strong><span style="font-size: 22px">[PLAIN]Language-Level Constraints[/PLAIN]</span></strong></p><p> [PLAIN]The language further enforces discipline by restricting what effect definitions may contain. Effect bodies must be simple, they cannot contain branching (if), local bindings (let), or nested functions.</p><p> For example:</p><p> [/PLAIN]</p><p></p><p> [CODE=haskell]</p><p> isControlFlow (Seq _) = True</p><p> isControlFlow (Let _ _ _) = True</p><p> isControlFlow (Fun _ _ _ _) = True</p><p> isControlFlow (If _ _ _) = True</p><p> [/CODE]</p><p></p><p> [PLAIN]If an effect body includes any of these constructs, elaboration fails.This restriction ensures that effects are declarative descriptions, not mini-programs with hidden logic.</p><p> Decision-making remains in the pure computation layer or in the governing runtime.</p><p> [/PLAIN]</p><p></p><p></p><p></p><p><strong><span style="font-size: 22px">[PLAIN]Conclusion[/PLAIN]</span></strong></p><p> [PLAIN]This architecture reframes program execution. Instead of:</p><p> [/PLAIN]</p><p></p><p> </p><p> [PLAIN]My language enforces: :</p><p> [/PLAIN]</p><p></p><p> <ul> <li data-xf-list-type="ul">[PLAIN]Compute desired actions (purely).<br /> [/PLAIN]<br /> </li> <li data-xf-list-type="ul">[PLAIN]Identify and organize them.<br /> [/PLAIN]<br /> </li> <li data-xf-list-type="ul">[PLAIN]Decide which are admissible.<br /> [/PLAIN]<br /> </li> <li data-xf-list-type="ul">[PLAIN]Execute them in a controlled order.<br /> [/PLAIN]<br /> </li> <li data-xf-list-type="ul">[PLAIN]Verify and record results immutably.<br /> [/PLAIN]<br /> </li> </ul><p></p><p> [PLAIN]The separation increases transparency and determinism. It becomes possible to inspect all intended changes before they occur. Execution history is stable and replayable. Duplicate actions are automatically suppressed.</p><p> [/PLAIN]</p><p></p><p> [PLAIN]In contrast to conventional interpreters, where IO can occur at any point in evaluation, this design introduces structure and governance.</p><p> [/PLAIN]</p></blockquote><p></p>
[QUOTE="deaf_judger, post: 68065, member: 390"] [B][SIZE=6][PLAIN]Governed Model of Program Execution[/PLAIN][/SIZE][/B] [PLAIN]Most introductory programming courses teach execution like: a program runs from top to bottom, performing calculations and occasionally interacting with the outside world—printing text, writing files, sending network requests. In many languages, calculation and action are interwoven. I propose a different structure. I will seperate calculation from action and insert a governing runtime between them. The result is a deterministic, auditable model of execution implemented in Haskell. To understand the design, it is helpful to clarify two importnat ideas: [/PLAIN] [PLAIN]A pure function is a function that only computes a result from its inputs. It does not modify files, read from the network, print to the screen, or depend on hidden global state. Given the same inputs, it always returns the same output. In contrast, an effect (short for “side effect”) is an action that changes or observes the external world such as writing a file, sleeping for a second, or printing a line. [/PLAIN] [PLAIN]Most programs mix these freely. I won't. Effects will be treated as descriptions of actions of possible actions, and actually performing them will be postponed until a later, controlled stage. [/PLAIN] [B][SIZE=6][PLAIN]Separating Calculation from Action[/PLAIN][/SIZE][/B] [PLAIN]My language evaluates expressions into values. Crucially, evaluating an effect does not perform it. It produces a value that describes it. [/PLAIN] [PLAIN]In the evaluator: [/PLAIN] [CODE=haskell] evalExpr _ (Emit ed) = Right (VEffect ed) [/CODE] [PLAIN]When the program encounters something like “emit this effect,” the interpreter returns a VEffect value. It does not run the effect and the interpretator remains purely computational. After evaluation finishes, the system collects all the effect descriptions that were produced: [/PLAIN] [CODE=haskell] collectEffects :: [Value] -> [EffectDescription] collectEffects [] = [] collectEffects (VEffect ed : vs) = ed : collectEffects vs collectEffects (VList subVs : vs) = collectEffects subVs ++ collectEffects vs collectEffects (_ : vs) = collectEffects vs [/CODE] [PLAIN]This function walks through the final values of the program and extracts the list of EffectDescription structures. Everything else is ignored. At this point, the program has not changed the world. It has only described the changes it would like to make. [/PLAIN] [B][SIZE=6][PLAIN]Why Treat Effects as Data?[/PLAIN][/SIZE][/B] [PLAIN]Treating effects as data provides several advantages: [/PLAIN] [LIST=1] [*][PLAIN]Predictability: The interpreter is entirely deterministic. It only computes values. [/PLAIN] [*][PLAIN]Inspectability: Before anything runs, the full set of requested actions is visible. [/PLAIN] [*][PLAIN]Control: Another component can decide which actions should actually occur. [/PLAIN] [/LIST] [PLAIN]The system assigns each effect a unique identifier derived from its content: [/PLAIN] [CODE=haskell] EffectID = SHA256(canonicalEffectBytes) [/CODE] [PLAIN]An effect's identity depends on what it is. If two effect descriptions are structurally identical, they have the same ID. This makes effects content-addressed. Identity is not based on when they are created or where they appear in the program. It is based solely on structure. [/PLAIN] [B][SIZE=6][PLAIN]Dependency Graphs and Deterministic Scheduling[/PLAIN][/SIZE][/B] [PLAIN]Effects may depend on other effects. For example, “write to file B” might depend on “create directory A.” These dependencies are explicitly recorded. The runtime constructs a dependency graph and executes effects in layers. Effects with no unmet dependencies form a “wave” and may run in parallel: [/PLAIN] [CODE=haskell] currentEntries <- mapConcurrently realizeTransition ready return (sortOn heEffectID currentEntries ++ nextEntries) [/CODE] [PLAIN]All effects in a layer are executed concurrently. After execution, the results are sorted by [/PLAIN]`EffectID' [PLAIN]before being recorded. This ensures that, even though execution is parallel, the historical record is deterministic. If some effects cannot run because their dependencies failed, they are rejected. Nothing is silently retried or implicitly reordered. [/PLAIN] [B][SIZE=6][PLAIN]Authorization Before Execution[/PLAIN][/SIZE][/B] [PLAIN]Before executing an effect, the runtime checks its historical record. If an identical effect (same [/PLAIN]`EffectID'[PLAIN]) has already succeeded, it is not executed again. [/PLAIN] [CODE=haskell] governorAdmit :: History -> EffectDescription -> Decision [/CODE] [PLAIN]If the effect has already been completed successfully, the decision is “reject.” Otherwise, it may proceed. This guarantees idempotence. The key architectural point here is that the component deciding whether an action may occur is different from the component that knows how to perform it. [/PLAIN] [B][SIZE=6][PLAIN]Executing and Verifying Effects[/PLAIN][/SIZE][/B] [PLAIN]Each type of effect has an associated specification: [/PLAIN] [CODE=haskell] data EffectSpec = EffectSpec { esRun :: EffectDescription -> IO Outcome ,esVerify :: EffectDescription -> IO Outcome } [/CODE] [PLAIN]The runtime: [/PLAIN] [LIST] [*][PLAIN]Decides whether the effect is allowed. [/PLAIN] [*][PLAIN]Runs it if permitted. [/PLAIN] [*][PLAIN]Verifies the result. [/PLAIN] [*][PLAIN]Records the outcome in a ledger. [/PLAIN] [/LIST] [B][SIZE=6][PLAIN]The Ledger[/PLAIN][/SIZE][/B] [PLAIN]Every attempted effect is appended to a persistent ledger stored in SQLite. Each entry records: [/PLAIN] [LIST] [*][PLAIN]The time of execution [/PLAIN] [*][PLAIN]The effect’s unique ID [/PLAIN] [*][PLAIN]Its dependencies [/PLAIN] [*][PLAIN]Whether it was admitted or rejected [/PLAIN] [*][PLAIN]Whether it succeeded or failed [/PLAIN] [/LIST] [PLAIN]The ledger is append-only. Past entries are never modified. This creates a durable audit trail of system behavior. The system also checks for “symmetry”: identical effect IDs should not receive inconsistent admission decisions across runs. If they do, the system can detect the inconsistency. [/PLAIN] [B][SIZE=6][PLAIN]Language-Level Constraints[/PLAIN][/SIZE][/B] [PLAIN]The language further enforces discipline by restricting what effect definitions may contain. Effect bodies must be simple, they cannot contain branching (if), local bindings (let), or nested functions. For example: [/PLAIN] [CODE=haskell] isControlFlow (Seq _) = True isControlFlow (Let _ _ _) = True isControlFlow (Fun _ _ _ _) = True isControlFlow (If _ _ _) = True [/CODE] [PLAIN]If an effect body includes any of these constructs, elaboration fails.This restriction ensures that effects are declarative descriptions, not mini-programs with hidden logic. Decision-making remains in the pure computation layer or in the governing runtime. [/PLAIN] [B][SIZE=6][PLAIN]Conclusion[/PLAIN][/SIZE][/B] [PLAIN]This architecture reframes program execution. Instead of: [/PLAIN] [PLAIN]My language enforces: : [/PLAIN] [LIST] [*][PLAIN]Compute desired actions (purely). [/PLAIN] [*][PLAIN]Identify and organize them. [/PLAIN] [*][PLAIN]Decide which are admissible. [/PLAIN] [*][PLAIN]Execute them in a controlled order. [/PLAIN] [*][PLAIN]Verify and record results immutably. [/PLAIN] [/LIST] [PLAIN]The separation increases transparency and determinism. It becomes possible to inspect all intended changes before they occur. Execution history is stable and replayable. Duplicate actions are automatically suppressed. [/PLAIN] [PLAIN]In contrast to conventional interpreters, where IO can occur at any point in evaluation, this design introduces structure and governance. [/PLAIN] [/QUOTE]
Insert quotes…
Name
Verification
Post reply
Forums
Boards
/g/ - Technology
A Governed Model of Deterministic Program Execution
Top