|
|
|
|
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp wrote:
> Orchid XP v8 <voi### [at] devnull> wrote:
>> std::string txt;
>> std::cin >> txt;
>
>> std::istringstream iss(txt);
>> int number;
>> iss >> number;
>
> I think you misunderstood the reason to use stringstreams.
Er, yeah, good point...
>> if (number < target) {std::cout << "Too low." << std::endl; continue;}
>> if (number > target) {std::cout << "Too high." << std::endl; continue;}
>> break;
>
> Wouldn't it be simpler to do it like:
>
> if(number == target) break;
> if(number < target) std::cout << "Too low.\n";
> else std::cout << "Too high.\n";
Mmm, I guess that would also work...
--
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Darren New <dne### [at] sanrrcom> wrote:
> Warp wrote:
> > case(compare(number, target)) of
> > What would be wrong with a syntax like that?
> All the functions in Haskell are curried. So it's really
> case (compare(number)(target)) of ...
How does Haskell distinguish where a nested (possibly curried) function
call ends, and the outer one continues? Assume that you would want to
write (here in C++ style) something like:
foo(a, bar(b, c), d, e)
If you wrote that as a Haskell-style no-delimiters function call,
I suppose it would look like:
foo a bar b c d e
Exactly how does Haskell decide how many parameters 'bar' takes there
(and consequently how many of the rest of the parameters are for 'foo')?
I can't even begin to imagine how you would write that using the
"point syntax", seen in many examples posted by Andrew. Perhaps you
use parentheses to enclose the 'bar' call?
(Btw, I think this demonstrates one problem with Haskell. I'm an
experienced programmer, and I do have a moderate understanding of the
functional paradigm, and I have been seeing quite many example programs
posted by Andrew during the last years. Yet I'm still completely unable
to figure out or deduce how you could write that in Haskell. It must be
simple, but I just don't know, even though I have seen many examples of
small Haskell programs.
There just is something about the Haskell paradigm and syntax that
makes it confusing and hard to assimilate.)
--
- Warp
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp wrote:
> How does Haskell distinguish where a nested (possibly curried) function
> call ends, and the outer one continues? Assume that you would want to
> write (here in C++ style) something like:
>
> foo(a, bar(b, c), d, e)
>
> If you wrote that as a Haskell-style no-delimiters function call,
> I suppose it would look like:
>
> foo a bar b c d e
>
> Exactly how does Haskell decide how many parameters 'bar' takes there
> (and consequently how many of the rest of the parameters are for 'foo')?
You'd have to throw in some brackets to disambiguate.
If you change every "foo(x, y, z)" into "(foo x y z)", you'll get a
valid expression. In this case, we have
foo a (bar b c) d e
If you wrap the whole thing in brackets, then the following rule
applies: the first token after each "(" is the function being called;
everything else is arguments.
What may be a little confusing is that a function's arguments may be
functions themselves - even standard library functions. This is very
useful from a programming perspective (indeed, the whole paradigm is
based on it), but perhaps rather unhelpful for anybody trying to read
the thing.
Where this starts to go wrong is where you start using operators.
Obviously "2 + 7" means... well... two plus seven. It would be tedious
(though perhaps more consistent) to write this as "(+) 2 7".
To understand how to parse an expression involving operators, you must
know (or take a reasonable stab at) operator precidences. For arithmetic
operators, it's the usual stuff. Function application has a higher
precidence than anything else in the language - so "foo x + bar y"
parses as "(foo x) + (bar y)" and not "foo (x + bar) y".
And that leads us neatly on to...
> I can't even begin to imagine how you would write that using the
> "point syntax", seen in many examples posted by Andrew.
You can't. Because the nested expression isn't the final argument in the
argument list. (Haskell programmers are very fussy about what order to
put function arguments in for just this reason.)
> (Btw, I think this demonstrates one problem with Haskell. I'm an
> experienced programmer, and I do have a moderate understanding of the
> functional paradigm, and I have been seeing quite many example programs
> posted by Andrew during the last years. Yet I'm still completely unable
> to figure out or deduce how you could write that in Haskell. It must be
> simple, but I just don't know, even though I have seen many examples of
> small Haskell programs.
> There just is something about the Haskell paradigm and syntax that
> makes it confusing and hard to assimilate.)
The following are all equivilent:
function1 (function2 (function3 (function4 (function5 x))))
function1 $ function2 $ function3 $ function4 $ function5 $ x
function1 $ function2 $ function3 $ function4 $ function5 x
(function1 . function2 . function3 . function4 . function5) x
The last one creates a function by chaining several functions together,
and then passes x as the argument to that function. Normally you
wouldn't do that; you'd only use (.) if you wanted to pass a function as
an argument or something:
map (reverse . toUpper)
(Takes a list of strings, converts each string to upper case, and then
reverses it.)
Where this starts to get crazy is if you have functions that take more
than one argument. Because functions are curried, you may write
function2args x $ function4args a b c $ function1arg j
or something.
So, between recognising language keywords, bracketed expressions, ($)
and (.), and infix operators, I guess there *is* quite a bit to be
getting on with.
It's interesting to me that most people seem confused not by curried
functions or monads or high-order functions, but by the basics of
parsing Haskell's syntax. I guess I'm so used to it be now that I take
it for granted - but obviously, if you can't read the language syntax,
you don't stand much chance of getting very far. I'll go have a think
about that...
--
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp <war### [at] tagpovrayorg> wrote:
> What you can do is this:
> std::string s;
> while(true)
> {
> std::cin >> s;
> if(!std::cin.good()) break;
> int value;
> std::istringstream iss(s);
> iss >> value;
> if(!iss.fail())
> std::cout << "The input was an integer: " << value << "\n";
> else
> std::cout << "The input was something else: " << s << "\n";
> }
Actually there is a way to achieve the same thing with std::cin
directly, without having to use stringstreams.
If an input stream fails to read data which fits the parameter type,
it will stop reading, so anything that was in the input (which was not
whitespace) will be left there. It's thus possible to check if reading
the integer filed, and if it did, read it as a string.
The only catch is that you have to clear the error flags of std::cin
before you can continue reading properly.
The above example code can thus be written as:
while(true)
{
int value;
std::cin >> value; // Try to read an integer
if(std::cin.fail()) // If there was no integer in the input
{
std::cin.clear(); // Clear the error flags
std::string s;
std::cin >> s; // Read a string
if(!std::cin.good()) break;
std::cout << "The input was something else: " << s << "\n";
}
else
{
std::cout << "The input was an integer: " << value << "\n";
}
}
Thus removing the need for stringstreams.
--
- Warp
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp wrote:
> Actually there is a way to achieve the same thing with std::cin
> directly, without having to use stringstreams.
>
> If an input stream fails to read data which fits the parameter type,
> it will stop reading, so anything that was in the input (which was not
> whitespace) will be left there. It's thus possible to check if reading
> the integer filed, and if it did, read it as a string.
> The only catch is that you have to clear the error flags of std::cin
> before you can continue reading properly.
Thanks for the tip.
By the way... what's the usual C++ idiom for handling failure?
In Haskell, if you have some function that could fail for some reason,
you have two options:
1. Throw an exception if there's a problem. (Only I/O code can catch and
handle exceptions.)
2. Use the "maybe" datatype, which contains either some data, or a
"there's nothing here" flag. (And because the type is different, the
caller *must* explicitly check which it is before using the result for
anything.)
Typically you throw an exception for something like "we ran out of
memory" or "you called with an invalid argument". But for something
like, say, looking up a key in a dictionary, it's a very predictable
thing that the key might not actually exist, so the "maybe" approach is
used there.
What is the "usual" C++ style for this kind of thing? (I'm asking a
question of style here; clearly there are several possible things you
*could* do in C++.)
--
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Orchid XP v8 <voi### [at] devnull> wrote:
> What is the "usual" C++ style for this kind of thing? (I'm asking a
> question of style here; clearly there are several possible things you
> *could* do in C++.)
The standard data containers, as well as 'new', throw an exception by
default when they run out of memory. Also the at() member function of
some of the containers throws an exception if you try to index out of
boundaries.
If you don't want to throw exceptions in your own code, then it depends
on what is it that you want to do to signal a condition.
The usual way to catch programming errors at runtime is to use
assertions. For example:
void foo(int min, int max)
{
assert(min <= max);
// rest of the code here
}
If the assertion fails, a message will be printed and the program is
immediately terminated at that point. Obviously this should only be
used in situations which are a symptom of a programming error and which
must be fixed.
(The good thing about assert() is that you can freely use it as much
as you want. In fact, the more you use it, the better. You can compile
the program with a special precompiler parameter which will remove all
the asserts from the executable so that they will not add overhead to
a final version.)
--
- Warp
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp wrote:
> The standard data containers, as well as 'new', throw an exception by
> default when they run out of memory. Also the at() member function of
> some of the containers throws an exception if you try to index out of
> boundaries.
>
> If you don't want to throw exceptions in your own code, then it depends
> on what is it that you want to do to signal a condition.
>
> The usual way to catch programming errors at runtime is to use
> assertions. For example:
>
> void foo(int min, int max)
> {
> assert(min <= max);
>
> // rest of the code here
> }
>
> If the assertion fails, a message will be printed and the program is
> immediately terminated at that point. Obviously this should only be
> used in situations which are a symptom of a programming error and which
> must be fixed.
Right. So assert() is for stuff that should never happen if the
programmer is doing their job right. In other words, BUGS.
How about stuff that might ordinarily be expected to not work? E.g.,
parsing strings, looking up keys in dictionaries, etc.
It seems that streams at least signal errors by altering the stream
object and getting the programmer to call a member function to check
whether an error condition occurred. Is that a usual C++ idiom?
--
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Orchid XP v8 <voi### [at] devnull> wrote:
> It seems that streams at least signal errors by altering the stream
> object and getting the programmer to call a member function to check
> whether an error condition occurred. Is that a usual C++ idiom?
I'm not sure there *is* any "usual" C++ idiom for error handling
(other than throwing exceptions).
--
- Warp
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Orchid XP v8 wrote:
> Both C and C++ are positively *bursting* with features that are subtle,
> counter-intuitive and cryptic.
No, actually, C is really, really straightforward. Almost moreso than
assembler. It's not subtle and complex and cryptic. It's just difficult
and tedious.
> This isn't exactly news. C++ at least
> appears to be something of an improvement in this regard...
I, personally, think C++ has many features that seem subtle and
counter-intuitive, as evidenced by the fact that it's really hard to
explain how some of the features work and when they come into play. Most
people seem to say "this is how you use them" without actually knowing
why using them that way actually works. (Granted, I don't have a whole
lot of experience with C++, so I probably sound way off base to those
who know C++ well.)
--
Darren New / San Diego, CA, USA (PST)
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp wrote:
> foo(a, bar(b, c), d, e)
>
> If you wrote that as a Haskell-style no-delimiters function call,
> I suppose it would look like:
>
> foo a bar b c d e
> Exactly how does Haskell decide how many parameters 'bar' takes there
> (and consequently how many of the rest of the parameters are for 'foo')?
It's curried. Each function only takes one.
In your example, I'm pretty certain you *have* to have parens.
foo a (bar b c) d e
> I can't even begin to imagine how you would write that using the
> "point syntax", seen in many examples posted by Andrew. Perhaps you
> use parentheses to enclose the 'bar' call?
Hmmmm. I don't know you can do it with "point syntax" either. I think
the a . b . c syntax only works when the result of "c" is the one and
only argument to "b", and the result of "b" is the one and only argument
to "a".
So if you wanted a function that returns the sum of the lengths of a
list of strings, you might write
length . concat
or something, if "concat" was a function that took a list of strings and
returned their concatenation.
> There just is something about the Haskell paradigm and syntax that
> makes it confusing and hard to assimilate.
I think most of the powerful languages have syntax that's confusing and
hard to assimilate. C and C++ are also very confusing in syntax. (For
example, I can barely follow the reference-counting pointer code you
posted, and that only because I am only trying to read it and not write
it. :-)
Even Tcl, which has exactly 12 rules of syntax, winds up being confusing
to newbies because it's *too* simple. LISP has too many parentheses,
even tho the grammar is about 3 lines of BNF.
About the only languages that aren't confusing are the weak ones: BASIC,
Pascal, etc.
If the language is powerful because it does a lot (like Ada or C++) you
wind up with lots and lots of syntax and lots of rules about the
interactions. If the language is powerful because it's simple and
regular (like LISP or FORTH or Tcl or Haskell) then it's confusing
because there's no *obvious* way to accomplish the powerful stuff you
know the language is capable of. (Sort of like Go or Chess or something
- simple rules but very unobvious combinations.)
--
Darren New / San Diego, CA, USA (PST)
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
|
|