
John Lato wrote:
So here's a very simple expression:
t1 = let v = sigGen (cnst 1) in outs v v
which is what led to my question. I'm binding the sigGen to 'v' to introduce sharing at the meta-level. Would it be better to introduce support for this in the dsl?
Often this is not a question of preference but that of necessity. Sharing at the meta-level may help the generator, but it does _not_ translate into the sharing at the object level. In the generated code, the code for 'sigGen (cnst 1)' shall be duplicated. It could be that two csound blocks must share the same signal source, to receive samples in parallel. Meta-level sharing (Haskell's let) would not do. We need a construct for an object-level let, for example t1 = let_ (SigGen (cnst 1)) (\v -> outs v v) (Template Haskell can improve the syntax.) The term `off-shoring' was coined by Walid Taha and collaborators, and first appeared in the paper Implicitly Heterogeneous Multi-Stage Programming. GPCE'05 (whose first draft was written in Feb 2004).

On Fri, Oct 8, 2010 at 10:29 PM,
John Lato wrote:
So here's a very simple expression:
t1 = let v = sigGen (cnst 1) in outs v v
which is what led to my question. I'm binding the sigGen to 'v' to introduce sharing at the meta-level. Would it be better to introduce support for this in the dsl?
Often this is not a question of preference but that of necessity. Sharing at the meta-level may help the generator, but it does _not_ translate into the sharing at the object level. In the generated code, the code for 'sigGen (cnst 1)' shall be duplicated. It could be that two csound blocks must share the same signal source, to receive samples in parallel. Meta-level sharing (Haskell's let) would not do. We need a construct for an object-level let, for example
This was a problem, but I did arrive at a solution. When my interpreter evaluates an expression, it creates a named variable to store the result and memoizes it. Future evaluations of the expression with the same arguments become a reference to the named variable. This works well for functions. However, there may be some operations that should not be memoized. These can be handled by simply having the interpreter re-evaluate the expression. I've found that including a user-supplied label to control memoization creates consistency within the embedded language, and thus a more natural programming style. When targeting csound, the generated code is nearly exactly what I would have written directly, except for auto-generated variable names. I don't yet know how feasible it will be for other interpreters though. John

John, Oleg,
2010/10/9
So here's a very simple expression:
t1 = let v = sigGen (cnst 1) in outs v v
which is what led to my question. I'm binding the sigGen to 'v' to introduce sharing at the meta-level. Would it be better to introduce support for this in the dsl?
Often this is not a question of preference but that of necessity. Sharing at the meta-level may help the generator, but it does _not_ translate into the sharing at the object level. In the generated code, the code for 'sigGen (cnst 1)' shall be duplicated. It could be that two csound blocks must share the same signal source, to receive samples in parallel. Meta-level sharing (Haskell's let) would not do. We need a construct for an object-level let, for example
t1 = let_ (SigGen (cnst 1)) (\v -> outs v v)
An alternative approach to model sharing at the object level is the technique I use for modelling context-free grammars in my PADL 2011 paper "Explicitly Recursive Grammar Combinators" [1] (just got acceptance notification this morning!). The idea is basically that you make the sharing in the object-level expression explicit by modelling all your terms as the results of one big recursive function and then opening up the recursion. Using ideas from the Multirec generic programming library and some recent Haskell type system extensions (most importantly GADTs and type families), you can do this in a well-typed way for sets of mutually recursive object-level expressions. In this case, you would get something like the following (written without any understanding of your problem domain, so sorry if I interpret stuff wrong here ;) ): data I1 data T1 data CircuitNode ix where I1 :: CircuitNode I1 T1 :: CircuitNode T1 myCircuit self I1 = sigGen (cnst 1) myCircuit self T1 = outs (self I1) (self I1) With a type class such as RecProductionRule in my paper, you can then even get rid of the self argument and get something like this: myCircuit I1 = sigGen (cnst 1) myCircuit T1 = outs (ref I1) (ref I1) The main advantage is that this approach extends to circuits with mutually recursive nodes, but contrary to simple meta-level sharing, allows you to observe and manipulate the recursive structure of the circuit. Oh, and it stays properly typed. More info in the paper and the accompanying technical report [2]. cheers Dominique Footnotes: [1] http://people.cs.kuleuven.be/~dominique.devriese/permanent/cfgc-submitted-PA... [2] http://www.cs.kuleuven.be/publicaties/rapporten/cw/CW594.abs.html
participants (3)
-
Dominique Devriese
-
John Lato
-
oleg@okmij.org