August 25, 2017 Re: Article: Writing Julia style multiple dispatch code in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to data pulverizer | On Thursday, 24 August 2017 at 23:50:21 UTC, data pulverizer wrote: > > ``` > double density(D: UnivariateDistribution!Discrete, U = getVariateType!D, T = GetDistributionParameterType!D)(D d, U x) > if(!is(D == Poisson!T)) > { > assert(false, "density function unimplemented for this distribution: " ~ D.stringof); > } > > double density(D: UnivariateDistribution!Continuous, U = getVariateType!D, T = GetDistributionParameterType!D)(D d, U x) > if(!is(D == Gamma!T) && !is(D == Gaussian!T) && !is(D == Uniform!T) && !is(D == Exponential!T)) > { > assert(false, "density function unimplemented for this distribution: " ~ D.stringof); > } > What you seem concerned about here is how to produce a meaningful error message for distribution that you do not have implementations for. A slightly more elegant solution would be to pack the structs into an AliasSeq and then use something like !allSatisfies to test them all. I'm sure there's a more elegant solution, but that's the first thing I thought of. > > immutable class(T...){...} > > that this class can only create immutable objects without having to write immutable everywhere and or a UDA, but making every member immutable accomplishes the same thing. > What you're looking for is an immutable constructor: class C { this() immutable; } |
August 25, 2017 Re: Article: Writing Julia style multiple dispatch code in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | On Friday, 25 August 2017 at 00:35:24 UTC, jmh530 wrote: > What you seem concerned about here is how to produce a meaningful error message for distribution that you do not have implementations for. A slightly more elegant solution would be to pack the structs into an AliasSeq and then use something like !allSatisfies to test them all. I'm sure there's a more elegant solution, but that's the first thing I thought of. > Andrei suggested allSatisfies that as an alternative approach to a Union keyword similar to Julia, at the time I was still stuck on how cool having a Union keyword like Julia's in D would be. >> >> immutable class(T...){...} > > What you're looking for is an immutable constructor: > > class C > { > this() immutable; > } Aha, thanks! |
August 25, 2017 Re: Article: Writing Julia style multiple dispatch code in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to data pulverizer | On Friday, 25 August 2017 at 01:04:31 UTC, data pulverizer wrote: > [snip] With respect to your point about immutability, you might be interested in the parameterize function in dstats.distrib. I hadn't noticed that was there, but I think it accomplishes, to a limited extent, the behavior of what you want. It returns a delegate with the values of the distribution fixed in there. Along the same lines, I think below is how I would set it up, rather than the mixin approach I discussed above. While it does not currently work with the parametrize funciton currently, I believe that with some simple adjustments it could. import std.stdio : writeln; struct Normal { import dstats : normalCDF, normalCDFR, normalPDF, invNormalCDF; alias cdf = normalCDF; alias cdfr = normalCDFR; alias pdf = normalPDF; alias density = pdf; alias icdf = invNormalCDF; } struct LogNormal { import dstats : logNormalCDF, logNormalCDFR, logNormalPDF; alias cdf = logNormalCDF; alias cdfr = logNormalCDFR; alias pdf = logNormalPDF; alias density = pdf; //no icdf for LogNormal in dstats } private void hasMemberCheck(alias T, string x)() { import std.traits : hasMember; static assert(hasMember!(T, x), T.stringof ~ " must have " ~ x ~" member to call " ~ x ~ " function"); } auto cdf(alias T, U...)(U u) { hasMemberCheck!(T, "cdf"); return T.cdf(u); } auto pdf(alias T, U...)(U u) { hasMemberCheck!(T, "pdf"); return T.pdf(u); } auto pmf(alias T, U...)(U u) { hasMemberCheck!(T, "pmf"); return T.pmf(u); } auto cdfr(alias T, U...)(U u) { hasMemberCheck!(T, "cdfr"); return T.cdfr(u); } auto density(alias T, U...)(U u) { hasMemberCheck!(T, "density"); return T.density(u); } auto icdf(alias T, U...)(U u) { hasMemberCheck!(T, "icdf"); return T.icdf(u); } void main() { writeln(Normal.cdf(0.5, 0.0, 1.0)); writeln(cdf!Normal(0.5, 0.0, 1.0)); writeln(icdf!Normal(cdf!Normal(0.5, 0.0, 1.0), 0.0, 1.0)); writeln(LogNormal.cdf(0.5, 0.0, 1.0)); writeln(cdf!LogNormal(0.5, 0.0, 1.0)); //writeln(icdf!LogNormal(cdf!LogNormal(0.5, 0.0, 1.0), 0.0, 1.0)); //error } |
August 25, 2017 Re: Article: Writing Julia style multiple dispatch code in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | On Friday, 25 August 2017 at 14:30:03 UTC, jmh530 wrote:
> On Friday, 25 August 2017 at 01:04:31 UTC, data pulverizer wrote:
>> [snip]
>
> With respect to your point about immutability, you might be interested in the parameterize function in dstats.distrib. I hadn't noticed that was there, but I think it accomplishes, to a limited extent, the behavior of what you want. It returns a delegate with the values of the distribution fixed in there.
>
> Along the same lines, I think below is how I would set it up, rather than the mixin approach I discussed above. While it does not currently work with the parametrize funciton currently, I believe that with some simple adjustments it could.
>
>
> import std.stdio : writeln;
>
> struct Normal
> { ...
Your wrapping strategy looks sensible though I would probably generate them all using string mixins.
|
August 25, 2017 Re: Article: Writing Julia style multiple dispatch code in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to data pulverizer | On Friday, 25 August 2017 at 16:01:27 UTC, data pulverizer wrote:
>
> Your wrapping strategy looks sensible though I would probably generate them all using string mixins.
That might require less maintenance going forward.
|
August 25, 2017 Re: Article: Writing Julia style multiple dispatch code in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to data pulverizer | On Friday, 25 August 2017 at 16:01:27 UTC, data pulverizer wrote: > > Your wrapping strategy looks sensible though I would probably generate them all using string mixins. See below. I haven't implemented the random variables yet, but otherwise it seems to be working well. There is some trickiness with deprecated stuff that I had to hard code, but other than that it's pretty generic. Also, I think it is ignoring my check to only include public/export stuff. Not sure why that is. module distribAlt; private template isMemberOf(alias T, string x) { import std.traits : hasMember; enum bool isMemberOf = hasMember!(T, x); } private void hasMemberCheck(alias T, string x)() { static assert(isMemberOf!(T, x), T.stringof ~ " must have " ~ x ~" member to call " ~ x ~ " function"); } private string genStructInternals(string funcName, string structName)() { import dstats.distrib; import std.array : appender; import std.algorithm.searching : endsWith; enum spaces = " "; auto aliasBuf = appender!string(); auto importBuf = appender!string(); enum string invName = "inv" ~ structName; enum bool anyPDForPMF = false; importBuf.put(spaces); importBuf.put("import dstats.distrib : "); foreach(member; __traits(allMembers, dstats.distrib)) { static if (__traits(getProtection, member) == "public" || __traits(getProtection, member) == "export") { import std.algorithm.searching : startsWith, findSplitAfter; import std.string : toLower; static if (startsWith(member, funcName)) { enum string memberAfter = findSplitAfter(member, funcName)[1]; enum string lowerMemberAfter = toLower(memberAfter); importBuf.put(member ~ ", "); aliasBuf.put(spaces); aliasBuf.put("alias " ~ lowerMemberAfter ~ " = " ~ member ~ ";"); aliasBuf.put("\n"); static if ((lowerMemberAfter == "pdf") || (lowerMemberAfter == "pmf")) { aliasBuf.put(spaces); aliasBuf.put("alias density = " ~ lowerMemberAfter ~ ";"); aliasBuf.put("\n"); } } else static if (startsWith(member, invName)) { enum string memberAfter = findSplitAfter(member, invName)[1]; importBuf.put(member ~ ", "); aliasBuf.put(spaces); aliasBuf.put("alias i" ~ toLower(memberAfter) ~ " = " ~ member ~ ";"); aliasBuf.put("\n"); } } } if (endsWith(importBuf.data, ", ")) { string importOut = importBuf.data[0 .. ($ - (", ".length))] ~";\n"; if (endsWith(aliasBuf.data, "\n")) return importOut ~ aliasBuf.data[0 .. ($ - ("\n").length)]; else assert(0, "No relevant functions in dstats.distrib"); } else { assert(0, "No relevant functions in dstats.distrib"); } } private string toLowerFirst(string name)() { import std.string : toLower; import std.conv : to; string firstLetter = name[0].toLower.to!string; return firstLetter ~ name[1 .. $]; } private string toUpperFirst(string name)() { import std.string : toUpper; import std.conv : to; string firstLetter = name[0].toUpper.to!string; return firstLetter ~ name[1 .. $]; } private template GenDistStruct(string name) { const char[] GenDistStruct = "///"~ "\n" ~ "struct " ~ toUpperFirst!(name) ~ "\n" ~ "{\n" ~ genStructInternals!(name, toUpperFirst!(name)) ~ "\n" ~ "}"; } string GenDistStructs() { import dstats.distrib; import std.array : appender; import std.algorithm.searching : startsWith, endsWith, canFind, findSplitBefore, findSplitAfter; string[__traits(allMembers, dstats.distrib).length] createdStructs; size_t i; auto structsBuf = appender!string(); foreach(member; __traits(allMembers, dstats.distrib)) { static if (__traits(getProtection, member) == "public" || __traits(getProtection, member) == "export") { static if ((member.endsWith("PDF") || member.endsWith("PMF") || member.endsWith("CDF") || member.endsWith("CDFR"))) { static if (member.endsWith("PDF")) enum string memberBefore = findSplitBefore(member, "PDF")[0]; else static if (member.endsWith("PMF")) enum string memberBefore = findSplitBefore(member, "PMF")[0]; else static if (member.endsWith("CDF")) enum string memberBefore = findSplitBefore(member, "CDF")[0]; else static if (member.endsWith("CDFR")) enum string memberBefore = findSplitBefore(member, "CDFR")[0]; static if (member.startsWith("inv")) enum string newMember = toLowerFirst!(findSplitAfter(memberBefore, "inv")[1]); else enum string newMember = memberBefore; static if (member != "chiSqrCDF" && member != "chiSqrCDFR" && member != "invChiSqrCDFR" && member != "invChiSqCDFR") //Deprecated: Easiest way I found to fix it { if (i == 0 || !(createdStructs[0 .. i].canFind(newMember))) { structsBuf.put(GenDistStruct!newMember); structsBuf.put("\n"); createdStructs[i] = newMember; i++; } } } } } return structsBuf.data; } mixin(GenDistStructs()); private template GenDistFunc(string name) { const char[] GenDistFunc = "auto " ~ name ~ "(alias T, U...)(U u)\n" ~ "{\n" ~ ` hasMemberCheck!(T, "` ~ name ~ `");` ~ "\n" ~ " return T." ~ name ~ "(u);\n" ~ "}"; } mixin(GenDistFunc!("pdf")); mixin(GenDistFunc!("pmf")); mixin(GenDistFunc!("cdf")); mixin(GenDistFunc!("cdfr")); mixin(GenDistFunc!("icdf")); mixin(GenDistFunc!("density")); void main() { import std.stdio : writeln; writeln(Normal.cdf(0.5, 0.0, 1.0)); writeln(cdf!Normal(0.5, 0.0, 1.0)); writeln(icdf!Normal(cdf!Normal(0.5, 0.0, 1.0), 0.0, 1.0)); writeln(LogNormal.cdf(0.5, 0.0, 1.0)); writeln(cdf!LogNormal(0.5, 0.0, 1.0)); } |
August 26, 2017 Re: Article: Writing Julia style multiple dispatch code in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | On Friday, 25 August 2017 at 20:54:05 UTC, jmh530 wrote:
> See below. I haven't implemented the random variables yet, but otherwise it seems to be working well. There is some trickiness with deprecated stuff that I had to hard code, but other than that it's pretty generic. Also, I think it is ignoring my check to only include public/export stuff. Not sure why that is.
>
> module distribAlt;
> ...
Wow, I didn't realise that you'd go off and work on it. You need to start a package for it! I'll bookmark this one as a little reminder of mixin techniques.
|
August 26, 2017 Re: Article: Writing Julia style multiple dispatch code in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to data pulverizer | On Saturday, 26 August 2017 at 02:14:59 UTC, data pulverizer wrote:
> On Friday, 25 August 2017 at 20:54:05 UTC, jmh530 wrote:
>> See below. I haven't implemented the random variables yet, but otherwise it seems to be working well. There is some trickiness with deprecated stuff that I had to hard code, but other than that it's pretty generic. Also, I think it is ignoring my check to only include public/export stuff. Not sure why that is.
>>
>> module distribAlt;
>> ...
>
> Wow, I didn't realise that you'd go off and work on it. You need to start a package for it! I'll bookmark this one as a little reminder of mixin techniques.
Something I had wanted for a long time and once your article got my juices flowing. I had a hard time stopping once you got me started!
I'm going to try to add support for the random number generators and then create a PR for dstats.
|
August 28, 2017 Re: Article: Writing Julia style multiple dispatch code in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to data pulverizer | On Thursday, 24 August 2017 at 23:50:21 UTC, data pulverizer wrote:
> I find OOP-polymorphic types ultimately unsatisfying, but I don't know of anyway to write, compile and load a D script with new types and methods on the fly into the same session.
That is why binding membership and polymorphism together is a historical wrong turn. CLOS had it right but the world followed the Simula/Smalltalk path because of a nice metaphor (objects sending messages to each other).
My openmethods library allows you to add methods "from outside" and also supports dynamic loading: you can add new methods to existing classes and new classes to hierarchies that have methods. See the blog post that just came up.
|
August 28, 2017 Re: Article: Writing Julia style multiple dispatch code in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to data pulverizer | On Thursday, 24 August 2017 at 23:50:21 UTC, data pulverizer wrote:
> I find OOP-polymorphic types ultimately unsatisfying, but I don't know of anyway to write, compile and load a D script with new types and methods on the fly into the same session.
That is why binding membership and polymorphism together is a historical wrong turn. CLOS had it right but the world followed the Simula/Smalltalk path because of a nice metaphor (objects sending messages to each other).
My openmethods library allows you to add methods "from outside" and also supports dynamic loading: you can add new methods to existing classes and new classes to hierarchies that have methods. See the blog post that just came up.
|
Copyright © 1999-2021 by the D Language Foundation