I posted the following code on rosettacode.org for the task of converting Arabic and Roman numerals.
import std.regex, std.array, std.algorithm;
immutable {
int[] weights = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
string[] symbols = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX",
"V", "IV", "I"];
}
string toRoman(int n) {
auto app = appender!string;
foreach (i, w; weights) {
while (n >= w) {
app.put(symbols[i]);
n -= w;
}
if (n == 0) break;
}
return app.data;
}
int toArabic(string s) {
int arabic;
foreach (m; match(s, "CM|CD|XC|XL|IX|IV|[MDCLXVI]")) {
arabic += weights[symbols.indexOf(m.hit)];
}
return arabic;
}
It used to work just fine, but now I get a compiler error.
Error: template
std.algorithm.indexOf(alias pred = "a
== b",R1,R2) if (is(typeof(startsWith!(pred)(haystack,needl
e)))) does not match any function
template declaration
According to the documentation indexOf is deprecated, and countUntil should be used in stead, but it gives me the same error.
Long story but I'll try to keep it short:
std.algorithm.indexOf expects an input range, which is a structural type that must define front, popFront() and empty. For arrays, these methods are defined in std.array and work via uniform function call syntax, which allows fun(someArray) to work the same as someArray.fun().
immutable string[] is not an input range, since popFront removes the first element of the array, which cannot be done for an immutable type. The fact that this used to work was a bug.
I've updated the Rosetta Code entry to change symbols to an immutable(string)[]. Here, the elements of symbols are immutable, but the array may be sliced and reassigned. For example:
void main() {
immutable string[] s1 = ["a", "b", "c"];
immutable(string)[] s2 = ["d", "e", "f"];
s2 = s2[1..$]; // This is what std.array.popFront does under the hood.
assert(s2 == ["e", "f"]); // Passes.
s2[1] = "g"; // Error: Can't modify immutable data.
s1 = s1[1..$]; // Error: Can't modify immutable data.
s1[1] = "g"; // Error: Can't modify immutable data.
}
immutable string[] is implicitly convertible to immutable(string)[] but implicit function template instantiation (often denoted IFTI; this is what's used to instantiate the indexOf template) is not smart enough try this.
I believe this is a bug in std.algorithm. If you remove the immutable qualifier, the code works as is. I think indexOf/countUntil should work on immutable arrays, but at the moment it does not.
You can make them manifest constants (precede each declaration with enum) and it appears to work. Amusingly, this may also be a bug.
Apologies for the breakage; I introduced it. I concur with dsimcha's description and proposed fix.
We are considering a simple change to the language to account for this simple case. That would automatically peel off one level of qualifiers when passing a value of a qualified type into a function. By that (for now hypothetical) rule, qualifier(T[]) would become (when passed to a function) qualifier(T)[] and qualifier(T*) would become qualifier(T)*. This would allow your example to work. The disadvantage is that a function would not be able to distinguish the top-level qualifier but I believe that that does not harm any concrete use.
Related
With using Ruby, we can do this.
s = "split by space"
A,B,C = s.split(" ").map(&:to_i)
With using D-lang, it's compile error.
string s = "split by space";
int A,B,C = s.split(" ").map!(x => x.to!int);
Jonathan is mostly right, but there is in fact a way to split a tuple into
its constituent parts, albeit more verbose than in Ruby, and without any handy
type inference:
import std.meta : AliasSeq;
import std.typecons : tuple;
auto foo() { return tuple(42, 29, "hello"); }
unittest {
int a, b;
string c;
AliasSeq!(a, b, c) = foo(); // Look ma, magic!
assert(a == 42);
assert(b == 29);
assert(c == "hello");
}
While there's no built-in way to do this with ranges like your example, it's
possible to implement in a library:
import std.meta : AliasSeq, Repeat;
import std.typecons : Tuple, tuple;
import std.algorithm : map;
import std.conv : to;
import std.string : split;
import std.range : isInputRange, ElementType;
unittest {
string s = "1 2 3";
int A,B,C;
AliasSeq!(A,B,C) = s.split(" ").map!(x => x.to!int).tuplify!3;
assert(A == 1);
assert(B == 2);
assert(C == 3);
}
auto tuplify(size_t n, R)(R r) if (isInputRange!R) {
Tuple!(Repeat!(n, ElementType!R)) result;
static foreach (i; 0..n) {
result[i] = r.front;
r.popFront();
}
assert(r.empty);
return result;
}
No, there is no way to do that. There has been talk off-and-on about possibly adding tuple support to the language such that you could something like
int a;
int b;
string c;
(a, b, c) = foo();
and maybe that will happen someday, but it's not possible right now. The closest would be using something like std.typecons.Tuple/tuple so that you can do something like
Tuple!(int, int, string) foo() { return tuple(42, 29, "hello"); }
Tuple!(int, int, string) result = foo();
or more likely
auto foo() { return tuple(42, 29, "hello"); }
auto result = foo();
but Tuple is ultimately just a struct, and you can't magically split it out at the other end. You have to access its members via indices such as result[0] or result[1], or if you declare Tuple with names - e.g. Tuple!(int, "x", int, "y", string, "str") - then you can access the members by name - e.g. result.x. So, Tuple/tuple allows you to return multiple values without explicitly declaring a struct type just for that, but it's still creating a struct type just for that, and while it allows you to easily pack values to return, it does not allow you to automatically unpack them on the other end. That would require compiler support of some kind that we don't have.
However, even if we had better tuple support in the language so that something like
(a, b, c) = foo();
worked, I doubt that what you're trying to do would work, since map specifically returns a range. So, it's an object with member functions, not a tuple of any kind to be split up. It just so happens to represent a list of values that can be extracted with the right set of function calls. And the number of values that it has is not known at compile time, so even if you assume that the compiler understands the range primitives well enough to get a list out of them for you, it can't guarantee at compile time that there are enough values to put into the variables you're trying to assign to, let alone that there are exactly that number of values. So, while it wouldn't be impossible to make something like that work (e.g. if it threw an Error at compile time if there weren't enough values in the range), I'd be surprised if that were implemented. D is a statically typed language and that would effectively be making a piece of it dynamic, so it would be pretty out-of-character for it to be in the language. Ruby is a dynamic language, so it's a very different beast.
Regardless, any improvements with tuples would be improvements to the language and would have to go through the DIP process and get approved, and nothing like that has happened yet.
Say I have a constant and immutable list of strings a
const a = ['b', 'c', 'd']
and I want to create a type A that looks like this:
type A = 'b' | 'c' | 'd'
My question is: How do I create the type A from the list a automatically?
The other way around would work for me as well: How to create the list a given the type A
Yes, you can do this. The only barrier is that if you write
const a = ['b','c','d'];
// inferred as string[]
then a will be inferred as string[], so the literal values 'a', 'b', and 'c' are forgotten by the time you try to derive A. You can always annotate the type of a explicitly:
const a: ['b','c','d'] = ['b','c','d'];
type A = typeof a[number];
//type A = "b" | "c" | "d"
but now you are repeating yourself, which you are trying to avoid. There is a solution:
In an answer to another question I recommended a helper function (tuple() in tuple.ts) to infer tuple types.
const a = tuple('b','c','d');
//inferred as type ["b", "c", "d"]
type A = typeof a[number];
//type A = "b" | "c" | "d"
If you don't care about it being a tuple, you can write a simple array inference helper function instead:
function inferLiteralArray<T extends string>(...arr: T[]): T[] {
return arr;
}
const a = inferLiteralArray("b", "c", "d");
//inferred as type ("b" | "c" | "d")[]
type A = typeof a[number];
//type A = "b" | "c" | "d"
Either way works, and you don't need to repeat yourself. Hope that helps; good luck!
Update 1
#fritz_da_silva said:
awesome, it works neatly!!! the a[number] syntax looks like black magic to me. could u please elaborate on why it works?
Sure. The syntax should be interpreted like this (see the parentheses I added for clarity):
type A = (typeof a)[number];
The typeof a part is using the typeof type query operator to get the type of a, which (for the tuple() example) is ["b", "c", "d"].
Then I am using the indexed access operator. If you have a type T and a type K of one of its keys (so it should extend keyof T; you can use string literals like "length" or numeric literals like 0 or unions of these), then T[K] is the type of the property accessible at that key. For an arraylike type A, the type A[number] gets the type of the elements of that array type. In the tuple example, this turns out to be a union, because there are multiple keys of type number with different property types. (When you use the indexed access operator, T[K1|K2] should be equal to T[K1]|T[K2]). Observe:
type TheTuple = typeof a; // ['b','c','d'];
type Zeroth = TheTuple[0]; // 'b'
type First = TheTuple[1]; // 'c'
type Second = TheTuple[2]; // 'd'
type A = TheTuple[number]; // 'b'|'c'|'d'
Does that make sense?
What you want to do is not possible as the array is created at runtime, and changes to the array cannot be determined by the compiler. Therefore, it cannot enforce a type system.
For example, consider the following:
const array = [ "Bob", "James", "Dan" ];
let value: *A key of array*
setTimeout(() => {
value = "James";
}, 1000);
array.splice(1, 1);
What would happen in the above scenario? By the time value = "James is called, "James" has been removed from the array, so an error should be thrown! But this occurs at runtime so the compiler is unable to warn you.
The workaround is to declare a type with the following construct, however it cannot be modified:
type MyType = "Bob" | "James" | "Dan"
let value: MyType = "Dan";
value = "Steven" // <- Compiler error!
EDIT: saravana sums it up quickly in their comment.
For lambda expressions, I don't quite get the usefulness of closures in C++11.
auto f = [] (int n, int m) { return n + m };
std::cout << f(2,2);
versus.
int n = 2;
auto f = [n] (int m) { return n + m };
std::cout << f(2);
This is a very basic and primitive example. I'm guessing that closures play an important part in other kinds of statements, but my C++ book doesn't clarify this (so far).
Why not include the closure as a parameter?
OK, a simple example, remove all the x's from a string
char x = 'x';
std::string s = "Text to remove all 'x's from";
s.erase(std::remove_if(s.begin(), s.end(), [x](char c) {return x == c;}), s.end());
Borrowed and modifed from http://en.cppreference.com/w/cpp/algorithm/remove
In this example, remove_if() only takes a single parameter, but I need two values for the comparison.
Closures are not always called immediately. They are objects which can be stored and called later when the data necessary to successfully execute the lambda function may no longer be in scope or easily accessible from the call site.
It's possible to to store any necessary data along with the closure but it's so much simpler for the closure to grab anything it needs when it's created and use it when it's eventually called. It provides a form of encapsulation.
This also decreases code coupling because if you were to store the data along with the code then the caller could only work with the specific objects you decided to store. Since a closure carries its own data along with it, it can work with any data it needs.
Here's an greatly oversimplified real-life example. I built a database server which needed to support fields with multiple values. The problem was that when results were displayed, it was important to highlight which values actually caused a record to match the search criteria. So, the query parser would spit out a predicate in the form of a closure which would indicate whether or not it was a matching value.
It looked something like this:
std::function< bool(int value) > parser::match_int(int search_val) {
return [=](int value) { value == search_val; };
}
That closure got stored in a collection. When it was time to render the record, I could easily determine which values needed to be highlighted. Keep in mind that the parser and any associated data is now gone:
void render_values(std::function< bool(int value) > pred, std::vector<int> values) {
for (int value : values) {
if (pred(value))
render_highlight(value);
else
render_normal(value);
}
}
Edited
Why I'm asking...
Yesterday, I started a project to create a Morse code translator which creates a file or appends to an existing file, translated Morse code from a given string or from the file text given.
Mainly,I have no idea in hell how to get this map to work with the string in which I want to return and I feel as if I've tried everything I can Google or read in documentation.
additionally...
I've left my horrendous attempt at iterating through the data structures , this time using vectors, having exhausted tries with map methods. I'm sure I'm missing simple syntx with the map structure but I left the last attempt up because I believe it conveys my intention quite clearly due to its baroque nature.
So to be more specific, what's the best way to access this map and return it through this function.
initial design
getTranslation()
/* #brief: Program returns string which is a translation
* of the Rvalue string which it takes as a argument
* #param text: string of letters, numbers and some symbols to be translated
* #return translation: translated string appended with map values
*/
string getTranslation (const string&& text) noexcept(true)
{
//return value
auto translation = "";
map <string,string> morseKey;
morseKey ["A"] = ".-";
morseKey ["B"] = "-...";
morseKey ["C"] = "-.-.";
morseKey ["D"] = "-...";
//...
// I was going to attempt to
// unpack to vectors then compare as vectors of
// strings because of consistent issues with
// type safety errors
// i've tried iterating over it differently
// but this is last hope code here
// any help on how to accomplish this in
// a better way but still retain the
// use of a map because of its ability
//to hold all sorts of characters
//would be greatly appreciated
/*
vector <string> mSymbol;
for (auto itr : morseKey)
{
mSymbols.push_back(itr.first);
}
vector <string> vText;
for (auto itr : text)
{
vText.push_back(itr);
}
for (int i = 0; i < text.length(); i++)
{
if (vText[i] == mSymbol[i])
{
translation += morseKey.at(i);
}
}
*/
translation = "*SCAFFOLDING* FUNCTION NOT COMPLETE";
return translation;
}
Edit:
Wow, Iv'e received some really good input and I believe that my issues are rooted in the fact that using auto caused translation to be as a const char* which wouldn't allow me to make my map a map std::map<char,string> morseKey. Also my Rvalue cast via move was apparently unnecessarily (I had a feeling). So I'm going to implement the knowledge I've gained from and post that before I mark my answer.
Edit 2
I removed the auto and 'translation' is now declared as a string
getTranslation's signature takes a const string&
I initialize morseKey as
static map <char,string> const morseKey = {{'A', ".-"},...
but get the compiler error of
'invalid conversion from ‘const char*’ to ‘const char&’
I don't understand why this is, or what makes either a pointer or ref in this situation and therefore how to fix it.
Wow... you practiced a lot of concepts, and you are just learning to code!!!
I'm sure you will be a successful programmer (but you should know it needs a lot more practicing!)
But about your "getTranslation" function, I changed it a little to:
#include <algorithm>
#include <cctype>
/*...*/
string getTranslation (string text) noexcept(true)
{
map <char,string> morseKey;
morseKey ['A'] = ".-";
morseKey ['B'] = "-...";
morseKey ['C'] = "-.-.";
/*...*/
string translation {""};
std::transform(text.begin(), text.end(), text.begin(), toupper);
for (it: text){
translation += morseKey[it];
}
return translation;
}
As you may know, map is an associative array; it means you don't need to iterate over all of its element to find your interesting element. You should associate a key to its corresponding record. In your case you should associate a char (not a string) to a string; so you should define your "morseKey" as:
map <char, string> morseKey;
and when you want to associate a character such as 'A' to ".-" you should do something like:
morseKey ['A'] = ".-"; /*instead of morsKey["A"] = ".-" */;
also when you used "auto" in defining your "translation" variable, compiler will consider it as a "const char*". so you should explicitly define your "translation" variable as:
string translation {""};
In addition because our "morseKey" map contains just uppercase of alphabets, we should convert alphabet characters of "text" variable to uppercase. This can be done very easily by:
std::transform(text.begin(), text.end(), text.begin(), toupper);
but for using this command you should include two libraries:
#include <algorithm> /*for "transform" */
#include <cctype> /*for "touppper" */
Also you shouldn't consider "text" variable as rvalue any more (because we modify it) so I change your function delcarion to:
string getTranslation (string text) noexcept(true)
Finally you should just iterate over your "text" variable and find corresponding Morse value of each character and append it to your return value; This also can be done very easily by:
for (it: text){
translation += morseKey[it];
}
Have fun with programming!
My reply for your second edit:
I think your information is not enough; perhaps it's better to ask your question as a new question, and also provide it with more details, such as in which line you got this compile error or any other useful details that you may think it can be helpful.
The function could be defined the following way. ( Note: I would make the map as a global variable in some namespace and initialize it with an array of std::pair(s) ).
std::string getTranslation( const std::string&& text) noexcept(true)
{
std::string translation;
std::map <std::string, std::string> morseKey;
morseKey ["A"] = ".-";
//...
for ( char c : text )
{
c = std::toupper( c );
auto it = morseKey.find( c );
if ( it != morseKey.end() ) translation.push_back( it->second );
}
return translation;
}
void main(){
int[3] arr = [1, 2, 3,];
}
Is the extra comma legal or is it not flagged as error because of a compiler bug? I have many mixins that generate arrays with the extra comma at the end. I would like to know if I should taken the time to remove them.
even this compiles without errors:
void main(){
int[3] arr = [1, 2, 3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,];
}
I believe it's legal in order to allow for templates (or even mixins) to work in a generic manner:
template Foo(T) { } //What if Foo is empty like this?
auto arr = [1, 2, Foo!(int), Foo!(long)];
// [1, 2, , ]
It makes templates much easier to work with, so that you don't have to special-case against special outputs.
A more realistic example:
template Iota(size_t start, size_t end) //All integers in range [start, end)
{
static if (start < end)
alias TypeTuple!(start, Iota!(start + 1, end)) Iota;
else
alias TypeTuple!() Iota;
}
auto arr1 = [-10, Iota!(0, 3)]; // arr is now [-10, 0, 1, 2]
auto arr2 = [-10, Iota!(a, b)]; // arr is now [-10, a .. b]
Now what happens if a is equal to b? Then arr2 decays to [-10, ].
It's allowed in many languages to allow code formatting like:
string[3] arr = [
"Some long String",
"And another",
"etc, etc, etc",
];
without having to omit the comma from the last value.
Java permits such an array initializer too.
I'm 99% sure the single comma is by design. The 2nd, 3rd, etc.? IMHO, it's a bug in the design or implementation, but I don't know which.
Some months ago Walter committed this behavior into dmd. Before, a trailing comma was sometimes allowed and sometimes not, and if you're in dmd1 land, you're stuck with that.
Now, for dmd2, at least, a trailing comma should always be valid in an array literal, as well as in parameter lists, argument lists, and template argument lists.
The multiple trailing commas, however, is a bug in the implementation.