June 10, 2015 Re: Self-referential tuples? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On 06/10/2015 01:48 AM, Timon Gehr wrote: > On 06/10/2015 01:04 AM, Andrei Alexandrescu wrote: >> On 6/9/15 3:58 PM, Timon Gehr wrote: >>> On 06/09/2015 05:28 PM, Andrei Alexandrescu wrote: >>>> Following the use of This in Algebraic >>>> (https://github.com/D-Programming-Language/phobos/pull/3394), we can >>>> apply the same idea to Tuple, thus allowing one to create >>>> self-referential types with ease. >>>> >>>> Consider: >>>> >>>> // A singly-linked list is payload + pointer to list >>>> alias List(T) = Tuple!(T, This*); >>>> >>>> // A binary tree is payload + two children >>>> alias Tree(T) = Tuple!(T, This*, This*); >>>> // or >>>> alias Tree(T) = Tuple!(T, "payload", This*, "left", This*, "right"); >>>> >>>> // A binary tree with payload only in leaves >>>> alias Tree2(T) = Algebraic!(T, Tuple!(This*, This*)); >>>> >>>> Is there interest in this? Other application ideas to motivate the >>>> addition? >>>> >>>> >>>> Andrei >>> >>> Well, the issue is with this kind of use case: >>> >>> alias List(T)=Algebraic!(Tuple!(),Tuple!(T,This*)); >> >> So a list is either nothing, or a head and a tail. What is the problem >> here? -- Andrei > > It's about which type 'This' refers to. Is it the Algebraic or the > Tuple? I assume here it would be the algebraic, which is expected, but > it can get non-obvious quickly especially when e.g. a template parameter > is a recursive tuple and the template uses the type in an Algebraic. > It's just a mess. E.g. what happens if you do List!(Tree!int)? > ReplaceType would need to treat Tuples specially, and then you lose the > other semantics even though it might sometimes be needed. 'This' is a > cute hack, but it doesn't replace a proper template fixpoint operator. If I'm not mistaken Algebraic already suffers from this kind of "This replacement hijacking". alias List(T)=Algebraic!(Tuple!(),Tuple!(T,std.variant.This*)); List!(List!(int)) // not a list of list of int, is it? | |||
June 10, 2015 Re: Self-referential tuples? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 06/10/2015 01:52 AM, Andrei Alexandrescu wrote:
> On 6/9/15 4:43 PM, Idan Arye wrote:
>>
>> The `This*` here is not mapped to `Algebraic!(Tuple!(),Tuple!(T,This*))`
>> - it's mapped to the closest containing tuple, `Tuple!(T,This*)`. This
>> means that the tail is not a list - it's a head and a tail. The list is
>> either empty or infinite.
>>
>> At any rate, I think this feature is useful enough even if it doesn't
>> support such use cases. You can always declare a list as a regular
>> struct...
>
> Way ahead of you :o). Algebraic would use std.variant.This, whereas
> Tuple would use std.typecons.This. So you get to choose. -- Andrei
I generally assume that the same identifier in the same scope of the same code snippet refers to the same symbol, but sure, this avoids this specific problem, but not others.
| |||
June 10, 2015 Re: Self-referential tuples? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On Tuesday, 9 June 2015 at 23:48:05 UTC, Timon Gehr wrote:
> 'This' is a cute hack, but it doesn't replace a proper template fixpoint operator.
Could you explain this a bit more, maybe using some pseudo-D for your proposed template fixpoint operator? Thanks.
I don't think I'd need such a thing for the JSON AST example, since it isn't parameterized by type. There, the D mapping looks clumsy because, as Andrei noticed, the 'fields' are not named. If you map the OCaml straight to D you get something like what I write below, and you want both the Kind and the internal structure to be non-private so you can write functions which work on them. It's the same as tagged unions/variants in other languages but so much easier to use.
enum Kind {
Bool,
Number,
String,
Null,
Array,
Object
}
alias JSON = JSONStruct *;
struct JSONStruct {
public:
Kind kind;
union {
bool jsonBool;
double jsonNumber;
string jsonString;
JSON[] jsonArray;
JSON[string] jsonObject;
}
this(Kind kind, bool jsonBool)
in { assert(kind == Kind.Bool); }
body {
kind = Kind.Bool;
this.jsonBool = jsonBool;
}
this(Kind kind, double jsonNumber)
in { assert(kind == Kind.Number); }
body {
kind = Kind.Number;
this.jsonNumber = jsonNumber;
}
this(Kind kind, string jsonString)
in { assert(kind == Kind.String); }
body {
kind = Kind.String;
this.jsonString = jsonString;
}
this(Kind kind)
in { assert(kind == Kind.Null); }
body {
kind = Kind.Null;
}
this(Kind kind, JSON[] jsonArray)
in { assert(kind == Kind.Array); }
body {
kind = Kind.Array;
this.jsonArray = jsonArray;
}
this(Kind kind, JSON[string] jsonObject)
in { assert(kind == Kind.Object); }
body {
kind = Kind.Object;
this.jsonObject = jsonObject;
}
}
| |||
June 10, 2015 Re: Self-referential tuples? | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Brian Rogoff | On 06/10/2015 05:52 PM, Brian Rogoff wrote: > On Tuesday, 9 June 2015 at 23:48:05 UTC, Timon Gehr wrote: >> 'This' is a cute hack, but it doesn't replace a proper template >> fixpoint operator. > > Could you explain this a bit more, maybe using some pseudo-D for your > proposed template fixpoint operator? Thanks. > ... import std.typecons, std.variant; alias List(T)=Algebraic!(Tuple!(),Tuple!(T,List!T*)); void main(){ List!int l; } The following error message is the reason why the 'This' hack is necessary: tt.d(3): Error: template instance Algebraic!(Tuple!(), Tuple!(int, List!int*)) recursive template expansion tt.d(6): Error: template instance tt.List!int error instantiating The simple solution is to just not have this error. The code can easily be given an unambiguous meaning. | |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply