>GoldenEye wrote:
>1.Since Scheme has an interpreter, you can run individual functions and
>play with your data structures
> without writing stubs.
> 2.Dynamic typing allows you to concentrate on real errors, rather than
> trying to placate the compiler god. It
> also makes code vastly more reusable.
Hardly true. The only time I ever notice the static type checker is
when I get a type mismatch. This would have been a run-time error in
scheme that may have hit for a long time, and been hard to debug.
Dynamic type checking is a hack to allow for faster interpretation which
gives awayt a lot.
> 3.Scheme is actually portable.
If you're using the cortect version.
> 4.Every Scheme function is prefix. We don't need no stinkin' 19-level
> operator precedence heirarchy.
> 5.In C, you have to write the code if you want a really exotic data
> structure, like a linked list.
Not with stl you don't. And I actually think it's easier to do complex
data structures in C++ because you actually have data structures. I
certianly find it easier in java or ML.
> Similarly, you
> have to include a special library if you want to do something
> bizarre, like write to standard output.
#include <iostream.h>
Is not a hard thig to do.
> 6.Scheme has first-class functions and continuations.
Well, C++ has function pointers, which can be used much like
first-class functions, though they are harder to use! I wish scheme had
currying too, I use that a lot.
> 7.In Scheme, (* 3 (/ 1 3)) evaluates to 1.
Bad in 2 ways. With integers, this is not the result you want.
Frequently you want integers to behave like integers. Secondly, this is
a lot easier for me to read:
3*(1/3)
> 8.Scheme has no *&%@#! pointers. Memory management is for compilers.
> 9.It's a lot harder to confuse set! and eq? than = and ==.
> 10.The following is actually a legal C statement, according to The
> UNIX-HATERS Handbook:
>
> for(;P("\n"),R=;P("|"))for(e=C;e=P("_"+(*u++/8)%2))P("|"+(*u/4)%2);
Doesn't look valid to me. R=; will probably cause a compiler error.
Here's the original post:
2.Dynamic typing allows you to concentrate on real errors, rather than
trying to placate the compiler god. It
also makes code vastly more reusable.
3.Scheme is actually portable.
5.In C, you have to write the code if you want a really exotic data
structure, like a linked list. Similarly, you
have to include a special library if you want to do something
bizarre, like write to standard output.
7.In Scheme, (* 3 (/ 1 3)) evaluates to 1.
10.The following is actually a legal C statement, according to The
UNIX-HATERS Handbook:
for(;P("\n"),R=;P("|"))for(e=C;e=P("_"+(*u++/8)%2))P("|"+(*u/4)%2);
> >GoldenEye wrote:
> > 10.The following is actually a legal C statement, according to The
> > UNIX-HATERS Handbook:
> >
> > for(;P("\n"),R=;P("|"))for(e=C;e=P("_"+(*u++/8)%2))P("|"+(*u/4)%2);
>
> Doesn't look valid to me. R=; will probably cause a compiler error.
Also, the second 'for' statement is missing the second semicolon which
should be inserted at:
for(;P("\n"),R=;P("|"))for(e=C;e=P("_"+(*u++/8)%2);)P("|"+(*u/4)%2);
^
I guess the point being that it's not possible to abuse Scheme's syntax?
Doug Bell
db...@shvn.com
Pointers to functions in C++ are very far from first class functions,
and continuations. Problem (and thrength) of C++ is that all
functions must be known at compile time. A scheme program may pop up
functions the programmer never had dreamed of. Compare this to numbers.
Numeric computations would be very hard in a language in which a
program cannot produce any other numbers than those mentioned somewhere
in the code. If you want a true functional programming facility, then
scheme probably is preferable over C++.
The choice of a programming language depends on many factors,
but let us not forget that personal taste is one of them.
Jacob
--
If Java would not have pointers, we would not need clone.
J. J. A. Koot Stichting Academisch Rekencentrum Amsterdam
Tel: +31 20 5923019 Postbus 94613, 1090 GP, Amsterdam, Netherlands
Fax: +31 20 6683167 http://www.sara.nl/koot Mailto:ko...@sara.nl
[...]
> 2.Dynamic typing allows you to concentrate on real errors, rather
> than trying to placate the compiler god. It also makes code vastly
> more reusable.
David Hanley wrote:
> Hardly true. The only time I ever notice the static type
> checker is when I get a type mismatch. This would have been a
> run-time error in scheme that may have hit for a long time, and
> been hard to debug. [...]
A good type system is better than no type system, but no type system
is better than a bad type system. C++ has a bad type system.
Goldeneye:
> 6.Scheme has first-class functions and continuations. [...]
David Hanley:
> Well, C++ has function pointers, which can be used much like
> first-class functions, though they are harder to use! I wish scheme had
> currying too, I use that a lot.
Function pointers are in no way a substitute for higher-order functions.
As for currying in scheme:
(define (curry f arg)
(lambda rest (apply f (cons arg rest))))
(define add3 (curry + 3))
(add3 4) => 7
...which also happens to be a good example of why function pointers are
in no way a substitute for higher-order functions.
Goldeneye:
> 7.In Scheme, (* 3 (/ 1 3)) evaluates to 1.
David Hanley:
> Bad in 2 ways. With integers, this is not the result you
> want. Frequently you want integers to behave like integers.
No. You mean that sometimes you don't want division to behave like
division:
(* 3 (quotient 1 3))
> Secondly, this is
> a lot easier for me to read:
>
> 3*(1/3)
Do you actually have all the operator precidences in C++ memorized? Or do
you, like me, put redundant parentheses in your code where-ever you're not
sure about them? (Or, do you, like many others, merely discover bugs in
your programs caused by operator precidences you didn't think about?)
Here's my very short list of reasons why Scheme is a better language
than C++:
1) Print out the (R4RS) definition of Scheme and have someone drop it
on your head. Next, print out the (ANSI Draft Standard) definition of
C++ and have someone drop that on your head.
Which is the better language?
I have to admit that there are situations where I would choose C++ over
Scheme. However, my only choices aren't Scheme and C++, and the only
reason I program in C++ at all is because the people I work with don't
have any experience with alternatives. If it weren't for that, I
wouldn't use C++ at all. C++ a disgusting hairball of a language that
should have been abandoned long ago for the obvious mistake that it was.
-thant
--
Thant Tessman <th...@shoreline-studios.com>
http://www.shoreline-studios.com
This is, of course, a matter of taste. I would qualify scheme's
runtime determination of all types as a really bad type system. C++'s
type system is actually not all *that* bad, though it certianly could be
better.
Nonetheless, the claim made in the original post was the dynamic typing
is inherently better than static typing, which I personally feel is
incorrect.
>
> Goldeneye:
>
> > 6.Scheme has first-class functions and continuations. [...]
>
> David Hanley:
>
> > Well, C++ has function pointers, which can be used much like
> > first-class functions, though they are harder to use! I wish scheme had
> > currying too, I use that a lot.
>
> Function pointers are in no way a substitute for higher-order functions.
I didn't say that they were as good in all cases; however, in many
cases they serve a similar function.
> As for currying in scheme:
>
> (define (curry f arg)
> (lambda rest (apply f (cons arg rest))))
>
> (define add3 (curry + 3))
> (add3 4) => 7
>
> ...which also happens to be a good example of why function pointers are
> in no way a substitute for higher-order functions.
Eh, no, sorry. That's not a full curry, though it's quite clever. I
was unaware of that construct. As long as we're talking about language
hacks, you could do something similar( though surely not the same not as
nice ) in C++ with either function poiners, or an object chain.
>
> Goldeneye:
>
> > 7.In Scheme, (* 3 (/ 1 3)) evaluates to 1.
>
> David Hanley:
>
> > Bad in 2 ways. With integers, this is not the result you
> > want. Frequently you want integers to behave like integers.
>
> No. You mean that sometimes you don't want division to behave like
> division:
No, the integer division of 1/3 is 0. Period. Claiming this correct
result as a language defect is foolish.
>
> (* 3 (quotient 1 3))
>
> > Secondly, this is
> > a lot easier for me to read:
> >
> > 3*(1/3)
>
> Do you actually have all the operator precidences in C++ memorized?
No, this is not necessary.
> Or do
> you, like me, put redundant parentheses in your code where-ever you're not
> sure about them?
Sure. So what?
>
> Here's my very short list of reasons why Scheme is a better language
> than C++:
>
> 1) Print out the (R4RS) definition of Scheme and have someone drop it
> on your head. Next, print out the (ANSI Draft Standard) definition of
> C++ and have someone drop that on your head.
That's a pretty good reason, actually, but I don't think it's the
end-all either.
>
> Which is the better language?
>
> I have to admit that there are situations where I would choose C++ over
> Scheme. However, my only choices aren't Scheme and C++, and the only
> reason I program in C++ at all is because the people I work with don't
> have any experience with alternatives. If it weren't for that, I
> wouldn't use C++ at all. C++ a disgusting hairball of a language that
> should have been abandoned long ago for the obvious mistake that it was.
I do think that C++ is not a very good language. I'd like to see
better languages succeed. However, language devotees have a serious
problem of refusing to see the flaws in thier pet languages. Heck, if
the language was the best soloution, it would probably be a lot more
widely used, right?
Refusing to see the problems with a something is highly destriental to
advancing it's success.
dave
--Mohammed
>A good type system is better than no type system, but no type system
>is better than a bad type system. C++ has a bad type system.
Why do you say that? C++ has a bad type system?
>Function pointers are in no way a substitute for higher-order functions.
>As for currying in scheme:
>
> (define (curry f arg)
> (lambda rest (apply f (cons arg rest))))
>
> (define add3 (curry + 3))
> (add3 4) => 7
>
>...which also happens to be a good example of why function pointers are
>in no way a substitute for higher-order functions.
This can be done in C++ or Java if all the functions take
their parameters from an array or something like that.
Then all we need to do is to store "f" and "arg" in a
(functional) object just like what you did.
---
Kent Tong
v3 is out!!!
Freeman Installer ==> http://www.netnet.net/users/freeman/
Print out the definition of a turing machine and have someone drop it
on your head. Next, print out the (R4RS) definition of Scheme and
have someone drop that on your head.
Which is the better language?
I find the smallness of Scheme to be both a thing of beauty and a
curse. When I want to use exceptions in C++, I just go ahead and do
it. When I want to use them in Scheme, I have to go searching the net
for an exceptions library. When I want to use objects in C++, I just
go ahead and do it. When I want to use them in Scheme, I have to go
searching the net for an objects library. When I want to use sets in
C++, I just go ahead and do it (including <set.h>). When I want to
use them in Scheme, I have to go searching the net for a set library.
The things I have to add to Scheme are not consistent with the next
person's things. If one library's exception system is different from
the next library's exception system, what do I do? Do I keep around
five module systems, three macro systems, eight object systems, and
four exception systems?
I still love Scheme ... it's my favorite language. Yet I never use it
for my projects now .. I've switched to using ML or C++. Big isn't
always Bad.
- Amit
> Thant Tessman wrote:
> >
> > GoldenEye wrote:
(For the record, no he didn't. He took the top ten list off of one of
my pages, http://www.cs.indiana.edu/hyplan/pedrake/scheme.html.)
> > As for currying in scheme:
> >
> > (define (curry f arg)
> > (lambda rest (apply f (cons arg rest))))
> >
> > (define add3 (curry + 3))
> > (add3 4) => 7
> >
> > ...which also happens to be a good example of why function pointers are
> > in no way a substitute for higher-order functions.
>
> Eh, no, sorry. That's not a full curry, though it's quite clever. I
What constitutes a full curry, IYHO?
> was unaware of that construct. As long as we're talking about language
> hacks, you could do something similar( though surely not the same not as
> nice ) in C++ with either function poiners, or an object chain.
I wasn't aware that C++ could generate functions (or methods) on the
fly. Pray tell, what is the C++ code equivalent to the above? Also,
what language does offer easy "full" currying?
> > > 7.In Scheme, (* 3 (/ 1 3)) evaluates to 1.
> >
> > David Hanley:
> >
> > > Bad in 2 ways. With integers, this is not the result you
> > > want. Frequently you want integers to behave like integers.
> >
> > No. You mean that sometimes you don't want division to behave like
> > division:
>
> No, the integer division of 1/3 is 0. Period. Claiming this correct
> result as a language defect is foolish.
I want numbers to behave like numbers; I'd rather do rounding
explicitly in those rare instances where I want it.
> I do think that C++ is not a very good language. I'd like to see
> better languages succeed. However, language devotees have a serious
> problem of refusing to see the flaws in thier pet languages. Heck, if
> the language was the best soloution, it would probably be a lot more
> widely used, right?
Non sequitur. The most widely used things are not the best. Look at
Microsoft products. Look at television. Look at McDonald's.
> Refusing to see the problems with a something is highly destriental to
> advancing it's success.
Granted. One of the things I like about Scheme is that it can be
expanded. Procedural abstraction is quite difficult in most other
languages. While the Powers That Be have not agreed on it yet, many
Scheme systems also have a <snorts manfully> REAL macro system, which
allows for defining new syntax. If there's something you don't like
about C++, you're stuck with it.
--
Peter Drake PhD Student in Cognitive Science, IU Bloomington
ped...@cs.indiana.edu http://www.cs.indiana.edu/hyplan/pedrake.html
"There's nothing wrong with you that an expensive operation can't
prolong." -- Surgeon to Mr. Notlob
Could you explain in what way this is not a full curry?
It's not a language hack either, it's fully idiomatic, ordinary Scheme.
--
== Seth Tisue <s-t...@nwu.edu> http://www.cs.nwu.edu/~tisue/
You don't need to.
> Pray tell, what is the C++ code equivalent to the above?
class add1
{
int i1;
int apply( int i2 ) { return i1 + i2; }
}
class add2
{
add1 *apply( int iv ) { return new add1( iv ); }
}
This is just one way; I can think of a lot of others offhand. I used a
somewhat similar technique in a sml->java comiler I am writing, though
that scheme was a bit more elegant( no pun intended ).
Since you're promoting a language which doesn't provide much, and asks
for programmed extensions for the simplest things, I hope you don;t
criticize this use of the C++ object system.
> Also,
> what language does offer easy "full" currying?
SML has a pretty nice curry system.
> > No, the integer division of 1/3 is 0. Period. Claiming this correct
> > result as a language defect is foolish.
>
> I want numbers to behave like numbers; I'd rather do rounding
> explicitly in those rare instances where I want it.
Well, I hope you're ready for:
1) Actual computer programmers misunderstanding when they see integer
division not behaving like integer division.
2) You programs running really slow when that cool integer computation
gets faulted to floating pint.
>
> > I do think that C++ is not a very good language. I'd like to see
> > better languages succeed. However, language devotees have a serious
> > problem of refusing to see the flaws in thier pet languages. Heck, if
> > the language was the best soloution, it would probably be a lot more
> > widely used, right?
>
> Non sequitur. The most widely used things are not the best.
If you had read the paragraph above, you would have seen that I already
know that. However, there are reasons that the widely used things are
widely used. Simply waving our arms and saying that the popular option
sucks doesn't advance the art one iota.
Making silly claims about scheme's supposed superiority to C++ won't
make more commercial projects use scheme, especially if the people who
chose C++ for them chose C++ for those supposed defects, such as the
type system.
> > Refusing to see the problems with a something is highly destriental to
> > advancing it's success.
>
> Granted. One of the things I like about Scheme is that it can be
> expanded. Procedural abstraction is quite difficult in most other
> languages. While the Powers That Be have not agreed on it yet, many
> Scheme systems also have a <snorts manfully> REAL macro system, which
> allows for defining new syntax.
Uck. I _hate_ that. The _last_ thing I want to do when trying to
debug someone else's code is trying to decipher the new language
features they've added. That possibility alone has probably caused
scheme not to be used for some projects.
> If there's something you don't like
> about C++, you're stuck with it.
To an extent, yes. Many projects choose not to use some of the more
esoteric concepts, such as multiple inheretence and the like. Though,
in truth, the only feature I've ever really pined for in C++ is garbage
collection, though people have added that in add-on packages.
dave
> > > No, the integer division of 1/3 is 0. Period. Claiming this correct
> > > result as a language defect is foolish.
> >
> > I want numbers to behave like numbers; I'd rather do rounding
> > explicitly in those rare instances where I want it.
>
> Well, I hope you're ready for:
>
> 1) Actual computer programmers misunderstanding when they see integer
> division not behaving like integer division.
> 2) You programs running really slow when that cool integer computation
> gets faulted to floating pint.
This follows only because many LANGUAGEs define 1 / 3 to be
truncation (or floating point division).
Mathematically, integer division is well defined IF you include
rationals as a possible result. If you do not, you get possible
strange results like
x = 1 / 3
y = 3 * x
and y is 0. Hardly the expected mathematical result of multiplying a
number with is multiplicative inverse.
It's even worse when you multiply large positive integers and get a
negative result because you overflowed a machine register.
Scheme and Lisp try to be mathematically correct. Languages are free
to ignore mathematics in lieu of something that is right most of the
time but is mathematically wrong sometimes.
The bottom line is you must know exactly how the language defines
operations and note that many times they do not match the mathematical
answer.
No need to comment on other things which are basically computer
language flame wars....
Ray
Even if it is so, would you mind writing a C analog of the following
recursive factorial:
(define y-fact
((lambda (f)
((lambda (g)
(f (lambda (arg)
((g g) arg))))
(lambda (g)
(f (lambda (arg)
((g g) arg))))))
(lambda (rec)
(lambda (n)
(if (< n 1)
1
(* n (rec (- n 1))))))))
the point is not whether it is possible or not, actually. Just how
contrived will it be, and how much harder will it be to recognize Y
combinator in it? The point is, any language can do anything, but is
good only for what it's good for.
--Vassili
> There are, in fact, several of us that can consistently remember
>that multiplication and division have higher precedence than addition and
>subtraction.
Sure, but what about * and [] and -> and :: and . and so and so forth?
It's particularly frustrating now that STL iterators have made
(*foo).something_or_other common again.
> *frown* And even if I put parentheses around every single
>subexpression I typed in, my C++ program would still have about half as many
>parentheses (and would, consequently, be about twice as readable) as the
>same program in Scheme.
However, your C++ program still has an order of magnitude more characters with
special syntactic meaning, making it an order of magnitude harder to read, so
you're still losing. You've got () denoting a function call, {} for blocks, ::
for scope resolution < > for template instantiation, *, ., &, and -> for
dealing with accessing bits (excuse me, "objects"), and operator overloading
and implicit casts making things even harder to follow.
How about this:
for (std::list < Big<Hairy<Template<thingamabob<char *> > > >::const_iterator
i = ((derivedtype *)&baseref)->baz()->begin();
i != ((derivedtype *)&baseref)->baz()->end(); i++ )
{
(*i)->do_something();
}
versus (mapc 'do-something i)
(Sorry, that's Common Lisp, my Scheme is rusty).
And yes, I actually *do* have to deal with code that hairy, due to legacy code
and the need to support 4 C++ compilers, each of which implements a subtly
different language.
C++ makes my eyes boggle. You have to go to incredible lengths to do
*anything* high-level and abstract in it, because you have to manually make up
for C++'s lack of anything remotely resembling a decent programming language.
I wouldn't necessarily choose Scheme for delivering apps in, but I would
choose Dylan, which is a Scheme variant, and I've done commercial development
quite nicely thank you very much in Common Lisp.
Foo.
The language defect is C++'s (and C's before it). As we were all taught
in grade school, 1 divided by 3 is 1/3 (one third). And that's what you
get in Scheme... which includes has rational numbers. The fact that C
didn't know about anything but "int" and "double" is a historical wart that
C++ inherited, but it's *NOT* particularly correct -- quite the contrary.
As someone else pointed out, if you *want* truncation in Scheme, you can
*ask* for it, several ways, in fact:
(floor (/ 1 3)) ==> 0
(ceiling (/ 1 3)) ==> 1
or more simply:
(quotient 1 3) ==> 0
It's simply that in Scheme it's not automatic that division of exact numbers
will truncate. Instead, division of exact numbers gives you an exact result,
namely, an exact rational number:
(/ 22674322497976 104331282936392) ==> 617/2839
How do you say *that* in C++?
-Rob
-----
Rob Warnock, 7L-551 rp...@sgi.com
Silicon Graphics, Inc. http://reality.sgi.com/rpw3/
2011 N. Shoreline Blvd. Phone: 415-933-1673 FAX: 415-933-0979
Mountain View, CA 94043 PP-ASEL-IA
I only want to address one topic of your message:
David Hanley <da...@netright.com> writes:
[Note: I'm re-adding the Scheme curry function under discussion]
>>>> (define (curry f arg)
>>>> (lambda rest (apply f (cons arg rest))))
>>>>
>>>> (define add3 (curry + 3))
>>>> (add3 4) => 7
>
> > Pray tell, what is the C++ code equivalent to the above?
>
> class add1
> {
> int i1;
> int apply( int i2 ) { return i1 + i2; }
> }
>
> class add2
> {
> add1 *apply( int iv ) { return new add1( iv ); }
> }
>
> This is just one way; I can think of a lot of others offhand. I used a
> somewhat similar technique in a sml->java comiler I am writing, though
> that scheme was a bit more elegant( no pun intended ).
Maybe it's my lack of understanding of C++, but it doesn't look
equivilant to me. Given the above definitions, I would almost say
that the equivilant to your add2 would be (curry curry +).
Give me a curry function in C++ (perhaps heavily templated and
overloaded) that would allow me to do the equivilant of the following
(using the above Scheme definition of the curry function):
(define add3 (curry + 3))
(define 5-or-greater (curry max 5))
(add3 4) => 7
(add3 4 5 6) => 18
(5-or-greater 1) => 5
(5-or-greater 1 2 3 4) => 5
(5-or-greater 4 5 6) => 6
Allowing me to use int add(int,...) and int max(int,...) functions,
although preferrably I'd like to use arbitrary classes and function
arities.
The closest I can see is something like so:
template<Type1,Type2,Type3>
class curry {
Type1 (*fun)(Type2,Type3);
Type2 arg;
public:
curry(Type1 (*f)(Type2,Type3),Type2 a) : fun = f; arg = a; {}
Type1 operator()(Type3 arg2) {return (*fun)(arg,arg2)}
};
But that limits one to reducing functions with two arguments to
functions with one argument, not quite the same as the scheme version.
--
Buddha Buck bmb...@acsu.buffalo.edu
"Just as the strength of the Internet is chaos, so the strength of our
liberty depends upon the chaos and cacaphony of the unfettered speech
the First Amendment protects." -- A.L.A. v. U.S. Dept. of Justice
Maybe I just went to a bad school, but was learned about something
called "integers" first. If i remember correctly, when dividing these
"integers" 1/3 the correct result was zero. I use this kind of stuff a
lot when I write computer programs, and am saddened that I've been using
an invalid construct all these years. ( note sarcasm )
> And that's what you
> get in Scheme...
The fact it gives a wrong result doesn't impress me too much.
> which includes has rational numbers. The fact that C
> didn't know about anything but "int" and "double"
hardly--it has short, long, float, et al.
dave
David Hanley <da...@netright.com> wrote:
+---------------
| No, the integer division of 1/3 is 0. Period. Claiming this correct
| result as a language defect is foolish.
+---------------
The language defect is C++'s (and C's before it). As we were all taught
in grade school, 1 divided by 3 is 1/3 (one third). And that's what you
get in Scheme... which includes has rational numbers.
Actually, 1/3 is 2. No, I am not kidding, I am just doing arithmetic
in Z_5 -- the (finite) field you get by taking the integers mod 5.
The "fact" that (/ 1 3) is 1/3, or 0, or 2, ... is nothing but an
_arbitrary_ choice. Of course, 1/3 is the most common choice outside
of computer programming, so you might argue that 1/3 is the "correct"
result. But it is only correct up to the definition of what the
division operator does on integers. The definitions for C and Scheme
are different, both are correct. We can argue about the usefulness of
either, not about correctness.
It's simply that in Scheme it's not automatic that division of exact numbers
will truncate. Instead, division of exact numbers gives you an exact result,
namely, an exact rational number:
(/ 22674322497976 104331282936392) ==> 617/2839
Scheme implementations are only encourages, not required to give the
above result. An error due to implementations restrictions may be
signalled as well. So much for Scheme's alleged portability.
--
-Matthias
okay.
> Maybe it's my lack of understanding of C++, but it doesn't look
> equivilant to me. Given the above definitions, I would almost say
> that the equivilant to your add2 would be (curry curry +).
>
> Give me a curry function in C++ (perhaps heavily templated and
> overloaded) that would allow me to do the equivilant of the following
> (using the above Scheme definition of the curry function):
>
> (define add3 (curry + 3))
> (define 5-or-greater (curry max 5))
> (add3 4) => 7
> (add3 4 5 6) => 18
> (5-or-greater 1) => 5
> (5-or-greater 1 2 3 4) => 5
> (5-or-greater 4 5 6) => 6
>
C doesn't have a way ( simple ) way to have a one-parameter funcrion
take a string of parameters, but this is how I implemented this in the
ml->java compiler:
First, in the class library:
class CurryBase {
protected int intApply() { retutn intApplication(); }
virtual intApplication() = 0;
}
class CurryInt : CurryBase
{
int i1;
CurryBase *CurryInt( int i ) { i1 = i; return this; }
}
class CurryIntInt : CurryInt
{
int i2;
CurryInt *CurryInt( int i ) { i2 = i; return this; }
}
Now, we can extend CurryIntInt:
class Adder : CurryIntInt // needs two integers
{
int intApplication() { return i1 + i2; }
}
class Max5 : CurryInt // needs one integer
{
int intApplicaion() { return max( i1 , 5 ); }
}
So, when we want to curry, we extend a class which represents the tuple
we want to process at the result of the curry process. It's more
keystrokes then the scheme code you posted, but I'm not sure if it's
better or worse.
When you apply an integer to an object that wants two integers, you get
an object that wants one integer. When you apply an integer to an
object that wants one integer, you get an object to which you can apply
an application method, yeilding your result. At each step along the
way, you can pass the objects around, etc,etc. The helper class
hierarchy can be generated with templates.
> class Adder extends Curry
> Allowing me to use int add(int,...) and int max(int,...) functions,
> although preferrably I'd like to use arbitrary classes and function
> arities.
>
> The closest I can see is something like so:
>
> template<Type1,Type2,Type3>
> class curry {
> Type1 (*fun)(Type2,Type3);
> Type2 arg;
>
> public:
> curry(Type1 (*f)(Type2,Type3),Type2 a) : fun = f; arg = a; {}
> Type1 operator()(Type3 arg2) {return (*fun)(arg,arg2)}
> };
>
> But that limits one to reducing functions with two arguments to
> functions with one argument, not quite the same as the scheme version.
That would work too, probably faster, though a bit less flexible.
dave
The R4RS does not require all implementations to support rationals.
They are an optional feature. So I strongly disagree with your
blanket statement "In Scheme...".
*Some* scheme implementations support bignums and rationals. Others
don't even unlimited precision "bignum" integers, and have smaller
integers than C implementations on the same machine.
Scheme's generic arithmetic has in some sense been one of the achilles'
heels of the language, since it is difficult to compile to efficient
code in common cases.
>How do you say *that* in C++?
Well, C++ has operator overloading and user-defined types. It would
be pretty easy, just like the usual textbook example of complex numbers.
Remember... "C++: The most elaborate complex number extension ever
added to a language."
--
Mike Haertel <hae...@ichips.intel.com>
Not speaking for Intel.
I think this has been the most correct post so far (but then
again, I study math). I personally think that the integer division of
1/3 should be an error, since 1/3 doesn't exist. This probably isn't
the most useful interpretation for computer programming, but then
again, we've strayed from talking about that.
I'd also like to add that, quibbles aside, I thought the 10
reasons were pretty funny. That seems to have been lost in the
shuffle.
| From: Raymond Toy <t...@rtp.ericsson.se>
| Date: 03 Dec 1996 15:47:08 -0500
|
| It's even worse when you multiply large positive integers and get a
| negative result because you overflowed a machine register.
Or even add them and get a nonsense negative result.
This is a much better example of why generic arithmetic in Lisp and
Scheme is a win in many cases. After all, the ring of integers is
well understood, and so is the ring of integers modulo any value
(including 2^16, 2^32, 2^64).
The problem with the lack of bignums in C and ML (the trapping
behavior of signed overflow in ML is not really adequate) is that it
makes the meaning of a program dependent on the machine word size and
the choice that the compiler-writer made for the size of one or
several flavors of integers.
Yes, this leads to greater efficiency in the absence of both hardware
and runtime system support, but it also leads to porting problems when
going to a different compiler or machine.
:-) I think you should re-read what you just wrote, as it's
rather funny. If you include rationals as a possible result,
then you're not doing integer division, since a rational number
is, by definition, not an integer - it's a rational. Integer
division of 1 by 3 produces a result of 0 - there's no other
way to present the result in the integer number system. If you
want to handle rational results on a computer, you must use
floating point (and start worrying about round-off error, truncation
error, etc., etc., etc.) Whole courses are taught in
Computer Science which deal with nothing but this single area
of computation - it is by no means a simple topic.
BTW, 1/3 is an irrational, not a rational, and there's no way to
represent that precisely at all (using floating point) on a computer.
Thus, in the example you give, y will never equal x no matter
what computer language you use. (Do any of the symbolic manipulation
packages like Maple have a way of handling this better?)
-- Rob
==============================================================
Rob McDermid Hummingbird Communications Ltd.
mcde...@hcl.com All opinions expressed are my own.
==============================================================
Bzzzzzzzzzzt!
So what would this code look like if you used templates or whatever to
extend it to work on other things besides integers?
Curious,
BTW, 1/3 is an irrational, not a rational,
Huh?
and there's no way to
represent that precisely at all (using floating point) on a computer.
Thus, in the example you give, y will never equal x no matter
what computer language you use. (Do any of the symbolic manipulation
packages like Maple have a way of handling this better?)
Of course -- by using rational numbers. (Which, btw, are _not_ to be
confused with floating point.)
--
-Matthias
It is too a rational. It's the ratio of two integers. It's a repeating
decimal. And it can be expressed exactly in base 3 as 0.1, in base 6
as 0.2, in base 12 as 0.25, and so on.
In fact, it would be interesting to write a package that used "BCDD"
(Binary-Coded DuoDecimal) to represent floating-point numbers, since
many more rational numbers would then have exact representations.
IMHO, anyway.
--Mark
--
Mark Meiss (mme...@indiana.edu) | No eternal reward will
Indiana University CS Dept. | forgive us now for - Jim Morrison
Bloomington, Indiana, USA | wasting the dawn.
BTW, 1/3 is an irrational, not a rational,
This will be news to many generations of mathematicians. 1/3 is more rational
than I am.
and there's no way to represent that precisely at all (using floating
point) on a computer.
Certainly there is; just use base 3 arithmetic. (Of course you'll have to
*implement* it all, which is a tad tricky, and there might be a little
performance reduction, but the principle's sound.)
Perhaps you mean that 1/3 has no finte exact representation in base 2 (or
10)? That's rather different from being ``irrational'', surely?
Thus, in the example you give, y will never equal x no matter
what computer language you use. (Do any of the symbolic manipulation
packages like Maple have a way of handling this better?)
Yes, they represent 1/3 as 1/3. The obvious implementation that comes to mind
is to represent a rational as a pair of integers with highest common factor
1. (That's what Poplog does, although it's not a symbolic manipulation
package.)
--
Regards, | "You're better off not dreaming of the things to come;
Kers. | Dreams are always ending far too soon." - Caravan.
>
> C doesn't have a way ( simple ) way to have a one-parameter funcrion
> take a string of parameters, but this is how I implemented this in the
> ml->java compiler:
OK, so I'll ignore the multiple arity issue for now.
> First, in the class library:
> class CurryBase {
> protected int intApply() { retutn intApplication(); }
> virtual intApplication() = 0;
> }
> class CurryInt : CurryBase
> {
> int i1;
> CurryBase *CurryInt( int i ) { i1 = i; return this; }
> }
> class CurryIntInt : CurryInt
> {
> int i2;
> CurryInt *CurryInt( int i ) { i2 = i; return this; }
> }
> Now, we can extend CurryIntInt:
> class Adder : CurryIntInt // needs two integers
> {
> int intApplication() { return i1 + i2; }
> }
> class Max5 : CurryInt // needs one integer
> {
> int intApplicaion() { return max( i1 , 5 ); }
> }
> So, when we want to curry, we extend a class which represents the tuple
> we want to process at the result of the curry process. It's more
> keystrokes then the scheme code you posted, but I'm not sure if it's
> better or worse.
OK, but does this scheme allow me to generate curried functions at run-time?
In scheme, I can pass curry a function that I can't determine what is
at compile-time, such as the comparison function used in qsort(). (I
doubt it if creating a less_than_pivot(void*) in this case would be
worth the effort, but is certainly is one implementation).
(This could be solved by having intApplication be not a virtual null
member function, but rather a pointer to an int(int,int), and
modifying the constructor appropriately, I guess. But that sort of
puts you where I was below).
I can also use as my argument to be curried any arbitrary run-time
value, as opposed to the Max5 class above (effectively, a MaxN class).
> When you apply an integer to an object that wants two integers, you get
> an object that wants one integer. When you apply an integer to an
> object that wants one integer, you get an object to which you can apply
> an application method, yeilding your result. At each step along the
> way, you can pass the objects around, etc,etc. The helper class
> hierarchy can be generated with templates.
> > The closest I can see is something like so:
> > template<Type1,Type2,Type3>
> > class curry {
> > Type1 (*fun)(Type2,Type3);
> > Type2 arg;
> > public:
> > curry(Type1 (*f)(Type2,Type3),Type2 a) : fun = f; arg = a; {}
> > Type1 operator()(Type3 arg2) {return (*fun)(arg,arg2)}
> > };
> > But that limits one to reducing functions with two arguments to
> > functions with one argument, not quite the same as the scheme version.
> That would work too, probably faster, though a bit less flexible.
I fail to see it as less flexible. It generates curries at run-time,
instead of using distinct classes for each curry, and allows arbitrary
2-arity functions with arbitrary return values.
Extending this seamlessly to 3-arity or higher functions doesn't seem
as simple as in your example, I will admit.
(If I am missing something, -please- explain: I'm a college student
who has never had a formal class in Scheme or any Lisp-like language,
and this is the first semester that C++ has been thrust upon me. It
is very likely that I am indeed missing something due to lack of
exposure and experience.)
In line with the previous parethesized remark, what, exactly, do you
mean by "full currying" as opposed to what the Scheme implementation
does? You stated a few messages ago that the scheme code didn't do
full currying. To my understanding (albeit limited), it does
(generates a function of n-1 arguments out of a function of n
arguments plus an argument).
Or would you prefer having to use syntax like so:
(define (5args a1 a2 a3 a4 a5)
(+ a1 a2 a3 a4 a5))
((((((curry 5args) 5) 4) 3) 2) 1) => 15
which could be considered "full currying" (replacing a function that
takes n arguments with a series of functions that take one argument
each and return a function that takes one argument each).
> dave
> > The language defect is C++'s (and C's before it). As we were all taught
> > in grade school, 1 divided by 3 is 1/3 (one third).
No, no no!!
Even the most hardend mathematicians agree that 1/3 is 0 if 1 and 3 are
in the INTEGER domain. To evaluate the division of one integer with
another integer will result in an integer, whether using programming
lanuages, alogrithms on paper or whatever. Integers have well defined
properties as does integer division - this is not in any way a fault of
C++.
Besides, what C++ does do is let you create your own types, which in
turn could represent numbers as numerators and denominators, and
redefine the meaning of operators which act upon them. C++ is pretty
poineering (and still unique, I believe) in this respect. What you have
described in Scheme takes that flexibilty away from you - can it do
integer division?
If you don't want to do integer division, don't use integers. This is
why C++ is a strongly typed language - unlike BBC BASIC say which also
dynamically altered the types of variables.
Are you saying BASIC is better than C++.
Stu
>
> David Hanley wrote:
>
> If you don't want to do integer division, don't use integers. This is
> why C++ is a strongly typed language - unlike BBC BASIC say which also
> dynamically altered the types of variables.
\begin{Pedant mode}
Actually BBC BASIC was in a sense strongly typed, just that the typing
information was included in the variable name.
So A$ could only hold string values
A could only hold floating point values and A% could only hold integer
values.
Further A$ A% and A where distinct variables. I don't think there was
a way of dynamically altering the types of variables in BBC Basic.
\end{Pedant mode}
Sorry to pick nits, but the number in base 12 is 0.4.
--
-------------------------------------------------------------
Will Ware <ww...@world.std.com> web <http://world.std.com/~wware/>
PGP fingerprint 45A8 722C D149 10CC F0CF 48FB 93BF 7289
Well, if I'm picking nits, I deserve to have my nits picked too.
Yeah, what you said. My brain burped halfway back into base 10 there.
That's simply not true! You just can't divide the integer 1 by the
integer 3 and get an integer result. It certainly is not zero. You can
enlarge the ring of integers with their field of fractions to get the
rational numbers and then 1 / 3 = 1/3. If you want a result like 0 you
should take the floor or the the Gauss bracket of 1/3. Scheme is
(thankfully) one of the few languages that gets arithmetic right.
Andreas Eder
I wrote:
> Function pointers are in no way a substitute for
> higher-order functions.
> As for currying in scheme:
>
> (define (curry f arg)
> (lambda rest (apply f (cons arg rest))))
>
> (define add3 (curry + 3))
> (add3 4) => 7
>
>...which also happens to be a good example of why function
> pointers are in no way a substitute for higher-order functions.
Kent Tong wrote:
> This can be done in C++ or Java if all the functions take
> their parameters from an array or something like that.
> Then all we need to do is to store "f" and "arg" in a
> (functional) object just like what you did.
How convenient.
Actually, I've built a curry system for C++ using templates. You
can do things like this:
void f(const int& i, const int& j) {
cout << i << " " << j << endl;
}
Thunk1<int> f2 = curry1(f, 23);
Thunk0 f3 = curry0(f2, 5);
f3();
"curry0" and "curry1" are function templates that automatically
instantiate other helper template classes. "f2" is a function
object taking a single integer as an argument, and "f3" is a
function object taking no arguments. The output of evaluating
"f3()" is "23 5" as one would expect. You can even combine
the two statements and evaluate them immediately like this:
(curry0(curry1(f, 23), 5))();
Now given that we're working in C++, you gotta admit this is
pretty cool--certainly better than passing arguments in by way
of an array. But let's start comparing it to, say, the Scheme
example above, or the equally fully-polymorphic yet type-safe
equivalent in SML.
First off, this C++ version was a pain to write, and it took a
long time to get it correct. Second, it's a pain to use because
you have to produce a different version of the template function
for every possible number of arguments (note the "1" and "0" in
curry1 and curry0 and Thunk1 and Thunk0) *and* for every possible
return type. (I've only built them for functions and function
objects returning void.) Also, you have to have a different
version for whether you're going to pass arguments by reference,
or literally on the stack. (I've only implemented the former,
which is why "f" takes "const int&" instead of "int".)
And to top it off, I have a completely different set of
template functions for packaging up objects and member
function pairs into thunks. (They do mix and match though.)
Some people might think that this is a good demonstration
of how expressive C++ is. Compared to C, yeah, sure. But
the truth is that it took several orders-of-magnitude longer
to implement than the equivalent Scheme or SML construct, and
yet it is also a much more awkward and less general solution.
And attempts to further generalize the solution always start
looking like full-fledged interpreters in their own right, so
you lose the supposed benefits of using C++ in the first place.
C++ just plain sucks. But you'll never know that if all you've
ever programmed in is C++ (or C, or Pascal, or Fortran, or
COBOL).
-thant
--
Thant Tessman <th...@acm.org>
Dennis
OK, try doing low-level work in scheme? Previous posts in the assembly vs
C/C++ thread referred to blit-scale function. ;-). I've no idea if this
could be written in Scheme or not. Does Scheme support pointers? I've no
idea.
C/C++ is a systems programming language. I doubt the developers of C cared
about whether 1/3 would be represented as a fraction, or about currying.
;-).
There any Scheme-based operating systems about?
Scheme, SML, C, C++, heck even assembly Use the right tool for the work
you're trying to do.
Dennis
Thant Tessman <th...@shoreline-studios.com> wrote in article
<32A6F7...@shoreline-studios.com>...
>> > No, the integer division of 1/3 is 0. Period. Claiming this correct
>> > result as a language defect is foolish.
>>
>> I want numbers to behave like numbers; I'd rather do rounding
>> explicitly in those rare instances where I want it.
>
> Well, I hope you're ready for:
>
> 1) Actual computer programmers misunderstanding when they see integer
>division not behaving like integer division.
> 2) You programs running really slow when that cool integer computation
>gets faulted to floating pint.
In scheme integer arithmetic will never get faulted to floating point!
Integer arithmetic will always stay integer arithmetic; if you cross the
fixnum boundary it might get slower, but at least you will get the right
result. And integer + integer is never a floating point, but always
integer.
>> Non sequitur. The most widely used things are not the best.
>
> If you had read the paragraph above, you would have seen that I already
>know that. However, there are reasons that the widely used things are
>widely used. Simply waving our arms and saying that the popular option
>sucks doesn't advance the art one iota.
>
> Making silly claims about scheme's supposed superiority to C++ won't
>make more commercial projects use scheme, especially if the people who
>chose C++ for them chose C++ for those supposed defects, such as the
>type system.
There"s no need here to advance the art. There are already better
things, and the reasons why the aren't used but obvioulsy inferior
things are mor of a psychological end educational nature. (You could
also say marketing). Do you really think that most commercial projects
are done in C or C++, because they are technically superior to other
languages ? No, it's because they simply don't know about modern
developments in programming languages!
>> > Refusing to see the problems with a something is highly destriental to
>> > advancing it's success.
>>
>> Granted. One of the things I like about Scheme is that it can be
>> expanded. Procedural abstraction is quite difficult in most other
>> languages. While the Powers That Be have not agreed on it yet, many
>> Scheme systems also have a <snorts manfully> REAL macro system, which
>> allows for defining new syntax.
>
> Uck. I _hate_ that. The _last_ thing I want to do when trying to
>debug someone else's code is trying to decipher the new language
>features they've added. That possibility alone has probably caused
>scheme not to be used for some projects.
Uck. I _hate_ that. The _last_ thing I want to do when trying to
debug someone else's code is trying to decipher the new procedures
they've added. Why can't they just use the predefined functions and
write everything in one big file full of asm statements. :-)
Seriously, abstraction helps to debug other peoples code, if it's done
right. And to do that properly you often need a good macro system. (Not
what C programmers think is a macro system).
Andreas
Andreas
Oops. Sorry, brain wasn't working very well towards the end of the day.
>
>In fact, it would be interesting to write a package that used "BCDD"
>(Binary-Coded DuoDecimal) to represent floating-point numbers, since
>many more rational numbers would then have exact representations.
>IMHO, anyway.
>
Didn't Borland used to have this as part of their C library? Or was
it just BCD?
Once you start getting into special-purpose math packages you can
do almost anything, of course, at the expense of efficiency (at least
on a binary-hardware computer). Of course, all of the compromises
we routinely make in mathematics on computers are directly related
to increasing the computation speed in binary, for general purpose
computation.
This is a pretty rediculous thread. Do you think any C++ programmers are
going to think, "Gee, currying is so much easier in Scheme, I think I
will switch." Hell, I don't even know what currying is. It is the same
for the blit-scale function in assembler is better argument. It is such
a infinitesimal part of what we do that it contributes nothing to the
discusion of what language is better. In addition, before this thread, I
have never even heard of Scheme. I'm not aware of a Borland, Symantec,
Microsoft or Metrowerks Scheme compiler. Where is the support for the
great language? It really would not matter if the Scheme semantics were
100 times better than C++. I'm going to use the language that brings me
the highest hourly rate and the most billable hours period.
Michael
| From: Stuart I Reynolds <s...@cs.bham.ac.bham>
| Date: Thu, 05 Dec 1996 11:53:45 +0000
|
| Besides, what C++ does do is let you create your own types, which in
| turn could represent numbers as numerators and denominators, and
| redefine the meaning of operators which act upon them. C++ is pretty
| poineering (and still unique, I believe) in this respect. What you have
| described in Scheme takes that flexibilty away from you - can it do
| integer division?
Scheme can do both integer and complex number division (in an
implementation that supports the full numeric tower).
The / operator performs complex division. The quotient operator
performs integer division.
Scheme has not taken the flexibility away. It has just made a
different choice on the meaning of a common operator.
The generic arithmetic of Scheme (and other Lisps) isolates from
word-size vagaries (implementations often have limited-size operators
as well, but not the standard) and some loss of accuracy.
> However, your C++ program still has an order of magnitude more characters with
> special syntactic meaning, making it an order of magnitude harder to read, so
> you're still losing. You've got () denoting a function call, {} for blocks, ::
> for scope resolution < > for template instantiation, *, ., &, and -> for
> dealing with accessing bits (excuse me, "objects"), and operator overloading
> and implicit casts making things even harder to follow.
I disagree. A language in which you have [] for array element
access is easier to read than one that uses (), especially if () has
other meanings.
I like having {} for blocks and () for function calls... versus
() for blocks and () for function calls. Yeesh.
* . & -> are used for two reasons: (a) with pointers, because
C++ can do that kind of thing; (b) with iterators, because C++ has no
lambdas (ouch).
> How about this:
>
> for (std::list < Big<Hairy<Template<thingamabob<char *> > > >::const_iterator
> i = ((derivedtype *)&baseref)->baz()->begin();
> i != ((derivedtype *)&baseref)->baz()->end(); i++ )
> {
> (*i)->do_something();
> }
>
> versus (mapc 'do-something i)
Well, the C++ will actually work, but your Lisp is buggy. (Lisp
also would give you the error in the wrong place, whereas if there were an
error in the C++ code, the compiler would flag it at the actual line where
your typo was.)
> And yes, I actually *do* have to deal with code that hairy,
Everybody does. :o\ The fact that C++ is as yet nonstandard
hurts a lot.
But in a feeble attempt to show the good side of C++, even in a
bad situation: In C++, you know that the cast to (derivedtype *) isn't
entirely safe (and you have plenty of time to think about it, as you
type... *ruegrin*) And of course the C++ will run faster, and without
unnecessary runtime checking.
Priorities...
> C++ makes my eyes boggle. You have to go to incredible lengths to do
> *anything* high-level and abstract in it, because you have to manually make up
> for C++'s lack of anything remotely resembling a decent programming language.
*laugh* I'll have to keep that one. Thanks for the food for
thought.
--Mohammed
No: the correct result in the domain of integers is 0 with a remainder of 2.
to handle such results more concisely, fractions were invented.
>lot when I write computer programs, and am saddened that I've been using
>an invalid construct all these years. ( note sarcasm )
> ...
> The fact it gives a wrong result doesn't impress me too much.
It gives you the right result in the domain of rational numbers, and there
either is a library function or you can write one yourself for each of the
following desired results:
- integer quotient
- remainder
- pair of quotient and remainder
>> which includes has rational numbers. The fact that C
>> didn't know about anything but "int" and "double"
>
> hardly--it has short, long, float, et al.
>
> dave
Hartmann Schaffer
Even the most hardend mathematicians agree that 1/3 is 0 if 1 and 3 are
in the INTEGER domain.
Nonsense. There is no division in the integer domain. That is to
say, in the ring of integers there doesn't exist a multiplicative
inverse for most of the elements. What you call integer division is a
very different concept. And here the answer 0 for 1/3 is not even
complete, because you forgot to mention the remainder. The result of
integer division is _two_ numbers: a quotient and a remainder.
Unfortunately, languages which get this right are extremely rare, even
though most microprocessors actually calculate both numbers at the
same time.
To evaluate the division of one integer with
another integer will result in an integer, whether using programming
lanuages, alogrithms on paper or whatever. Integers have well defined
properties as does integer division - this is not in any way a fault of
C++.
Yes, it is just a different concept, not at all the same as taking the
inverse in a domain that provides such multiplicative inverses. If
you make clear beforehand what you are talking about, then, of course,
there is no confusion later on. As I pointed out in another reply
before, you could just as easily define 1/3 to be 2. And it would
even make sense.
It is C's fault to denote two very different concepts by the same
symbol: /. C++ has inherited this fault. Furthermore, by allowing
programmers to add their own overloads it has made the situation
worse. Example: cout << 2 << 2. This one should print "22". On
the other hand: cout << (2 << 2) completely changes the meaning of the
second << and prints "8".
Besides, what C++ does do is let you create your own types, which in
turn could represent numbers as numerators and denominators, and
redefine the meaning of operators which act upon them. C++ is pretty
poineering (and still unique, I believe) in this respect.
Huh? Do you actually know any other language. C++ is by no means
pioneering in _any_ respect.
What you have
described in Scheme takes that flexibilty away from you - can it do
integer division?
Of course. Except, in Scheme you use a different name for that
operation (which is appropriate, since it is conceptually very
different).
--
-Matthias