control resumed inspired me to take a small exercise.
"Code a minimal approximation of the python yield operator based generators"
Here follow the results I managed to get with help from Matthias Felleisen, via the plt mailing list. You can see the non-edited exchange via the mailing list archives and control and macors. All control&prompt are forms specific to plt scheme's control.ss module. The first attempt looks something like this:
(require (lib "control.ss"))
(define (make-step)
(define (control-state)
(yield 1)
(yield 2)
(yield 3)
'finished)
(define (yield value) (control resume-here (set! control-state resume-here) value))
(define (generator) (prompt (control-state)))
generator)
(define step (make-step))
(step) (step)
It does the job. Kind of. For me the interesting bit is how the interplay of prompt and control achieve maintaining the current state of execution before the return and allowing to continue from that interruption. It can be done with call/cc but it looks a helluva a lot more complicated and is far more unreadable.
There is a problem with the code above though. As Matthias notes in his email:
LESSON: never 'test' by running things at the top-level prompt. It IS a prompt. -- Matthias
So comes version 2:
(require (lib "control.ss"))
(define (make-step)
(define (control-state)
(yield 1)
(yield 2)
(yield 3)
'finished)
(define (yield value)
(control resume-here
(set! control-state
(lambda () (prompt (resume-here))))
value))
(define (generator) (prompt (control-state)))
generator)
(define step (make-step))
(equal? '(1 2 3) (list (step) (step) (step)))
control-state is a variable holding a reference to a function with no arguments, doing what the python function would do. yield is a variable holding a reference to a function which does the interrupt magic. generator is a variable holding a reference to a (sugary) function which does the initial step.
The logic of the above algorithm is roughly as follows - mark thy state, do what you need to do, when you encounter control stop, remember your state by wrapping it in a function (resume-here), remember where do you what to continue from ( the set! control-state ...). Notice that the value of control-state is replaced. This is possible since the resume-here continuation is a function and a first class value.
So what next. Boilerplate code is tedious to write. And there is a lot of boilerplate code there. And every function, which needs to follow this recipe, will need to duplicate it.
So scheme macros to the rescue. It is not a trivial problem. A 'generator' function can look something like this:
This is a followup of a few of my previous posts (lisp-like programming, aspects and honey, patterns & languages, closures), which describe some programming idioms typical for lisp-like languages.
Here I will add some very short examples for how to do partial evaluation in php. The most straight forward approach would be something like:
I've been playing lately with a lot of different ideas. Part of it is to further my own education, part of it is looking for good software design tips. Although there exist quite a few good applications or frameworks, both open source and closed, I can't recommend any as really flexible. By really flexible, I mean easy ways to change its behaviour, how it reacts to the outside world. Most frameworks and applications excell at being themselves, and are rarely excelling at being really good citizens, they are inward looking, as far as their configuration and query is concerned. These are bold statements. They are quite subjective and probably useless. I'll try to explain what I really mean by positive examples.
The semantics of this language I'm thinking of are essentially scheme, with layout as opposed to bracket syntax, or more precisely being able to use either. The parallel blocks initially will be implemented using engines. The syncronicity issues can be implemented in a similar fasion, with a proxy function, to mediate between the function proper and it's return value.
I've been reviewing, scratching and descratching the idease for the language core, which for the time being I'll be calling da code.
Everything revolves around a few fundamental questions about functions. What is a function? What is a function behaviour? What is the effect of one function's evaluation(behaviour) on the overall ecosystem of a program?
In my head there are two fundamental kinds of function composition - sequential and parallel. It is true that they are redundant, since each of them can be expressed by the other, but in an attempt to provide a relatively brief and expressive language, I will consider both. This should help with intuitive application of different computational schematics.