www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Function template argument deduction

reply Paul Backus <snarwin gmail.com> writes:
I'm playing around with functional programming in D, and have run 
into a problem with the following code:

--- list.d
import std.variant: Algebraic, This, visit;
import std.typecons: Tuple, tuple;

struct Nil {}
alias List(T) = Algebraic!(
     Nil,
     Tuple!(T, "head", This*, "tail")
);
alias Cons(T) = Tuple!(T, "head", List!T*, "tail");

List!T* list(T)(T[] items...)
{
     if (items.length == 0)
         return new List!T(Nil());
     else
         return new List!T(Cons!T(items[0], list(items[1..$])));
}

string list2string(T)(List!T list)
{
     import std.stdio: write;

     list.visit!(
         (Nil _) => "nil",
         (Cons!T cons) => "cons(" ~ cons.head ~ ", " ~ 
list2string(*cons.tail) ~ ")"
     );
}


unittest {
     List!int* myList = list(1, 2, 3);

     assert(list2string(*myList) == "cons(1, cons(2, cons(3, 
nil)))");
}

---

The error I get is "template list.list2string cannot deduce 
function from argument types [...]"; i.e., the compiler can't 
figure out that T is supposed to be 'int'.

My question is, why not? Is there anything I can do to get this 
to work? The compiler seems to be able to handle this sort of 
thing in general (e.g., it can deduce 'int' from an argument of 
type 'Tuple!(int, int)'), so what makes this particular case fail?
Apr 06 2018
parent reply Uknown <sireeshkodali1 gmail.com> writes:
On Saturday, 7 April 2018 at 05:10:05 UTC, Paul Backus wrote:
 I'm playing around with functional programming in D, and have 
 run into a problem with the following code:

 [...]
I don't see the error you are talking about: https://run.dlang.io/is/XWPIc1 Are you using the latest compiler?
Apr 06 2018
parent reply Paul Backus <snarwin gmail.com> writes:
On Saturday, 7 April 2018 at 05:46:07 UTC, Uknown wrote:
 I don't see the error you are talking about: 
 https://run.dlang.io/is/XWPIc1

 Are you using the latest compiler?
Compile with -unittest. And yes; I'm using DMD 2.079.0.
Apr 06 2018
parent reply Uknown <sireeshkodali1 gmail.com> writes:
On Saturday, 7 April 2018 at 05:58:10 UTC, Paul Backus wrote:
 On Saturday, 7 April 2018 at 05:46:07 UTC, Uknown wrote:
 I don't see the error you are talking about: 
 https://run.dlang.io/is/XWPIc1

 Are you using the latest compiler?
Compile with -unittest. And yes; I'm using DMD 2.079.0.
Now I feel silly. Anyway, I played around with your code. One thing I found was `cons.head` returns a `T`, which can't be appended to a string. You can fix this with `cons.head.to!string`, where `to` is from std.conv. I'm not sure why IFTI isn't deducing `T` to be `int` though. Hopefully some one else can help out here. What I did notice though is that when `string list2string(T)(List!T list)` was changed to `string list2string(T)(VariantN!(16LU, Nil, Tuple!(T, "head", This*, "tail")) list)` The compiler correctly deduce `T` to be `int`
Apr 06 2018
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 04/06/2018 11:26 PM, Uknown wrote:
 On Saturday, 7 April 2018 at 05:58:10 UTC, Paul Backus wrote:
 On Saturday, 7 April 2018 at 05:46:07 UTC, Uknown wrote:
 I don't see the error you are talking about:
 https://run.dlang.io/is/XWPIc1

 Are you using the latest compiler?
Compile with -unittest. And yes; I'm using DMD 2.079.0.
Now I feel silly. Anyway, I played around with your code. One thing I found was `cons.head` returns a `T`, which can't be appended to a string. You can fix this with `cons.head.to!string`, where `to` is from std.conv. I'm not sure why IFTI isn't deducing `T` to be `int` though. Hopefully some one else can help out here. What I did notice though is that when `string list2string(T)(List!T list)` was changed to `string list2string(T)(VariantN!(16LU, Nil, Tuple!(T, "head", This*, "tail")) list)` The compiler correctly deduce `T` to be `int`
I played with it as well by hacking the following: string list2string(L)(L list) { import std.traits : TemplateArgsOf; alias T = TemplateArgsOf!L[2][0]; // ... } I hit the same problem that you describe. (Additionally, list2string does not return anything.) Ali
Apr 06 2018
prev sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Saturday, 7 April 2018 at 06:26:24 UTC, Uknown wrote:
 What I did notice though is that when
 `string list2string(T)(List!T list)` was changed to
 `string list2string(T)(VariantN!(16LU, Nil, Tuple!(T, "head", 
 This*, "tail")) list)`
 The compiler correctly deduce `T` to be `int`
Interesting. Looks like this is an issue with aliases, because I get the error with this code too: --- test.d import std.typecons: Tuple, tuple; alias Pair(T) = Tuple!(T, T); void foo(T)(Pair!T p) { return; } unittest { Pair!int x = tuple(1, 2); foo(x); } ---
Apr 07 2018
parent Paul Backus <snarwin gmail.com> writes:
On Saturday, 7 April 2018 at 14:02:55 UTC, Paul Backus wrote:
 Interesting. Looks like this is an issue with aliases, because 
 I get the error with this code too:

 --- test.d
 import std.typecons: Tuple, tuple;

 alias Pair(T) = Tuple!(T, T);

 void foo(T)(Pair!T p)
 {
     return;
 }

 unittest {
     Pair!int x = tuple(1, 2);
     foo(x);
 }
 ---
Looks like this is the same problem described in issue 1807: https://issues.dlang.org/show_bug.cgi?id=1807 I'm not sure what D was like when Martin Nowak made the most recent comment on that issue, in 2012, but alias templates do have their own dedicated language construct now, so maybe this is worth revisiting.
Apr 07 2018