D function templates and type inference - d

Consider the following code:
module ftwr;
import std.regex;
import std.stdio;
import std.conv;
import std.traits;
S consume (S) (ref S data, Regex ! ( Unqual!(typeof(S.init[0])) ) rg)
{
writeln (typeid(Unqual!(typeof(S.init[0]))));
auto m = match(data, rg);
return m.hit;
}
void main()
{
auto data = "binary large object";
auto rx = regex(".*");
consume (data, rx); // this line is mentioned in the error message
}
Now, I expect the compiler to infer that consume is to be instantiated as
string consume!(string)(string, Regex!(char))
but that doesn't seem to happen. The errors are as follows:
func_template_with_regex.d(24): Error: template ftwr.consume(S) does not match any function template declaration
func_template_with_regex.d(24): Error: template ftwr.consume(S) cannot deduce template function from argument types !()(string,Regex!(char))
and I see that the parameter types are correct... I've tried some variations of function signature, like:
S consume (S) (Regex ! ( Unqual!(typeof(S.init[0])) ) rg, ref S data)
which doesn't compile also (the idea was to change the order of arguments), and
immutable(S)[] consume (S) (Regex ! ( S ) rg, ref immutable(S)[] data)
which compiles and infers the types alright. If I specify the type explicitly in the call, i.e.
consume!string(data, rx);
it also compiles and the debug writeln prints char, just as expected. Am I missing something in the inference rules, or I've just hit a bug in the compiler?
Oh yes:
$ dmd -v
DMD64 D Compiler v2.053
...

I can't say if it's a bug, but here's a workaround which doesn't force you to specify the type or change the order of arguments. Change consume's signature to:
S consume (S, U) (ref S data, Regex!U rg) if (is(U == Unqual!(typeof(S.init[0]))))

Related

Template for currying functions in D?

Is it possible to write a template or similar that can be used to automatically curry functions in D? Manually writing out all the nested delegates is killing me.
Basically, for a function f with e.g. 3 arguments, which can usually be called like f(a,b,c), I want it to be callable as f(a)(b)(c).
I know about std.functional.partial, but that's not what I want. I want to translate the function definition side, not the calling side.
I also know this is far from best practice, but I'm generating code, so bear with me.
Well, something along these lines should do the job:
template autocurry(alias what) {
import std.traits;
static if(Parameters!what.length)
auto autocurry(Parameters!what[0] arg) {
alias Remainder = Parameters!what[1 .. $];
auto dg = delegate(Remainder args) {
return what(arg, args);
};
static if(Remainder.length > 1)
return &autocurry!dg;
else
return dg;
}
else
alias autocurry = what;
}
int foo(int a, string b, float c) {
import std.stdio; writeln(a, " ", b, " ", c);
return 42;
}
string test() {
import std.stdio; writeln("called test");
return "no args";
}
void main() {
import std.stdio;
alias lol = autocurry!foo;
writeln(lol(30)("lol")(5.3));
auto partial = lol(20);
partial("wtf")(10.5);
alias t = autocurry!test;
writeln(t());
}
The idea there is pretty simple: generate the helper function based on the remaining arguments - if there are any, return the address of the helper as the delegate, otherwise, just return the delegate that calls the collected arguments. A little recursiveness handles 1+ arg cases, and the static if on the outside handles the 0 arg case by just returning the original function.
Language features to note:
eponymous templates. When a template has a member with the same name as the template (in this case, autocurry), it is automatically referenced when used.
tuple expansion. When I call what(arg, args), the args one, being a built-in tuple, is automatically expanded to create the complete argument list.
the various auto returns here (the explicit auto autocurry and the implicit delegate keyword without specifying a return type) just forward whatever other random type the body happens to return.
In the main function, I did alias lol = autocurry!foo; (I use lol as my placeholder name a lot, lol). You could also overload it at top level:
int foo(int a, string b, float c) {
import std.stdio; writeln(a, " ", b, " ", c);
return 42;
}
alias foo = autocurry!foo; // overloads the auto-curried foo with the original foo
And now you can use it directly, along side the original:
void main() {
foo(30)("lol")(5.3); // overload resolves to curried version
foo(40, "cool", 103.4); // overload resolves to original automatically
}
If you prefer a new name or the overload is up to you, either can work.
Note that each argument is liable to allocate some memory to store it for the next delegate. The GC will be responsible for cleaning that up.

Why this Clang ASTMatcher cause wrong polymorphic conversion?

