www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why any! with map! is not working here

reply rnd <r_narang yahoo.com> writes:
I am trying to check if any character in the string is > 127 by 
following function:

import std.algorithm.searching;
import std.algorithm.iteration;
bool isBinary(char[] ss){
   return (any!(map!(a => a > 127)(ss)));
}

However, I am getting this error:

Error: variable ss cannot be read at compile time

I also tried:

bool isBinary(char[] ss){
	return (any!(ss.map!(a => a > 127)));
}


But I get error:

Error: template identifier map is not a member of variable 
mysrcfile.isBinary.ss


How can this be corrected?
Jun 06 2019
next sibling parent Marco de Wild <mdwild sogyo.nl> writes:
On Thursday, 6 June 2019 at 09:01:11 UTC, rnd wrote:
 I am trying to check if any character in the string is > 127 by 
 following function:

 import std.algorithm.searching;
 import std.algorithm.iteration;
 bool isBinary(char[] ss){
   return (any!(map!(a => a > 127)(ss)));
 }

 However, I am getting this error:

 Error: variable ss cannot be read at compile time

 I also tried:

 bool isBinary(char[] ss){
 	return (any!(ss.map!(a => a > 127)));
 }


 But I get error:

 Error: template identifier map is not a member of variable 
 mysrcfile.isBinary.ss


 How can this be corrected?
Removing the ! makes it work: ``` import std.algorithm.searching; import std.algorithm.iteration; bool isBinary(char[] ss){ return (any(map!(a => a > 127)(ss))); } ``` `any` takes a runtime argument (a range) and optionally a template argument. You can also use UFCS[0] ``` import std.algorithm.searching; import std.algorithm.iteration; bool isBinary(char[] ss){ return ss.map!(a => a > 127).any; } ``` to make it more obvious to see what is happening. It can be quite confusing to mix chains of template and runtime arguments. [0] https://tour.dlang.org/tour/en/gems/uniform-function-call-syntax-ufcs
Jun 06 2019
prev sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, June 6, 2019 3:01:11 AM MDT rnd via Digitalmars-d-learn wrote:
 I am trying to check if any character in the string is > 127 by
 following function:

 import std.algorithm.searching;
 import std.algorithm.iteration;
 bool isBinary(char[] ss){
    return (any!(map!(a => a > 127)(ss)));
 }

 However, I am getting this error:

 Error: variable ss cannot be read at compile time

 I also tried:

 bool isBinary(char[] ss){
   return (any!(ss.map!(a => a > 127)));
 }


 But I get error:

 Error: template identifier map is not a member of variable
 mysrcfile.isBinary.ss


 How can this be corrected?
Well, it might be easier to see the problem if you removed the outer layer of parens, since they do nothing and just clutter up the code further. bool isBinary(char[] ss){ return any!(map!(a => a > 127)(ss)); } Now, let's add the parens for the function call for clarity. bool isBinary(char[] ss){ return any!(map!(a => a > 127)(ss))(); } So, as should now be obvious, the first problem here is that you're not passing any function arguments to any - neither through UFCS or through the normal function call syntax. any takes a predicate as a template argument and a range as a runtime argument. Presumably, you want to be passing ss to any. However, you're passing it to map, which is part of the predicate for any, and the way that you're doing it results in the compiler trying to evaluate ss at compile-time, which isn't going to work, because it's a runtime variable - hence the compiler error that you're seeing. So, to start, the any portion should be something more like any!pred(ss); or ss.any!pred(); or ss.any!pred; where pred is whatever the predicate is. That would then iterate through ss and return whether the predicate returned true for any element. So, you'd want something like bool isBinary(char[] ss){ return any!pred(ss); } That then leaves the question of what the predicate should be (since, you're obviously not going to just put the value pred there). The predicate needs to be something that's callable - be it a function, a delegate, a lambda, etc. Most typically, it's a lambda. map!(a => a > 127)(ss); is not a lambda. It's simply a function call to map. The a => a > 127 is a lambda for map, but the overall expression is not a lambda. It calls map on ss and converts it to a range of bool where each element is true if the corresponding element of ss was greater than 127. It could be turned into a lambda by doing something like b => map!(a => a > 127)(ss) but the return value isn't bool (which is what's necessary for a predicate), and it really doesn't make sense to be using ss in the predicate anyway. You're already iterating over ss with any. What you want is a predicate that's going to be true for an element of ss that matches the condition you're testing for. What you said about that is
 I am trying to check if any character in the string is > 127
So, let's build something that does that. The simplest would be a => a > 127 This would then give you bool isBinary(char[] ss){ return any!(a => a > 127)(ss); } map is neither necessary nor useful here. map is for converting the elements from one type to another, which you don't need to do here. Now, that solution _does_ unfortunately autodecode, so it's actually decoding sequences of char to dchar and then testing them - which will work in this case but is unnecessary work. To avoid that, either std.string.representation or std.utf.byCodeUnit would work. e.g. bool isBinary(char[] ss){ return any!(a => a > 127)(ss.representation()); } or bool isBinary(char[] ss){ return any!(a => a > 127)(ss.byCodeUnit()); } representation would convert string[] to immutable(ubyte)[], and byCodeUnit converts string[] to a range of code units instead of a range of code points (so a range of char instead of a range of dchar). Of course, you could also do something like bool isBinary(char[] ss){ return any!isASCII(ss.byCodeUnit()); } using std.ascii.isASCII, which makes what you're testing for more explicit. And if you prefer UFCS, then bool isBinary(char[] ss){ return ss.byCodeUnit().any!isASCII(); } or bool isBinary(char[] ss){ return ss.byCodeUnit.any!isASCII; } - Jonathan M Davis
Jun 06 2019
parent reply rnd <r_narang yahoo.com> writes:
On Thursday, 6 June 2019 at 09:49:28 UTC, Jonathan M Davis wrote:
 So, to start, the any portion should be something more like

 any!pred(ss);

 or

 ss.any!pred();

 or

 ss.any!pred;

 where pred is whatever the predicate is.
