Skip to content

Instantly share code, notes, and snippets.

@barneycarroll
Created June 29, 2022 18:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save barneycarroll/2238db92fc4bdaa7e5a868100bdfd2e9 to your computer and use it in GitHub Desktop.
Save barneycarroll/2238db92fc4bdaa7e5a868100bdfd2e9 to your computer and use it in GitHub Desktop.
export default generator =>
new Proxy(generator, {apply(){
return recorder(
generator, this, arguments
)
}})
function recorder([generator, context, args], ...records){
const iterator = generator.apply(context, args)
try {
while(records.length)
iterator.next(...records.unshift())
}
catch(e){
console.error(
`Fatal error forking iterator `,
iterator,
` from generator `,
generator,
)
throw e
}
return new Proxy(iterator, {
get: ({}, k) => (
'next' == k ? function next(){
if(this == iterator)
records.push(arguments)
return Reflect.apply(iterator, this, arguments)
}
:
'fork' == k ? () => recorder(iterator, ...records)
:
'detach' == k ? () => iterator
:
'records' == k ? records.slice()
:
Reflect.get(iterator, k)
)
})
}

Recorder-generator

Special generators whose iterators can be cloned.

import recorder from './recorder-generator.js'

const decoratedGenerator = recorder(generatorFunction) 
// The decorated generator has the same surface API and the same source
const iterator1 = decoratedGenerator(generatorInput)

while(condition1){
  // The iterator produced behaves as normal
  iterator1.next(Date.now())
}

// Fork creates a new initialisation of the decorated generator
// then fast-forwards it to the same state as iterator2
const iterator2 = iterator1.fork()

// The 2 iterators can now diverge

The iterator isn't really cloned – instead all input provided its yield evaluations are recorded; When the .fork() method is invoked, the source generator is re-run with the same input, then the resulting iterator is advanced, using .next(), and fed the same memoized input in the same sequence as the base.

The author should take care only to record and fork generators without side-effects, or a .fork() will cause changes to the runtime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment