Thread overview
Function template argument deduction
Apr 07, 2018
Paul Backus
Apr 07, 2018
Uknown
Apr 07, 2018
Paul Backus
Apr 07, 2018
Uknown
Apr 07, 2018
Ali Çehreli
Apr 07, 2018
Paul Backus
Apr 07, 2018
Paul Backus
April 07, 2018
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?
April 07, 2018
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?
April 07, 2018
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.
April 07, 2018
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`
April 06, 2018
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

April 07, 2018
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);
}
---
April 07, 2018
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.