Apparently, following also works: any(ss.map!(a => a > 127)) // as written by Marco de Wild or any(map!(a => a > 127)(ss)) Thanks for detailed explanations. Philosophically, I personally think, there should be only one way to do such things since that will add to simplicity, as in C. Apparently, smallness and simplicity of C contributed greatly to its success. Only drawbacks of C, like its unsafe parts, should be removed and clearly advantages newer concepts should be added in a clearly defined manner. Just thinking loudly!
Jun 06 2019
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, June 6, 2019 5:50:36 AM MDT rnd via Digitalmars-d-learn wrote:
 On Thursday, 6 June 2019 at 09:49:28 UTC, Jonathan M Davis wrote:
 So, to start, the any portion should be something more like

 any!pred(ss);

 or

 ss.any!pred();

 or

 ss.any!pred;

 where pred is whatever the predicate is.
Apparently, following also works: any(ss.map!(a => a > 127)) // as written by Marco de Wild or any(map!(a => a > 127)(ss)) Thanks for detailed explanations. Philosophically, I personally think, there should be only one way to do such things since that will add to simplicity, as in C. Apparently, smallness and simplicity of C contributed greatly to its success. Only drawbacks of C, like its unsafe parts, should be removed and clearly advantages newer concepts should be added in a clearly defined manner. Just thinking loudly!
If any is not given a predicate, it defaults to just checking whether the element itself is true (requiring that the element be bool), which is why Marco's suggestion works, but it's a rather odd way to write the code and will be less efficient unless the optimizer manages to optimize away the extra work involved with having map. However, in general, with D, you're not going to find that there is only one way to do things. There are going to tend to be many different approaches to solve the same problem. D code is often simple because of the powerful language constructs and standard library, but it makes no attempt to make it so that there's only one way to do things - especially when you start combining stuff to do whatever it is you're trying to do. - Jonathan M Davis
Jun 06 2019
parent reply rnd <r_narang yahoo.com> writes:
On Thursday, 6 June 2019 at 21:32:11 UTC, Jonathan M Davis wrote:
 If any is not given a predicate, it defaults to just checking 
 whether the element itself is true (requiring that the element 
 be bool), which is why Marco's suggestion works, but it's a 
 rather odd way to write the code and will be less efficient 
 unless the optimizer manages to optimize away the extra work 
 involved with having map.

 However, in general, with D, you're not going to find that 
 there is only one way to do things. There are going to tend to 
 be many different approaches to solve the same problem. D code 
 is often simple because of the powerful language constructs and 
 standard library, but it makes no attempt to make it so that 
 there's only one way to do things - especially when you start 
 combining stuff to do whatever it is you're trying to do.

 - Jonathan M Davis
Maybe one of these methods can be made 'official' or 'idiomatic':
 any!pred(ss);
 ss.any!pred();
 ss.any!pred;
This will reduce learning burden on beginners.
Jun 06 2019
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, June 6, 2019 10:21:39 PM MDT rnd via Digitalmars-d-learn wrote:
 On Thursday, 6 June 2019 at 21:32:11 UTC, Jonathan M Davis wrote:
 If any is not given a predicate, it defaults to just checking
 whether the element itself is true (requiring that the element
 be bool), which is why Marco's suggestion works, but it's a
 rather odd way to write the code and will be less efficient
 unless the optimizer manages to optimize away the extra work
 involved with having map.

 However, in general, with D, you're not going to find that
 there is only one way to do things. There are going to tend to
 be many different approaches to solve the same problem. D code
 is often simple because of the powerful language constructs and
 standard library, but it makes no attempt to make it so that
 there's only one way to do things - especially when you start
 combining stuff to do whatever it is you're trying to do.

 - Jonathan M Davis
Maybe one of these methods can be made 'official' or 'idiomatic':
If you're looking for the language or library to tell you exactly how you should be doing things, then you've come to the wrong language. There are approaches that are more idiomatic than others (e.g. range-based solutions are usually favored), but D is purposefully designed to be multi-paradigm, and there are going to be very different approaches to a problem where each approach is equally viable or where one approach is better in some situations, whereas another is better in others. And once we're dealing with combining functions to get a job done, it would actually be very difficult to try to claim that a particular combination of them is the correct way. Which functions make sense is going to depend on the task, and it's naturally going to be possible to combine functions in different ways to get the same result.
 any!pred(ss);
 ss.any!pred();
 ss.any!pred;
This will reduce learning burden on beginners.
We're not going to make requirements over that sort of thing any more than we're going to require that all D code use a particular bracing style. D provides the tools needed to get stuff done, but for the most part, it doesn't try to tell you how to use them. There are some best practices for how to go about things in D, but that's not usually about stuff like coding style, and it really covers a fairly small number of the decisions that a D programmer has to make. The closest that you're going to get on coding style is the official style guide ( https://dlang.org/dstyle.html ), and aside from some Phobos-specific requirements at the bottom, it's mostly just about how you name public symbols so that there's some consistency when using other people's libraries. For best practices, you're going to get things like "use ranges" and "make your imports local." You're not going to be told how to format your code or which set of functions you should be using to solve a particular problem. - Jonathan M Davis
Jun 06 2019