www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to hide a function return type in order to wrap several functions

reply tastyminerals <tastyminerals gmail.com> writes:
This is rather a generic implementation question not necessarily 
related to D but I'd like to get some opinions.
I have a collection of functions that all have the same input, a 
string. The output however is different and depending on what the 
function does it can be ulong, double or bool. The problem is 
that for each line of text I'd like to apply all these functions, 
collect the results and write them into some file. For example,

auto numberOfPunctChars(string text)
{
     const ulong cnt = text.filter!(c => c.isPunctuation).count;
     return Feature!ulong("numberOfPunctChars", cnt);
}


auto ratioOfDigitsToChars(string text)
{
     const double digits = numberOfDigitChars(text).val.to!double;
     const double alphas = numberOfAlphaChars(text).val.to!double;
     const double ratio = digits / (alphas > 0 ? alphas : digits);
     return Feature!double("ratioOfDigitsToChars", ratio);
}

auto hasUnbalancedParens(string text)
{
     const bool isBalanced = balancedParens(text, '(', ')') && 
balancedParens(text, '[', ']');
     return Feature!bool("hasUnbalancedParens", !isBalanced);
}

As you can see, I created a templated Feature struct. This does 
not help much because I also want to create an associative array 
of ["functionName": &numberOfPunctChars]. How can I define such 
an array when "Feature!T function(string)[string] allFuns" 
requires defining T beforehand and using auto is not possible?

I was thinking of having a Feature struct with 3 fiels of ulong, 
double and bool members but then each Feature init would look 
ugly imho "Feature("name", null, 1.5, null)". There should be a 
another way.
Sep 27 2020
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Sunday, 27 September 2020 at 18:54:11 UTC, tastyminerals wrote:
 This is rather a generic implementation question not 
 necessarily related to D but I'd like to get some opinions.
 I have a collection of functions that all have the same input, 
 a string. The output however is different and depending on what 
 the function does it can be ulong, double or bool. The problem 
 is that for each line of text I'd like to apply all these 
 functions, collect the results and write them into some file. 
 For example,

 [...]

 As you can see, I created a templated Feature struct. This does 
 not help much because I also want to create an associative 
 array of ["functionName": &numberOfPunctChars]. How can I 
 define such an array when "Feature!T function(string)[string] 
 allFuns" requires defining T beforehand and using auto is not 
 possible?

 I was thinking of having a Feature struct with 3 fiels of 
 ulong, double and bool members but then each Feature init would 
 look ugly imho "Feature("name", null, 1.5, null)". There should 
 be a another way.
You can use an Algebraic [1] or SumType [2] for this: alias Feature = SumType!(ulong, double, bool); Feature numberOfPunctChars(string text) { // ... return Feature(cnt); } Feature ratioOfDigitsToChars(string text) { // ... return Feature(ratio); } Feature hasUnbalancedParens(string text) { // ... return Feature(!isBalanced); } [1] http://dpldocs.info/experimental-docs/std.variant.Algebraic.html [2] https://code.dlang.org/packages/sumtype
Sep 27 2020
parent tastyminerals <tastyminerals gmail.com> writes:
On Sunday, 27 September 2020 at 20:03:21 UTC, Paul Backus wrote:
 On Sunday, 27 September 2020 at 18:54:11 UTC, tastyminerals 
 wrote:
 [...]
You can use an Algebraic [1] or SumType [2] for this: alias Feature = SumType!(ulong, double, bool); Feature numberOfPunctChars(string text) { // ... return Feature(cnt); } Feature ratioOfDigitsToChars(string text) { // ... return Feature(ratio); } Feature hasUnbalancedParens(string text) { // ... return Feature(!isBalanced); } [1] http://dpldocs.info/experimental-docs/std.variant.Algebraic.html [2] https://code.dlang.org/packages/sumtype
Nice, thanks. Never used it, shall take a look.
Oct 03 2020
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 9/27/20 11:54 AM, tastyminerals wrote:

 I have a collection of functions that all have the same input, a string.
 The output however is different and depending on what the function does
 it can be ulong, double or bool.
The following approach overcomes the different return type issue by creating delegates that take string and return string: auto numberOfPunctChars(string text) { return 42; } auto ratioOfDigitsToChars(string text) { return 1.5; } auto hasUnbalancedParens(string text) { return true; } struct FeatureSet { alias TakesString = string delegate(string); TakesString[] features; void register(Func)(Func func) { // Here, we convert from a function returning any type // to a delegate returning string: features ~= (string s) { import std.conv : text; return func(s).text; }; } // Here, we apply all feature delegates and put the outputs // into the provided output range. void apply(O)(ref O outputRange, string s) { import std.format : formattedWrite; import std.algorithm : map; outputRange.formattedWrite!"%-(%s\n%|%)"(features.map!(f => f(s))); } } void main() { auto featureSet = FeatureSet(); featureSet.register(&numberOfPunctChars); featureSet.register(&ratioOfDigitsToChars); featureSet.register(&hasUnbalancedParens); // lockingTextWriter() just makes an output range from // an output stream. import std.stdio; auto output = stdout.lockingTextWriter; featureSet.apply(output, "hello world"); // As another example, you can use an Appender as well: import std.array : Appender; auto app = Appender!(char[])(); featureSet.apply(app, "goodbye moon"); writefln!"Appender's content:\n%s"(app.data); } Ali
Sep 27 2020
parent tastyminerals <tastyminerals gmail.com> writes:
On Sunday, 27 September 2020 at 22:55:14 UTC, Ali Çehreli wrote:
 On 9/27/20 11:54 AM, tastyminerals wrote:

 [...]
input, a string.
 [...]
function does
 [...]
[...]
Thank you. Quite an inspirational example with delegates.
Oct 03 2020