digitalmars.D.learn - A feture adjustment request and a syntax blasphemy
- BCS (144/144) Oct 27 2006 This is allowed:
- Chris Nicholson-Sauls (7/187) Oct 27 2006 My brain hurts from reading that. You are an evil, evil, little man, an...
- BCS (4/10) Oct 28 2006 In case you are interested, if anyone working under me ever attempted to...
- David Medlock (17/43) Oct 28 2006 If I am not mistaken but this is a closure.
- Jarrett Billingsley (12/20) Oct 29 2006 As David said, this is called partial evaluation, and I believe someone ...
- BCS (31/41) Oct 29 2006 Closures and currying provide some of what I was looking for. However, i...
- BCS (644/669) Oct 30 2006 FWIW I realized (at midnight this morning) why this doesn't work.
This is allowed: void foo(int[] ar){} ... static int[] i = [1,2,3]; i.foo(); And this is allowed: struct I { int[] v; void foo(){} } ... I i; auto dg = &i.foo; So why no this? void foo(int[] ar){} ... static int[] i = [1,2,3]; auto dg = &i.foo; And another one: This is allowed: static int[] i = [1,2,3]; void function(int[]) fp = function void(int[] j){return;}; i.fp(); So why no this? static int[] i = [1,2,3]; i.function void(int[] j){return;}(); You may be wondering where this is all going (and what that was about a blasphemy). Well her it is: <code type="WTF!"> // a base type for derivation class Type{} // a templated derived type to store things in class TypeT(T) : Type { public T val; static TypeT!(T) opCall(T v) { auto ret = new TypeT!(T); ret.val = v; return ret; } } /* Doc ::= A:a B:b C:c = new Fig(a,b,c) | D:d E:e = new Fig(d,e) */ TypeT!(Fig) delegate() Parse_Doc(inout char[] from) { char[] tmp; // copy from tmp = from; if(auto a = Parse_A(tmp)) // try to parse an "a" if(auto b = Parse_B(tmp)) // try to parse an "b" if(auto c = Parse_C(tmp)) // try to parse an "c" { // if all's good // update what's been parsed from = tmp; return &( // make an array from the args [cast(Type delegate())a,b,c] // copy it (force off stack) .dup ) // form delegate from array // and function literal .function TypeT!(Fig)(Type delegate()[] args) { // literal calls given code auto ret = new Fig( // call args for values cast(a.typeof)args[0]().val, cast(b.typeof)args[1]().val, cast(b.typeof)args[2]().val); // place in object and return return TypeT!(ret.typeof)(ret); }; } // restore tmp tmp = from; // blah, blah, blah if(auto d = Parse_D(tmp)) if(auto e = Parse_E(tmp)) { from = tmp; return &([cast(Type delegate())d,e].dup) .function TypeT!(Fig)(Type delegate()[] args) { auto ret = new Fig( cast(d.typeof)args[0]().val, cast(e.typeof)args[1]().val); return TypeT!(ret.typeof)(ret); }; } return null; } /* A ::= "hello":v = v */ TypeT!(char[]) delegate() Parse_A(inout char[] from) { char[] tmp; tmp=from; // check for a "hello" if(from[0.."hello".length] == "hello") { // update from from = from["hello".length..$]; // return delegate returning "hello" in obj return &("hello".dup).function TypeT!(char[])() { auto ret = from[0.."hello".length]; return TypeT!(ret.typeof)(ret); }; } return null; } /// ........ </code> <script> for(auto i = brain.Remove; true; i.Lather.Rinse){} </script> WHAT IN ALL THAT IS HOLY WAS THAT!!!! It is a recursive decent parser that avoids executing actions that are never used. This would allow for actions to have side effects that would otherwise have to be undone after it is discovered that the current parse attempt fails. Rather than do each action as it is tried, each reduction function returns a delegate that has enough info to do the actions for the components and the code to use the result to execute the action. After calling the topmost Reduction function, the return value then needs to be called. auto a = Parse_Doc(SomeString); if(a is null) return; auto a().val; The important things are I would like to see both of these things added. Also, this syntax blasphemy shows that there is a use for som of these things and was to cool to not post about
Oct 27 2006
BCS wrote:This is allowed: void foo(int[] ar){} ... static int[] i = [1,2,3]; i.foo(); And this is allowed: struct I { int[] v; void foo(){} } ... I i; auto dg = &i.foo; So why no this? void foo(int[] ar){} ... static int[] i = [1,2,3]; auto dg = &i.foo; And another one: This is allowed: static int[] i = [1,2,3]; void function(int[]) fp = function void(int[] j){return;}; i.fp(); So why no this? static int[] i = [1,2,3]; i.function void(int[] j){return;}(); You may be wondering where this is all going (and what that was about a blasphemy). Well her it is: <code type="WTF!"> // a base type for derivation class Type{} // a templated derived type to store things in class TypeT(T) : Type { public T val; static TypeT!(T) opCall(T v) { auto ret = new TypeT!(T); ret.val = v; return ret; } } /* Doc ::= A:a B:b C:c = new Fig(a,b,c) | D:d E:e = new Fig(d,e) */ TypeT!(Fig) delegate() Parse_Doc(inout char[] from) { char[] tmp; // copy from tmp = from; if(auto a = Parse_A(tmp)) // try to parse an "a" if(auto b = Parse_B(tmp)) // try to parse an "b" if(auto c = Parse_C(tmp)) // try to parse an "c" { // if all's good // update what's been parsed from = tmp; return &( // make an array from the args [cast(Type delegate())a,b,c] // copy it (force off stack) .dup ) // form delegate from array // and function literal .function TypeT!(Fig)(Type delegate()[] args) { // literal calls given code auto ret = new Fig( // call args for values cast(a.typeof)args[0]().val, cast(b.typeof)args[1]().val, cast(b.typeof)args[2]().val); // place in object and return return TypeT!(ret.typeof)(ret); }; } // restore tmp tmp = from; // blah, blah, blah if(auto d = Parse_D(tmp)) if(auto e = Parse_E(tmp)) { from = tmp; return &([cast(Type delegate())d,e].dup) .function TypeT!(Fig)(Type delegate()[] args) { auto ret = new Fig( cast(d.typeof)args[0]().val, cast(e.typeof)args[1]().val); return TypeT!(ret.typeof)(ret); }; } return null; } /* A ::= "hello":v = v */ TypeT!(char[]) delegate() Parse_A(inout char[] from) { char[] tmp; tmp=from; // check for a "hello" if(from[0.."hello".length] == "hello") { // update from from = from["hello".length..$]; // return delegate returning "hello" in obj return &("hello".dup).function TypeT!(char[])() { auto ret = from[0.."hello".length]; return TypeT!(ret.typeof)(ret); }; } return null; } /// ........ </code> <script> for(auto i = brain.Remove; true; i.Lather.Rinse){} </script> WHAT IN ALL THAT IS HOLY WAS THAT!!!! It is a recursive decent parser that avoids executing actions that are never used. This would allow for actions to have side effects that would otherwise have to be undone after it is discovered that the current parse attempt fails. Rather than do each action as it is tried, each reduction function returns a delegate that has enough info to do the actions for the components and the code to use the result to execute the action. After calling the topmost Reduction function, the return value then needs to be called. auto a = Parse_Doc(SomeString); if(a is null) return; auto a().val; The important things are I would like to see both of these things added. Also, this syntax blasphemy shows that there is a use for som of these things and was to cool to not post aboutMy brain hurts from reading that. You are an evil, evil, little man, and I utterly despise you for all that dribble! And yet... despite myself, I do find it strangely compelling. :) Perhaps there ought to be a way found to at least achieve what you're after. Pretty ingenious -- but still very, very evil. -- Chris Nicholson-Sauls
Oct 27 2006
== Quote from Chris Nicholson-Sauls's articleMy brain hurts from reading that. You are an evil, evil, little man, and I utterly despise you for all that dribble! And yet... despite myself, I do find it strangely compelling. :) Perhaps there ought to be a way found to at least achieve what you're after. Pretty ingenious -- but still very, very evil. -- Chris Nicholson-SaulsIn case you are interested, if anyone working under me ever attempted to get paid for something like that, I'd give them twenty lashes with a handful of wet noodles. OTOH doing that with a code generator...
Oct 28 2006
BCS wrote:This is allowed: void foo(int[] ar){} ... static int[] i = [1,2,3]; i.foo(); And this is allowed: struct I { int[] v; void foo(){} } ... I i; auto dg = &i.foo; So why no this? void foo(int[] ar){} ... static int[] i = [1,2,3]; auto dg = &i.foo;If I am not mistaken but this is a closure. In javascript the above is: var i = [ 1,2,3,4]; var dg = function() { return foo(i); } If you have a function f( a, b ) then you wish to call it with only a single parameter g = f(x) this will yield a function g which has the following behavior: g( y ) = f( x, y ) This is currying, or partial evaluation. A good paper on this is: http://www.dina.kvl.dk/~sestoft/pebook/ Very good paper. -DavidM
Oct 28 2006
"BCS" <BCS pathlink.com> wrote in message news:ehu935$d2p$4 digitaldaemon.com...So why no this? void foo(int[] ar){} ... static int[] i = [1,2,3]; auto dg = &i.foo;As David said, this is called partial evaluation, and I believe someone has written a template library for D to do just this.. Ah, here it is, Tom S. wrote it: http://158.75.59.9/~h3/code/bind.rar Maybe that will let you do at least somewhat what you'd like to do :)So why no this? static int[] i = [1,2,3]; i.function void(int[] j){return;}();How about: static int[] i = [1,2,3]; auto f = function void(int[] j){return;}; i.f(); ?
Oct 29 2006
Closures and currying provide some of what I was looking for. However, if I understand them correctly*, they don't do exactly what I want. The closure approach would be fine if it didn't require some language magic or annotations to get the local parameters off the stack. The system I used avoids this by dynamically allocating off the heap for the context. (this is only better than annotation because it doesn’t require language support) Currying (again, if I understand correctly) will end up using some sort of runtime generated function or a wrapper delegate that manipulates the stack (another form of a closure) again this doesn’t quite have the effect I'm looking for. In this case it is because of the extra call/return overhead. Really what I want is to be able to form a delegate from any heap item and a literal code block. particularly I want the context of such a thing to be the heap item, not the enclosing scope. <ptr_type>.delegate <type>(<type_list>){<code>} FWIW, I got the program I posted working but had to use an anonymous class with the function as a method. Not as clean a solution because of the overhead involving objects, but it works. { auto c = new class{ T delegate() d; T action() { return d(); } } return &a.action; } *I haven’t read the article DavidM cited yet (lack of time n'all) == Quote from Jarrett Billingsley (kb3ctd2 yahoo.com)'s article"BCS" <BCS pathlink.com> wrote in messageI was trying to get away without the temporary. If you will notice, you suggestion is effectively the same as the example of something that works that I gave.So why no this? static int[] i = [1,2,3]; i.function void(int[] j){return;}();How about: static int[] i = [1,2,3]; auto f = function void(int[] j){return;}; i.f(); ?
Oct 29 2006
BCS wrote:This is allowed: void foo(int[] ar){} ... static int[] i = [1,2,3]; i.foo(); And this is allowed: struct I { int[] v; void foo(){} } ... I i; auto dg = &i.foo; So why no this? void foo(int[] ar){} ... static int[] i = [1,2,3]; auto dg = &i.foo;FWIW I realized (at midnight this morning) why this doesn't work. in the struct/class case the context is a pointer (32 bits) in the array case it is a pointer length pair (64 bits). It just doesn't fit in the hole. and for the strong of will here is the working version using class literals. (The grammar comes from my CS homework, that, BTW is not the impetus for the program) /* Code ::= BlatA:b " " Code:c = new Code(b,c) BlatA:b = new Code(b) BlatA ::= Thunk:t Blat:b = new BlatA(t,b) Blat ::= "!" Thunk:t Blat:b = new Blat(t,b) "*" Chunk:c Blat:b = new Blat(c,b) = new Blat() Thunk ::= T:t Thunk:c T:u = new Thunk(t, c, u); B:b Thunk:c A:a = new Thunk(b, c, a); A:a Thunk:c B:b = new Thunk(a, c, b); W:w = new Thunk(w); Chunk ::= T:t Chunk:c T:u = new Chunk(t, c, u); B:b Chunk:c B:d = new Chunk(b, c, d); A:a Chunk:c A:b = new Chunk(a, c, b); W:w = new Chunk(w); T ::= "T":t = new T(t); B ::= "B":b = new B(b); A ::= "A":a = new A(a); W ::= "W" = new W(); */ import std.stdio; void main() { char[] str = "W*TWT*W BAWBA!BBWAA!W W".dup; auto ret = Parse_Code(str); if(ret is null) writef("false"); else ret().val.dmp(); writef(\n); } /********** some utils ****/ class Type{} class TypeT(T) { public T val; this(T v){val = v;} } alias Type delegate() ret_; bool Peak(T)(inout T[] from, T[] match) { if(from.length >= match.length && from[0..match.length] == match) { from = from[match.length..$]; return true; } return false; } /* Code ::= BlatA:b " " Code:c = new Code(b,c) BlatA:b = new Code(b) */ alias TypeT!(Code) delegate() ret_Code; ret_Code Parse_Code(inout char[] from) { char[] data; data = from; if(auto b = Parse_BlatA(data)) if(Peak!(char)(data, " ")) if(auto c = Parse_Code(data)) { from = data; auto ret = new class { ret_BlatA dg_b; ret_Code dg_c; TypeT!(Code) action() { auto b = dg_b().val; auto c = dg_c().val; return new TypeT!(Code)(new Code(b,c)); } }; ret.dg_b = b; ret.dg_c = c; return &ret.action; } data = from; if(auto b = Parse_BlatA(data)) { from = data; auto ret = new class { ret_BlatA dg_b; TypeT!(Code) action() { auto b = dg_b().val; return new TypeT!(Code)(new Code(b)); } }; ret.dg_b = b; return &ret.action; } return null; } /* BlatA ::= Thunk:t Blat:b = new BlatA(t,b) */ alias TypeT!(BlatA) delegate() ret_BlatA; ret_BlatA Parse_BlatA(inout char[] from) { char[] data; data = from; if(auto t = Parse_Thunk(data)) if(auto b = Parse_Blat(data)) { from = data; auto ret = new class { ret_Thunk dg_t; ret_Blat dg_b; TypeT!(BlatA) action() { auto t = dg_t().val; auto b = dg_b().val; return new TypeT!(BlatA)(new BlatA(t,b)); } }; ret.dg_t = t; ret.dg_b = b; return &ret.action; } return null; } /* Blat ::= "!" Thunk:t Blat:b = new Blat(t,b) "*" Chunk:c Blat:b = new Blat(c,b) = new Blat() */ alias TypeT!(Blat) delegate() ret_Blat; ret_Blat Parse_Blat(inout char[] from) { char[] data; data = from; if(Peak!(char)(data, "!")) if(auto t = Parse_Thunk(data)) if(auto b = Parse_Blat(data)) { from = data; auto ret = new class { ret_Thunk dg_t; ret_Blat dg_b; TypeT!(Blat) action() { auto t = dg_t().val; auto b = dg_b().val; return new TypeT!(Blat)(new Blat(t, b)); } }; ret.dg_t = t; ret.dg_b = b; return &ret.action; } data = from; if(Peak!(char)(data, "*")) if(auto c = Parse_Chunk(data)) if(auto b = Parse_Blat(data)) { from = data; auto ret = new class { ret_Chunk dg_c; ret_Blat dg_b; TypeT!(Blat) action() { auto c = dg_c().val; auto b = dg_b().val; return new TypeT!(Blat)(new Blat(c, b)); } }; ret.dg_c = c; ret.dg_b = b; return &ret.action; } data = from; if(true) { from = data; auto ret = new class { TypeT!(Blat) action() { return new TypeT!(Blat)(new Blat()); } }; return &ret.action; } return null; } /* Thunk ::= T:t Thunk:c T:u = new Thunk(t, c, u); B:b Thunk:c A:a = new Thunk(b, c, a); A:a Thunk:c B:b = new Thunk(a, c, b); W:w = new Thunk(w); */ alias TypeT!(Thunk) delegate() ret_Thunk; ret_Thunk Parse_Thunk(inout char[] from) { char[] data; data = from; if(auto t = Parse_T(data)) if(auto c = Parse_Thunk(data)) if(auto u = Parse_T(data)) { from = data; auto ret = new class { ret_T dg_t; ret_Thunk dg_c; ret_T dg_u; TypeT!(Thunk) action() { auto t = dg_t().val; auto c = dg_c().val; auto u = dg_u().val; return new TypeT!(Thunk)(new Thunk(t, c, u)); } }; ret.dg_t = t; ret.dg_c = c; ret.dg_u = u; return &ret.action; } data = from; if(auto b = Parse_B(data)) if(auto c = Parse_Thunk(data)) if(auto a = Parse_A(data)) { from = data; auto ret = new class { ret_B dg_b; ret_Thunk dg_c; ret_A dg_a; TypeT!(Thunk) action() { auto b = dg_b().val; auto c = dg_c().val; auto a = dg_a().val; return new TypeT!(Thunk)(new Thunk(b, c, a)); } }; ret.dg_b = b; ret.dg_c = c; ret.dg_a = a; return &ret.action; } data = from; if(auto a = Parse_A(data)) if(auto c = Parse_Thunk(data)) if(auto b = Parse_B(data)) { from = data; auto ret = new class { ret_A dg_a; ret_Thunk dg_c; ret_B dg_b; TypeT!(Thunk) action() { auto a = dg_a().val; auto c = dg_c().val; auto b = dg_b().val; return new TypeT!(Thunk)(new Thunk(a, c, b)); } }; ret.dg_a = a; ret.dg_c = c; ret.dg_b = b; return &ret.action; } data = from; if(auto w = Parse_W(data)) { from = data; auto ret = new class { ret_W dg_w; TypeT!(Thunk) action() { auto w = dg_w().val; return new TypeT!(Thunk)(new Thunk(w)); } }; ret.dg_w = w; return &ret.action; } return null; } /* Chunk ::= T:t Chunk:c T:u = new Chunk(t, c, u); B:b Chunk:c B:d = new Chunk(b, c, d); A:a Chunk:c A:b = new Chunk(a, c, b); W:w = new Chunk(w); */ alias TypeT!(Chunk) delegate() ret_Chunk; ret_Chunk Parse_Chunk(inout char[] from) { char[] data; data = from; if(auto t = Parse_T(data)) if(auto c = Parse_Chunk(data)) if(auto u = Parse_T(data)) { from = data; auto ret = new class { ret_T dg_t; ret_Chunk dg_c; ret_T dg_u; TypeT!(Chunk) action() { auto t = dg_t().val; auto c = dg_c().val; auto u = dg_u().val; return new TypeT!(Chunk)(new Chunk(t, c, u)); } }; ret.dg_t = t; ret.dg_c = c; ret.dg_u = u; return &ret.action; } data = from; if(auto b = Parse_B(data)) if(auto c = Parse_Chunk(data)) if(auto d = Parse_B(data)) { from = data; auto ret = new class { ret_B dg_b; ret_Chunk dg_c; ret_B dg_d; TypeT!(Chunk) action() { auto b = dg_b().val; auto c = dg_c().val; auto d = dg_d().val; return new TypeT!(Chunk)(new Chunk(b, c, d)); } }; ret.dg_b = b; ret.dg_c = c; ret.dg_d = d; return &ret.action; } data = from; if(auto a = Parse_A(data)) if(auto c = Parse_Chunk(data)) if(auto b = Parse_A(data)) { from = data; auto ret = new class { ret_A dg_a; ret_Chunk dg_c; ret_A dg_b; TypeT!(Chunk) action() { auto a = dg_a().val; auto c = dg_c().val; auto b = dg_b().val; return new TypeT!(Chunk)(new Chunk(a, c, b)); } }; ret.dg_a = a; ret.dg_c = c; ret.dg_b = b; return &ret.action; } data = from; if(auto w = Parse_W(data)) { from = data; auto ret = new class { ret_W dg_w; TypeT!(Chunk) action() { auto w = dg_w().val; return new TypeT!(Chunk)(new Chunk(w)); } }; ret.dg_w = w; return &ret.action; } return null; } /* T ::= "T":t = new T(t); */ alias TypeT!(T) delegate() ret_T; ret_T Parse_T(inout char[] from) { char[] data = from; if(Peak(data, "T")) { from = data; auto ret = new class { TypeT!(T) action() { return new TypeT!(T)(new T()); } }; return &ret.action; } return null; } /* B ::= "B":b = new B(b); */ alias TypeT!(B) delegate() ret_B; ret_B Parse_B(inout char[] from) { char[] data = from; if(Peak(data, "B")) { from = data; auto ret = new class { TypeT!(B) action() { return new TypeT!(B)(new B()); } }; return &ret.action; } return null; } /* A ::= "A":a = new A(a); */ alias TypeT!(A) delegate() ret_A; ret_A Parse_A(inout char[] from) { char[] data = from; if(Peak(data, "A")) { from = data; auto ret = new class { TypeT!(A) action() { return new TypeT!(A)(new A()); } }; return &ret.action; } return null; } /* W ::= "W" = new W(); */ alias TypeT!(W) delegate() ret_W; ret_W Parse_W(inout char[] from) { char[] data = from; if(Peak(data, "W")) { from = data; auto ret = new class { TypeT!(W) action() { return new TypeT!(W)(new W()); } }; return &ret.action; } return null; } /*********** stuff for actions ********/ class Code { BlatA bl; Code co; this(BlatA b){bl=b; co=null;} this(BlatA b, Code c){bl=b; co=c;} void dmp() { writef("Code("); bl.dmp(); if(co !is null) { writef(" "); co.dmp; } writef(")"); } } class BlatA { Thunk th; Blat bl; this(Thunk t, Blat b){th=t;bl=b;} void dmp() { writef(" BlatA("); th.dmp(); bl.dmp(); writef(")"); } } class Blat { Thunk th; Chunk ch; Blat bl; this(){th=null;ch=null;bl=null;} this(Thunk t, Blat b){th=t;bl=b;ch=null;} this(Chunk c, Blat b){ch=c;bl=b;th=null;} void dmp() { if(bl is null) return; writef(" Blat("); if(th !is null) { writef("! "); th.dmp(); bl.dmp(); } else { writef("* "); ch.dmp(); bl.dmp(); } writef(")"); } } class Thunk { char f; Thunk th; this(T v, Thunk t, T u){th=t;f='T';} this(B b, Thunk t, A a){th=t;f='B';} this(A a, Thunk t, B b){th=t;f='A';} this(W w){th=null;f='W';} void dmp() { writef(" Thunk("); switch(f) { case 'W': W.dmp(); break; case 'T': T.dmp(); th.dmp(); T.dmp(); break; case 'B': B.dmp(); th.dmp(); A.dmp(); break; case 'A': A.dmp(); th.dmp(); B.dmp(); break; } writef(")"); } } class Chunk { char f; Chunk ch; this(T t, Chunk c, T u){ch=c;f='T';} this(B b, Chunk c, B d){ch=c;f='B';} this(A a, Chunk c, A b){ch=c;f='A';} this(W w){ch=null;f='W';} void dmp() { writef(" Chunk("); switch(f) { case 'W': W.dmp(); break; case 'T': T.dmp(); ch.dmp(); T.dmp(); break; case 'B': B.dmp(); ch.dmp(); B.dmp(); break; case 'A': A.dmp(); ch.dmp(); A.dmp(); break; } writef(")"); } } class T { this(){} static void dmp(){writef(" T ");} } class A { this(){} static void dmp(){writef(" A ");} } class B { this(){} static void dmp(){writef(" B ");} } class W { this(){} static void dmp(){writef(" W ");} }
Oct 30 2006