1"use strict";(globalThis.webpackChunkbarnum_docs=globalThis.webpackChunkbarnum_docs||[]).push([[2942],{6924(e,n,t){t.r(n),t.d(n,{assets:()=>o,contentTitle:()=>i,default:()=>l,frontMatter:()=>s,metadata:()=>c,toc:()=>d});var r=t(6106),a=t(9236);const s={},i="Context and Variables",c={id:"patterns/context-and-variables",title:"Context and Variables",description:"Pipeline data flows forward \u2014 each step receives the previous step's output. bind and bindInput make earlier values available to later steps without threading them through every intermediate handler.",source:"@site/versioned_docs/version-0.4/patterns/context-and-variables.md",sourceDirName:"patterns",slug:"/patterns/context-and-variables",permalink:"/docs/patterns/context-and-variables",draft:!1,unlisted:!1,tags:[],version:"0.4",frontMatter:{},sidebar:"documentationSidebar",previous:{title:"Racing",permalink:"/docs/patterns/racing"},next:{title:"Early Return",permalink:"/docs/patterns/early-return"}},o={},d=[{value:"The problem",id:"the-problem",level:2},{value:"bindInput \u2014 named parameter access",id:"bindinput--named-parameter-access",level:2},{value:"bind \u2014 concurrent variable capture",id:"bind--concurrent-variable-capture",level:2},{value:"How it works",id:"how-it-works",level:2}];function h(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"context-and-variables",children:"Context and Variables"}),"\n",(0,r.jsxs)(n.p,{children:["Pipeline data flows forward \u2014 each step receives the previous step's output. ",(0,r.jsx)(n.code,{children:"bind"})," and ",(0,r.jsx)(n.code,{children:"bindInput"})," make earlier values available to later steps without threading them through every intermediate handler."]}),"\n",(0,r.jsx)(n.h2,{id:"the-problem",children:"The problem"}),"\n",(0,r.jsxs)(n.p,{children:["Consider a workflow that implements a refactor, type-checks, reviews, and then commits. Several of these steps need the ",(0,r.jsx)(n.code,{children:"worktreePath"})," from the original input, but intermediate steps like ",(0,r.jsx)(n.code,{children:"implement"})," and ",(0,r.jsx)(n.code,{children:"typeCheckFix"})," produce their own outputs."]}),"\n",(0,r.jsxs)(n.p,{children:["Without ",(0,r.jsx)(n.code,{children:"bindInput"}),", every handler has to accept and re-emit the fields that later steps need:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:'// Without bindInput: manual threading\nconst implementAndReview =\n // implement needs worktreePath + description, but must also pass worktreePath through\n augment(pick("worktreePath", "description").then(implement))\n // typeCheckFix needs worktreePath, must also pass it through\n .then(augment(pick("worktreePath").then(typeCheckFix)))\n // judge needs the full context, must pass worktreePath through\n .then(augment(judgeRefactor.then(classifyJudgment) /* ... handle NeedsWork/Approved ... */))\n // commit needs worktreePath\n .then(pick("worktreePath").then(commit).drop())\n // createPR needs branch + description \u2014 hope they survived all that augmenting\n .then(pick("branch", "description").then(preparePRInput).then(createPR));\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Every step wraps in ",(0,r.jsx)(n.code,{children:"augment"})," to merge its output back so downstream steps can access earlier fields. The pipeline becomes a mess of ",(0,r.jsx)(n.code,{children:"augment"})," and ",(0,r.jsx)(n.code,{children:"pick"})," calls just to thread data through. And if any step forgets to preserve a field, later steps break silently."]}),"\n",(0,r.jsx)(n.h2,{id:"bindinput--named-parameter-access",children:"bindInput \u2014 named parameter access"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"bindInput"})," captures the pipeline input once and makes it available by name throughout the body:"]}),"\n",(0,r.jsxs)(n.p,{children:["From ",(0,r.jsx)(n.a,{href:"https://github.com/barnum-circus/barnum/tree/master/demos/identify-and-address-refactors/handlers/refactor.ts",children:(0,r.jsx)(n.code,{children:"demos/identify-and-address-refactors/handlers/refactor.ts"})}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:'export const implementAndReview = bindInput<ImplementAndReviewParams>((params) =>\n params.pick("worktreePath", "description").then(implement).drop()\n .then(params.pick("worktreePath").then(typeCheckFix).drop())\n\n .then(loop((recur) =>\n judgeRefactor.then(classifyJudgment).branch({\n NeedsWork: a
1pplyFeedback.drop()\n .then(params.pick("worktreePath").then(typeCheckFix))\n .drop().then(recur),\n Approved: drop,\n }),\n ).drop())\n\n .then(params.pick("worktreePath").then(commit).drop())\n .then(params.pick("branch", "description").then(preparePRInput).then(createPR)),\n);\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"params"})," is a reference to the original input. ",(0,r.jsx)(n.code,{children:'params.pick("worktreePath")'})," retrieves those fields at any point \u2014 even deep inside the loop's ",(0,r.jsx)(n.code,{children:"NeedsWork"})," branch. No threading, no augmenting. Each step ",(0,r.jsx)(n.code,{children:".drop()"}),"s its own output because downstream steps pull what they need from ",(0,r.jsx)(n.code,{children:"params"})," directly."]}),"\n",(0,r.jsx)(n.h2,{id:"bind--concurrent-variable-capture",children:"bind \u2014 concurrent variable capture"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"bind"})," runs multiple actions concurrently and makes their results available as variables:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",children:"bind(\n [fetchUser, fetchPermissions, fetchConfig],\n ([user, permissions, config]) =>\n user.then(processUser)\n .then(permissions.then(checkAccess))\n .then(config.then(applySettings)),\n)\n"})}),"\n",(0,r.jsxs)(n.p,{children:["All three fetches run in parallel. Once complete, ",(0,r.jsx)(n.code,{children:"user"}),", ",(0,r.jsx)(n.code,{children:"permissions"}),", and ",(0,r.jsx)(n.code,{children:"config"})," are variable references \u2014 dereferencing them at any point in the body retrieves the captured value."]}),"\n",(0,r.jsx)(n.h2,{id:"how-it-works",children:"How it works"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"bind"})," compiles to ",(0,r.jsx)(n.code,{children:"All"})," (for concurrent execution) followed by nested ",(0,r.jsx)(n.code,{children:"ResumeHandle"})," layers (one per variable). Each variable reference is a ",(0,r.jsx)(n.code,{children:"ResumePerform"})," that reads from the handler's state. See ",(0,r.jsx)(n.a,{href:"/docs/architecture/algebraic-effect-handlers",children:"algebraic effect handlers"})," for the compilation details."]})]})}function l(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},9236(e,n,t){t.d(n,{R:()=>i,x:()=>c});var r=t(7378);const a={},s=r.createContext(a);function i(e){const n=r.useContext(s);return r.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:i(e.components),r.createElement(s.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.