I am Writing a tool using clang as frontend and matching some AST nodes.
I create ASTMatcher as follow:
void Rule_1_2_1::registerMatchers(MatchFinder *Finder)
{
DeclarationMatcher Matcher = decl(hasType(builtinType().bind("non-typedef"))).bind("non-typedef-decl");
Finder->addMatcher(Matcher, this);
}
void Rule_1_2_1::run(const MatchFinder::MatchResult &Result)
{
if (const BuiltinType *type = Result.Nodes.getNodeAs<BuiltinType>("non-typedef")) {
if (!type->isFloatingPoint() && !type->isInteger())
return;
if (const Decl *decl = Result.Nodes.getNodeAs<Decl>("non-typedef-decl")) {
DiagnosticsEngine &DE = Result.Context->getDiagnostics();
Context->report(this->CheckerName, this->ReportMsg, DE, decl->getLocStart(), DiagnosticIDs::Note);
}
}
}
But compiler gives me following errors:
/usr/include/clang/ASTMatchers/ASTMatchersInternal.h: In instantiation of ‘clang::ast_matchers::internal::PolymorphicMatcherWithParam1<MatcherT, P1, ReturnTypesF>::operator clang::ast_matchers::internal::Matcher<From>() const [with T = clang::Decl; MatcherT = clang::ast_matchers::internal::matcher_hasType0Matcher; P1 = clang::ast_matchers::internal::Matcher<clang::QualType>; ReturnTypesF = void(clang::ast_matchers::internal::TypeList<clang::Expr, clang::TypedefNameDecl, clang::ValueDecl>)]’:
../src/modules/gjb/Rule_1_2_1.cpp:18:81: required from here
/usr/include/clang/ASTMatchers/ASTMatchersInternal.h:1104:5: Error:static assertion failed: right polymorphic conversion
static_assert(TypeListContainsSuperOf<ReturnTypes, T>::value,
^~~~~~~~~~~~~
I know i am not familiar with Clang ASTMatcher and the documentation may be not very detailed.
Why this error happened?
line 18 is the line of Matcher defined.
I'm posting this as an answer since it is too long for a comment, but it is only a guess at your problem, not a definite solution.
The error looks like it occurs when you compile your matcher, not when you apply it. Which means you misused the API, not that it doesn't match anything in your code. The AST matcher API checks that you don't do things that make no sense, like filtering on an attribute that may not even exist.
In your case, you are looking for declarations that have some type. But asking a declaration what its type is doesn't necessarily make sense. The Decl class in Clang is the root of the entire declaration hierarchy and includes things like EmptyDecl (which represents simply a single semicolon outside a statement context) and StaticAssertDecl (static_assert), neither of which have a type.
Every node matcher has type information on what nodes it produces. Every narrowing matcher has information on what nodes it applies to. It is checked at compile time that these are compatible.
They interesting parts of the error message are not the unfortunately vague message, but the static_assert condition itself and the listing of the active parameter substitutions.
TypeListContainsSuperOf<ReturnTypes, T>::value is the condition, i.e. "the type list must contain a type that is a supertype of T".
But what is T, and what does the type list contain? The error message says: "In instantiation of with " and then lists substitutions. There we learn that:
T = clang::Decl
MatcherT = clang::ast_matchers::internal::matcher_hasType0Matcher
ReturnTypesF = void(clang::ast_matchers::internal::TypeList<clang::Expr, clang::TypedefNameDecl, clang::ValueDecl>)
ReturnTypes is not directly listed, but it's pretty obvious that it refers to the parameter type of ReturnTypesF, i.e. the TypeList in there.
This tells us the following things:
The decl() matcher produces clang::Decl nodes.
The matcher we're currently validating is the hasType() matcher.
The hasType() matcher can work on any of clang::Expr, clang::TypedefNameDecl, and clang::ValueDecl.
But Decl is a supertype of TypedefNameDecl and ValueDecl, not the other way around, and unrelated to Expr. This means that the static assertion fails. The decl() matcher does not produce nodes that hasType() can work with.
Depending on your exact goals, using valueDecl() instead might work.

transform each element of tuple; get that tuple

I have a tuple in D. I want to apply an element-wise operation on that tuple, and get that transformed tuple for passing into another function that accepts variadic template arguments. The execution path of the transform is defined at compile time, but the actual value is not.
The purpose of this is similar to the template mechanism used in C++'s bind construct, for determining where to use placeholders/passed arguments and where to use stored arguments at compile time.
How do I accomplish this?
this is the first time in D I've ever missed a feature in C++11's template system: the pack/unpack operator - please make me not feel bad :-(
EDIT: Ended up using mixins, because apparently any generic programming solution you want can be solved by using them. May answer with them if no one comes up with anything more elegant than taking D's ridiculously powerful jackhammer-of-a-generic-programming-tool to it.
The element of a tuple can be anything that a template alias parameter can be. However, run-time expressions cannot be alias parameters - they are evaluated at compile time. Thus, it is not possible to transform a tuple using a transformation that runs at compile-time (barring workarounds such as where the transformation defines a #property function that returns the result).
If the expression and transformation can be evaluated at compile-time, see staticMap from std.typetuple.
If I understand the question right, then this is possible but it's a highly experimental (undocumented and not guaranteed to always work) feature:
import std.stdio;
import std.traits;
import std.typetuple;
ReturnType!Call Delay(alias Call, alias arg)() { return Call(arg); }
template Map(alias Call, args...)
{
static if (args.length > 1)
alias Map = TypeTuple!(Delay!(Call, args[0]),Map!(Call, args[1..$]));
else
alias Map = Delay!(Call, args[0]);
}
int square(int arg)
{
return arg * arg;
}
void print(int res1, int res2)
{
writefln("%s %s", res1, res2); // writes '25 100'
}
void test(Args...)(Args args)
{
print(Map!(square, args));
}
void main()
{
int x = 5;
int y = 10;
test(x, y);
}
Originally asked here: Mapping variadic template arguments in D

Sending a templated function as an argument to a templated function in D

I'm trying to send D's sort function as a template argument to the pipe function. When I use sort without template arguments it works:
import std.stdio,std.algorithm,std.functional;
void main()
{
auto arr=pipe!(sort)([1,3,2]);
writeln(arr);
}
However, when I try to use sort with a template argument:
import std.stdio,std.algorithm,std.functional;
void main()
{
auto arr=pipe!(sort!"b<a")([1,3,2]);
writeln(arr);
}
I get an error - main.d(5): Error: template instance sort!("b<a") sort!("b<a") does not match template declaration sort(alias less = "a < b",SwapStrategy ss = SwapStrategy.unstable,Range)
Why does it happen? sort!"b<a" works on it's own, and it has the same arguments and return types as sort, so why does pipe accept sort but not sort!"b<a"? And is there a correct syntax for what I try to do?
UPDATE
OK, I've tried to wrap the sort function. The following code works:
import std.stdio,std.algorithm,std.functional,std.array;
template mysort(string comparer)
{
auto mysort(T)(T source)
{
sort!comparer(source);
return source;
}
}
void main()
{
auto arr=pipe!(mysort!"b<a")([1,3,2]);
writeln(arr);
}
So why doesn't the original version work? is this because of the extra template parameters sort takes?
Yes it's because of the extra template parameters — specifically the Range parameter. The problem can be reduced to
size_t sort2(alias f, Range)(Range range)
{
return 0;
}
alias sort2!"b<a" u;
The instantiation sort!"b<a" will fail because the Range is not determined. The function call sort2!"b<a"([1,2,3]) works because the parameter [1,2,3] can tell the compiler the type Range is int[]. This is known as "implicit function template instantiation (IFTI)". But IFTI only works when it is used as a function. In your use case, sort!"b<a" is instantiated without providing all parameters, thus the error.
This can be fixed by making the input a function literal, which is just similar to your mysort solution:
auto arr = pipe!(x => sort!"b<a"(x))([1,3,2]);
Or you could provide all required template parameters. This makes the code very unreadable though.
auto arr = pipe!(sort!("b<a", SwapStrategy.unstable, int[]))([1,3,2]);

Functor Structure extension and Multiple Ascription in SML

Is there any way in Standard ML to make a functor output a structure which has all of the functionality of the passed in structure, plus any new functionality.
In a similar way, is it possible to do multiple ascription? In the case of the above it would be immediately useful because you could ascribe the output of the functor to both the signature of the original structure and another signature which specifies the new functionality.
I understand the implications of doing such a thing, and why it might be a bad idea. Currently I've just been keeping a copy of the passed in structure within the functor output - but this means you have a long chain of "Foo.Bar.func" to access the base functionality.
Thanks
Say I wanted to make a signature for "TestUp". Is there any way to do this without duplicating the contents of the "TEST" into a new signature?
If I understand your question correctly then you are looking for the include keyword, which will include the definition of a previous signature into a new and thus extending the signature with the previous definitions.
signature TEST_EXT =
sig
include TEST
val beep1 : meep -> unit
end
functor TestUp_EXT(T : TEST) : TEST_EXT =
struct
open T
fun localFun s = beep (10, s)
val beep1 = localFun
end
structure Test2_EXT = TestUp_EXT (Test);
Test2_EXT.beep (5, "EXT: Hi");
Test2_EXT.beep1 "Hi";
print (Int.toString (Test2.rand ()) ^ "\n");
(* This will fail as the signature doesn't define this function,
however as seen the function can easily be used within the functor as
expected *)
(* Test2_EXT.localFun "Hi"; *)
You can use open to bring the contents of a structure into the current scope. If used inside another structure (or functor), it'll do what I believe it is you want.
An example can be seen here:
signature TEST =
sig
type meep;
val beep : int * meep -> unit;
end;
structure Test : TEST =
struct
type meep = string
fun beep (0, _) = ()
| beep (n, s) = (print (s^"\n"); beep (n-1, s));
end;
functor TestUp (T : TEST) =
struct
open T
fun rand () = 4
end;
structure Test2 = TestUp (Test);
Test.beep (5, "Hello");
Test2.beep (5, "Hi");
print (
Int.toString (Test2.rand ()) ^ "\n"
);