Lisp on Lines

D

Daniel Brockman

I think what's going on here is that it's making a copy of
the method instead of just pointing a variable at it.

Actually, since methods are themselves immutable, making a
copy of one would have the same effect as =E2=80=9Cjust pointing a
variable at it,=E2=80=9D except it would be slower.

My point is that =E2=80=98def a.b ; 1 end ; def a.b ; 2 end=E2=80=99 is m=
ore
like =E2=80=98a.b =3D lambda {1} ; a.b =3D lambda {2}=E2=80=99 and less l=
ike
=E2=80=98a.b =3D lambda {1} ; a.b.body =3D "2"=E2=80=99. (Of course, thi=
s last
statement is completely bogus.)

If that doesn't make sense, forget I ever said anything.
I know I mean, and I know you know what you mean. :)

--=20
Daniel Brockman <[email protected]>

So really, we all have to ask ourselves:
Am I waiting for RMS to do this? --TTN.
 
L

Lothar Scholz

Hello Brian,



BM> Er, there are quite a few open source CL implementations

BM> http://www.cliki.net/Common Lisp implementation

Unfortunately there is no good plattform independent CL
implementation - all of them lack windows support. And none of
the free have good multithreading support, for this you must send
some many to Franz Inc.

It's sad to see the Lisp world in such a bad state.
 
A

Adrian Howard

On 26 Jul 2005, at 07:37, Lothar Scholz wrote:
[snip]
Unfortunately there is no good plattform independent CL
implementation - all of them lack windows support. And none of
the free have good multithreading support, for this you must send
some many to Franz Inc.
[snip]

OpenMCL has native threads doesn't it? Now if you want unicode /and/
threads you're out of luck ;-)

Adrian
 
D

Devin Mullins

One could generalize that solution:

class Symbol
def to_proc
lambda { |a,*b| a.send(self,*b) }
end
end

[1,2,3].inject(&:+)

(For some reason, irb complained unless I put parens around it.)

For an even shorter version, here's my APL subset for Ruby:

class Symbol
def *(ary)
ary.inject {|a,b| a.send(self, b)}
end
def [](*ary)
self * ary
end
end
class Array
def +@
:+*self
end
def -@
:-*self
end
end

Now, :+*[1,2,3], :+[1,2,3], and +[1,2,3] are all valid. (Not that I=20
actually use this libary; just came up with it to make a point about=20
Ruby to somebody. :p)

(I would've overloaded /, but Ruby kept thinking I was trying to=20
construct a regular expression.)

And here's a vaguely neat extension of that idea:

class Symbol
def **(ary)
ary.inject { |a,b| a.send(self, *b) }
end
end

:gsub ** ["Hello!",
[/Hell/,"Good"]
[/o!/,"bye.]]

Talk about reducing duplication. :)

Devin

Daniel said:
Hi Joe,

=20
Sorry, please bear with me... the Lisp I had in mind was
more like:

(setf a #'length)
(funcall a "foo")

(Hard to make an exact parallel because Ruby has methods
not functions, and Lisp AFAIK has functions not
methods...?)
=20

Ruby has both methods and functions, but methods are more
primitive than functions. In particular, functions are
objects and thus have methods. Methods, on the other hand,
are not objects (and they are not functions). So functions
are implemented using methods, not the other way around.

As for the example code, the closest Ruby equivalent would
have to be something like the following:

a =3D :length
"foo".send(a)

This is because in Ruby, polymorphism is implemented by
having different =E2=80=98length=E2=80=99 methods for different objects,
whereas in Lisp, there is just one function =E2=80=98length=E2=80=99 tha= t
handles all types of objects. (Of course, CLOS simplifies
the task of adding new clauses by way of defmethod, but a
generic function is still just one function.)

=20
Setting a variable to the function itself seems pretty
different than wrapping a call to the function in a lambda,
=20

Again, there is not just a single =E2=80=98length=E2=80=99 method in Rub= y,
so you can't =E2=80=9Cset a variable to the function itself.=E2=80=9D T= he
closest analogy to the =E2=80=9Cfunction itself=E2=80=9D is the method n= ame.
=20

but honestly, now I can't think of what the actual
implications would be... other than a little bit of
additional terseness in calls like

(reduce #'+ '(1 2 3))
vs.
[1, 2, 3].inject {|a,b|a+b}
=20

You could actually define the equivalent of Lisp's =E2=80=98+=E2=80=99
function in Ruby, by doing this:

module Kernel
def +(a, b) a + b end
end

Then the example with inject could be written like this:

[1,2,3].inject &method:)+)

But this will fail when someone overrides the =E2=80=98+=E2=80=99 operat= or,
in which case you need to do something like this:

[1,2,3].inject &Object.new.method:)+)

Much cleaner would be to define the function in a separate
namespace so that name clashes are avoided:
=20
Function =3D Object.new
class << Function
alias [] method
def +(*terms) terms.inject(0) { |a, b| a + b } end
end

Now the example looks like this:

[1,2,3].inject &Function[:+]

You could go one step further:

class Symbol
def to_proc
Function[self].to_proc
end
end

Note that if you take the Kernel#+ approach, the above
implementation needs to be much hairier:

class Symbol
def to_proc
Binding.of_caller do |boc|
eval(%{method:)#{self})}, boc).to_proc
end
end
end

Now you can reduce the original example (no pun intended)
to the following,

[1,2,3].inject &:+

which is actually *shorter* than the equivalent Lisp code.

By the way, a more popular definition of Symbol#to_proc is
to have =E2=80=98foo.each &:bar=E2=80=99 equal =E2=80=98foo.each { |x| x= bar }=E2=80=99.
This won't work in the above example because we cannot use
the Fixnum#+ method to fold an array of integers (since it
only takes one argument!).

(If you want both variants of Symbol#to_proc, I guess you
could use a unary plus or minus operator to disambiguate.
However, =E2=80=98[1,2,3].inject &-:+=E2=80=99 is starting to look rathe= r
much like line noise.)

=20
 
J

Joe Cheng

Daniel said:
Hi Joe,

=20

Ruby has both methods and functions, but methods are more
primitive than functions. In particular, functions are
objects and thus have methods. Methods, on the other hand,
are not objects (and they are not functions). So functions
are implemented using methods, not the other way around.
=20
Interesting--that's the first I've heard of it. Do you have a link to=20
some documentation about functions? I don't see anything in the PickAxe=20
or ri.

Oh, is it the Function[] syntax you demonstrate below?
As for the example code, the closest Ruby equivalent would
have to be something like the following:

a =3D :length
"foo".send(a)

This is because in Ruby, polymorphism is implemented by
having different =E2=80=98length=E2=80=99 methods for different objects,
whereas in Lisp, there is just one function =E2=80=98length=E2=80=99 tha= t
handles all types of objects. (Of course, CLOS simplifies
the task of adding new clauses by way of defmethod, but a
generic function is still just one function.)
=20
I understand. I was not concerned about polymorphic methods vs.=20
functions, but rather the ability to directly capture a reference to a=20
[method|function].

Let me try illustrating in Boo instead:

class Foo:
def bar():
print("hello")

a =3D Foo() # calling Foo constructor
b =3D a.bar
b() # same as calling a.bar()

This is different than what you are trying to accomplish in your post,=20
and admittedly, even pretty different from what my Lisp example was in=20
terms of functionality.
Again, there is not just a single =E2=80=98length=E2=80=99 method in Rub= y,
so you can't =E2=80=9Cset a variable to the function itself.=E2=80=9D T= he
closest analogy to the =E2=80=9Cfunction itself=E2=80=9D is the method n= ame.
=20
I was looking for something like the above example in Boo. Although=20
using lambda/proc, send:)symbol), or method:)symbol), they all seem to=20
accomplish the task (with useful differences in behavior between the=20
three of them).
but honestly, now I can't think of what the actual
implications would be... other than a little bit of
additional terseness in calls like

(reduce #'+ '(1 2 3))
vs.
[1, 2, 3].inject {|a,b|a+b}
=20
You could actually define the equivalent of Lisp's =E2=80=98+=E2=80=99
function in Ruby, by doing this:

module Kernel
def +(a, b) a + b end
end

Then the example with inject could be written like this:

[1,2,3].inject &method:)+)
=20
That is actually pretty close. I've never seen the &-syntax (that is,=20
not from the caller)... I can see there are a lot of possibilities with=20
that.
But this will fail when someone overrides the =E2=80=98+=E2=80=99 operat= or,
in which case you need to do something like this:

[1,2,3].inject &Object.new.method:)+)

Much cleaner would be to define the function in a separate
namespace so that name clashes are avoided:
=20
Function =3D Object.new
class << Function
alias [] method
def +(*terms) terms.inject(0) { |a, b| a + b } end
end

Now the example looks like this:

[1,2,3].inject &Function[:+]

You could go one step further:

class Symbol
def to_proc
Function[self].to_proc
end
end

Note that if you take the Kernel#+ approach, the above
implementation needs to be much hairier:

class Symbol
def to_proc
Binding.of_caller do |boc|
eval(%{method:)#{self})}, boc).to_proc
end
end
end

Now you can reduce the original example (no pun intended)
to the following,

[1,2,3].inject &:+

which is actually *shorter* than the equivalent Lisp code.
=20
Wow, that is really cool. Although one problem... my irb is complaining=20
about Binding.of_caller not being defined. Do I need to require=20
something first?
By the way, a more popular definition of Symbol#to_proc is
to have =E2=80=98foo.each &:bar=E2=80=99 equal =E2=80=98foo.each { |x| x= bar }=E2=80=99.
This won't work in the above example because we cannot use
the Fixnum#+ method to fold an array of integers (since it
only takes one argument!).

(If you want both variants of Symbol#to_proc, I guess you
could use a unary plus or minus operator to disambiguate.
However, =E2=80=98[1,2,3].inject &-:+=E2=80=99 is starting to look rathe= r
much like line noise.)
=20
I didn't mean to emphasize #'+, it is just the canonical example in the=20
Lisp tutorials I've read... :)

Thanks for the very interesting response, I learned a lot.
 
D

Daniel Brockman

Devin Mullins said:
One could generalize that solution:

class Symbol
def to_proc
lambda { |a,*b| a.send(self,*b) }
end

Wow, I really like it! Why didn't I think of that?

You've unified my version with the usual definition,
resulting in the be-all and end-all of Symbol#to_proc.

This *so* needs to be put in the standard library. :)
class Symbol
def *(ary)
ary.inject {|a,b| a.send(self, b)}
end

Way cool! I actually like this one, and I'm not kidding.
Redefine Array#* to double-dispatch on symbols and this will
actually be usable. Think about it=E2=80=94

[1,2,3] * "+" means [1,2,3].join("+"),

so it makes sense for

[1,2,3] * :+ to mean [1,2,3].inject(&:+).

More intuitively, we think of =E2=80=98[*foo] * "bar"=E2=80=99 as joining
the elements of =E2=80=98foo=E2=80=99 by "bar". Analogously, we can thin=
k
of =E2=80=98[*foo] * :bar=E2=80=99 as joining, or more correctly *recudin=
g*,
the elements of =E2=80=98foo=E2=80=99 using :bar.

This strikes me as highly intuitive:

[1,2,3] * "+" #=3D> "1+2+3"

[1,2,3] * :+ #=3D> 1 + 2 + 3

As does this (though perhaps slightly less so):

[1,2,3] * "foo" #=3D> "1foo2foo3"

[1,2,3] * :foo #=3D> 1.foo(2).foo(3)"
[crazy APL stuff snipped]

Now, :+*[1,2,3], :+[1,2,3], and +[1,2,3] are all valid.
(Not that I actually use this libary; just came up with it
to make a point about Ruby to somebody. :p)

That's cool; you really managed to take this to its extreme.
Of course, =E2=80=98:+[1,2,3]=E2=80=99 is too cryptic and =E2=80=98+[1,2,=
3]=E2=80=99 is
better written as =E2=80=98[1,2,3].sum=E2=80=99, but still. :)
(I would've overloaded /, but Ruby kept thinking I was
trying to construct a regular expression.)

Hmm, what would you have had that do?
And here's a vaguely neat extension of that idea:

class Symbol
def **(ary)
ary.inject { |a,b| a.send(self, *b) }
end
end

:gsub ** ["Hello!",
[/Hell/,"Good"]
[/o!/,"bye.]]

Talk about reducing duplication. :)

Wow... amazing. Of course, this

["Hello!", [/Hell/, "Good"], [/o!/, "bye."]] ** :gsub

is both longer and more cryptic than this,

"Hello!".gsub(/Hell/, "Good").gsub(/o!/, "bye.")

but still... the former has *no* duplication. :)

By the way, the above example suggests that it might be
useful to have String#gsub take multiple arguments:

class String
unless method_defined? :gsub1
alias :gsub1 :gsub
def gsub(*a)
(a.size =3D=3D 1 ? a.first : a.pairs).
inject(self) { |a, b| a.gsub1 *b }
end
end
end

module Enumerable
def pairs ; groups(2) end
def groups(n)
(a =3D entries).each_index { |i| a[i, n] =3D [a[i, n]] }
end
end

"Hello!".gsub(/Hell/ =3D> "Good", /o!/ =3D> "bye.") #=3D> "Goodbye."

Using a hash to visually pair each expression to its
replacement has the unfortunate side effect of effectively
randomizing the order of the substitutions, so you'll have
to use commas if order is significant:

"Hello!".gsub(/Hell/, "Good", /o!/, "bye.") #=3D> "Goodbye."


Anyway, thanks for sharing your cool inventions, Devin. :)

--=20
Daniel Brockman <[email protected]>

So really, we all have to ask ourselves:
Am I waiting for RMS to do this? --TTN.
 
J

Joe Van Dyk

Hello Mark,
=20

=20
MJR> Huh? Is GNU Common Lisp not actually an implementation of Common Li= sp?
MJR> GCL is not only open source, it's Free Software(TM) in the
MJR> Richard Stallman-approved sense.
=20
Here, in an image based system like LISP, free in the GPL sense is a very= very
bad idea. Only BSD image based systems are useable for commercial
applications. This is a fundamental difference to the gcc compiler
where the GPL makes sense.

What do you mean by "image based system"? And what does that have to
do with the GPL?
 
D

Devin Mullins

Daniel said:
Wow, I really like it! Why didn't I think of that?
=20
You weren't being challenged by someone showing you a code snippet=20
claiming that APL is a superior language. :) BTW, change *b to b, in my=20
code.
This *so* needs to be put in the standard library. :)
=20
Aww... that's the nicest thing anybody could ever say...
Way cool! I actually like this one, and I'm not kidding.
Redefine Array#* to double-dispatch on symbols and this will
actually be usable. Think about it=E2=80=94

[1,2,3] * "+" means [1,2,3].join("+"),

so it makes sense for

[1,2,3] * :+ to mean [1,2,3].inject(&:+).
=20
Actually, I like that a lot more than :+ * [1,2,3].
Hmm, what would you have had that do?
=20
Sorry, I just assumed that everybody except me knew APL, so I could just=20
talk about it as if I knew what I was talking about and get buy-in from=20
everybody else. In APL, the syntax for doing that is something akin to=20
"+ / 1 2 3". But you showed an excellent reason why "*" makes more sense=20
for Ruby.
Wow... amazing. Of course, this

["Hello!", [/Hell/, "Good"], [/o!/, "bye."]] ** :gsub

is both longer and more cryptic than this,

"Hello!".gsub(/Hell/, "Good").gsub(/o!/, "bye.")

but still... the former has *no* duplication. :)
=20
Well, if you're doing, like, seven gsubs, the former will win out, but=20
if you're chaining seven gsubs, you're probably doing something wrong. I=20
suppose you could use "** :gsub" to aid in some sort of configuration=20
file thing:

class Array
def **(sym)
inject {|a,b| a.send(sym,*b)} end end

gsubs =3D YAML::load [[/Hell/,"Good"],[/o!/,"bye."]].to_yaml #your config=
=20
file here
some_words_ive_got_lying_around =3D %w{cat dog tree Hello! french oreo!}
some_words_ive_got_lying_around.map! {|word| [word,*gsubs] ** :gsub }
#=3D> ["cat", "dog", "tree", "Goodbye.", "french", "orebye."]
By the way, the above example suggests that it might be
useful to have String#gsub take multiple arguments:

class String
unless method_defined? :gsub1
=20
Heh, never seen that "unless method_defined?" thing before. I like it, I=20
think. (I'm still not comfortable about the alias-and-call-original=20
trick, and this makes me a little more comfortable about it.)
"Hello!".gsub(/Hell/ =3D> "Good", /o!/ =3D> "bye.") #=3D> "Goodbye."
"Hello!".gsub(/Hell/, "Good", /o!/, "bye.") #=3D> "Goodbye."
=20
Hehe, neat. I actually haven't used gsub a lot, so I can't comment on=20
its usefulness, but I see a lot of other people gsubbing a lot, so I bet=20
it would be a pretty desired addition.
Anyway, thanks for sharing your cool inventions, Devin. :)
=20
You're welcome, and thanks for calling my inventions cool! Makes me feel=20
better for not contributing a library or toolkit or whatever to the Ruby=20
community. :)

Random aside: I learned something about #map just now:

irb(main):001:0> [1,2,3].map
=3D> [1, 2, 3]
irb(main):002:0> [1,2,3].map!
LocalJumpError: no block given
from (irb):2:in `map!'
from (irb):2

Odd... :p

Devin
 
D

Daniel Brockman

Devin Mullins said:
You weren't being challenged by someone showing you a code
snippet claiming that APL is a superior language. :)

Hmm, yeah, I guess that would've done it. :)
BTW, change *b to b, in my code.

Why? I can't think of any iterators that pass three or more
arguments to the block off-hand (at least I can't think of
any such cases where it makes sense to simply invoke a
single method upon each yield), but does it hurt to support
that hypothetical case anyway?
Way cool! I actually like this one, and I'm not kidding.
Redefine Array#* to double-dispatch on symbols and this
will actually be usable. Think about it=E2=80=94

[1,2,3] * "+" means [1,2,3].join("+"),

so it makes sense for

[1,2,3] * :+ to mean [1,2,3].inject(&:+).
=20
Actually, I like that a lot more than :+ * [1,2,3].

Yeah... I was thinking they should both work, but I guess
that's unnecessary, given that =E2=80=98"+" * [1,2,3]=E2=80=99 doesn't wo=
rk.

Random aside: In mathematics, a non-commutable + operator
is pretty damn near unthinkable, wheras in computer science
it's completely normal. I think that's kind of interesting.
Sorry, I just assumed that everybody except me knew APL,
so I could just talk about it as if I knew what I was
talking about and get buy-in from everybody else.

Ah. In light of this thread, I'm actually a little curious
about what other insights one might get from learning APL.
In APL, the syntax for doing that is something akin to
"+ / 1 2 3". But you showed an excellent reason why "*"
makes more sense for Ruby.

I see.
Wow... amazing. Of course, this

["Hello!", [/Hell/, "Good"], [/o!/, "bye."]] ** :gsub

is both longer and more cryptic than this,

"Hello!".gsub(/Hell/, "Good").gsub(/o!/, "bye.")

but still... the former has *no* duplication. :)

Well, if you're doing, like, seven gsubs, the former will
win out, but if you're chaining seven gsubs, you're
probably doing something wrong.

Good point. Although I don't think lots of gsubs are any
indication that you are doing something wrong. (I'd hate to
think *I* ever did something wrong.)
I suppose you could use "** :gsub" to aid in some sort of
configuration file thing:

class Array
def **(sym)
inject {|a,b| a.send(sym,*b)} end end

Nice to see someone else stuffing away those pesky =E2=80=98end=E2=80=99s
like that. I have my Emacs coloring them really dimly.
gsubs =3D YAML::load [[/Hell/,"Good"],[/o!/,"bye."]].to_yaml
#your config file here
some_words_ive_got_lying_around =3D %w{cat dog tree Hello! french oreo!= }
some_words_ive_got_lying_around.map! {|word| [word,*gsubs] ** :gsub }
#=3D> ["cat", "dog", "tree", "Goodbye.", "french", "orebye."]

Okay, but with my modified String#gsub, that's better
written like this:

gsubs.flatten!
some_words.map! { |word| word.gsub(*gsubs) }
Heh, never seen that "unless method_defined?" thing before.
I like it, I think. (I'm still not comfortable about the
alias-and-call-original trick, and this makes me a little
more comfortable about it.)

Yeah. Having been bitten a few times by the double-aliasing
bug that comes into play when a file that uses the =E2=80=9Calias
and redefine=E2=80=9D idiom is loaded twice, I always try to make
sure my (declarative) code is resistant to being loaded
multiple times.

--=20
Daniel Brockman <[email protected]>

So really, we all have to ask ourselves:
Am I waiting for RMS to do this? --TTN.
 
B

Bob Hutchison

What do you mean by "image based system"? And what does that have to
do with the GPL?

In an image based system, like lisp or smalltalk, all software is
loaded into memory and directly accessed. There is no concept of
linking. That explanation is a bit simplistic maybe, but it gives you
the idea. I think the difficulty is more to to with the LGPL than the
GPL, since the LGPL is defined in terms of linking while the GPL is
defined in terms of use. In an image based system you can't have
linking, so you can't be LGPL compliant, and so you must be GPL
compliant. There is actually something called the LLGPL, where the one
of the 'L's stands for 'lisp', that deals with this situation.

I *think* what Lothar is arguing is that using GCL is different than
using GCC for commercial applications because of the fact that GCL is
image based. This isn't necessarily true, it depends on how the runtime
is licensed and designed since GCL compiles to native via GCC and so
has a linking step hidden away in there -- but I'm too
apathetic/unconcerned to look up the details. As usual, if you don't
like the GPL don't use GPLed software. Simple. (Maybe a more
interesting question is whether you are allowed to run
non-GPL-compatibly licensed software with the GCL runtime at all?)

I don't understand why Lothar says only the BSD license is safe for
commercial use -- that is trivially not true since there are several
commercially licensed CL implementations that are definitely not BSD
licensed, nor is it necessarily true of open source implementations as
there are dozens/hundreds of OSI approved licenses -- so I imagine he
is just being a bit overly specific. His point is clear enough if you
don't take it literally.

I hope this makes some sense... I suppose I really shouldn't be posting
this late.

Cheers,
Bob
 
L

Lothar Scholz

Hello Bob,



BH> I *think* what Lothar is arguing is that using GCL is different than
BH> using GCC for commercial applications because of the fact that GCL is
BH> image based. This isn't necessarily true, it depends on how the runtime
BH> is licensed and designed since GCL compiles to native via GCC and so
BH> has a linking step hidden away in there -- but I'm too

The question is what is the runtime ?

If you for example want any user customizable parts of your
application, you normally allow the loading of lisp files and then the
problem comes up. There are no clear borders and normally you end up
very soon with using the whole lisp system.

BH> I don't understand why Lothar says only the BSD license is safe for
BH> commercial use -- that is trivially not true since there are several
BH> commercially licensed CL implementations that are definitely not BSD
BH> licensed, nor is it necessarily true of open source implementations as

Yes i meant for open source lisp implementations, the commercial ones
are normally okay by definition.

I only know a few of the licenses and so to cut a long story short _I_
would only accept a BSD lisp systems or one that is completely public
domain. And there is none available.
 
G

gabriele renzi

benny ha scritto:
William James wrote:



BTW: did anyone try to write a Ruby interpreter in Lisp?
Might be challenging...

no, but there were some scheme implementations in ruby ;)
 
D

Devin Mullins

Daniel said:
[[1,2,3],[4,5,6],[7,8,9]] * :+ should =3D> [1,2,3,4,5,6,7,8,9]
Random aside: In mathematics, a non-commutable + operator
is pretty damn near unthinkable, wheras in computer science
it's completely normal. I think that's kind of interesting.
=20
Well, in Ruby it's completely normal. I can't think of any other=20
language that does that by default...

One thing that's okay in programming but not in math is that 5/2 =3D=3D 2=
:)
Ah. In light of this thread, I'm actually a little curious
about what other insights one might get from learning APL.
=20
Not much, I don't think. It's a language whose primary use is processing=20
lists and matrices of numbers, and whose sole focus is absolute=20
terseness at the expense of readability in any sense of the word. But=20
hey, maybe I'm being pessimistic. I shouldn't prevent you from a=20
potential learning experience:

http://en.wikipedia.org/wiki/APL_programming_language
http://www.thocp.net/software/languages/apl.htm
http://www.thefreecountry.com/compilers/apl.shtml
http://www.engin.umd.umich.edu/CIS/course.des/cis400/apl/apl.html
http://www.users.cloud9.net/~bradmcc/APL.html
http://www.acm.org/sigs/sigapl/

My favorite quote from the wikipedia page:
"APL is a mistake, carried through to perfection. It is the language of=20
the future for the programming techniques of the past: it creates a new=20
generation of coding bums."
--Edsger Dijkstra
Nice to see someone else stuffing away those pesky =E2=80=98end=E2=80=99= s
like that. I have my Emacs coloring them really dimly.
=20
I did that just for you. :) Also because it was an email, and I was=20
going for fewness of lines.
Okay, but with my modified String#gsub, that's better
written like this: <snip>
=20
True.

Yeah. Having been bitten a few times by the double-aliasing
bug that comes into play when a file that uses the =E2=80=9Calias
and redefine=E2=80=9D idiom is loaded twice, ...
=20
I'm eager to see when Behaviors is ready for prime-time. Ruby needs more=20
support for this sort of thing.

Also, what do you think of an 'original' keyword for when you redefine a=20
method (assuming that Behaviors solves your loaded-twice problem)?
class String
def gsub(*a)
if a.size =3D=3D 1 then original
else original(a[0]).gsub(a[1..-1])
end
end
end

One could use the original keyword like one uses the super keyword.

Devin
 
J

Jaypee

Devin said:
Not much, I don't think. It's a language whose primary use is processing
lists and matrices of numbers, and whose sole focus is absolute
terseness at the expense of readability in any sense of the word. But
hey, maybe I'm being pessimistic. I shouldn't prevent you from a
potential learning experience:
....
Choosing a comment of Dijkstra on APL is as valid having the creator of
COBOL comment on Ruby. It's just irrelevant.

The terseness of of APL is only a reflection seen from outside. In fact
there are many idioms, that you quickly recognize and don't need to
spell out. It does give you some different ways to solve a problem,
because of the richness of operators. For example as sorting is one of
those operators, sorting is easily used as part of an instruction,
amongst other operations.
I have spent the first 4 years of my professional life coding in APL.
The scars are benigne, not as bad as the same amount of Visual Basic.

Example: Imagine you had to emulate an old time text processor to
justify lines to a given width, by adding spaces where there are already.
The width is w
(line iota ' ') yields a vector of indices of white spaces in the line
(it's the dyadic iota: A iota B)

(rho line) is the length of the line (monadic rho)
iota n is the vector 1..n (monadic iota)
Let's make a vector of all indices of the line : iota rho line

Let's reuse as many indices of white spaces as needed:
(w - rho line) rho line itota ' '
The dyadic rho is used here, (size rho pattern), it reuses the
pattern as many time as needed to fill the result to the specified size.

Let's sort all the indices:
sort (iota rho line), (w - rho line) rho line itota ' '

Then use the resulting vector with the original line so:
line[sort (iota rho line), (w - rho line) rho line itota ' ']
is the answer of the problem ...

Sorry for the length and OT twist of that reply ;-)
J-P
 
W

William James

Jaypee said:
Example: Imagine you had to emulate an old time text processor to
justify lines to a given width, by adding spaces where there are already.
The width is w

w=60

DATA.each_line {|line|

t=line.split;n=t.size-1;q,r=(w-t.join.size).divmod(n)
print t.zip([" "*q]*n,[" "]*r);puts""

}

print "="*w

__END__
The quick red fox jumps over the lazy brown hogs.
The quick red fox jumps over lazy brown hogs.
The quick red fox jumps over lazy hogs.
The quick fox jumps over lazy hogs.
The quick fox.


-----
The output is

The quick red fox jumps over the lazy brown hogs.
The quick red fox jumps over lazy brown hogs.
The quick red fox jumps over lazy hogs.
The quick fox jumps over lazy hogs.
The quick fox.
============================================================
 
D

Daniel Brockman

Devin Mullins said:

[[1,2,3],[4,5,6],[7,8,9]] * :+ should =3D> [1,2,3,4,5,6,7,8,9]

class Symbol
def to_proc
lambda { |a, *b| a.send(self, *b) } end end

[[1,2,3],[4,5,6],[7,8,9]].inject(&:+) #=3D> [1..9].to_a

class Symbol
def to_proc
lambda { |a, b| a.send(self, b) } end end

[[1,2,3],[4,5,6],[7,8,9]].inject(&:+) #=3D> [1..9].to_a

It only matters when the iterator (=E2=80=98inject=E2=80=99, in this case=
)
passes more than two arguments to the block. ...right?
Well, in Ruby it's completely normal. I can't think of any
other language that does that by default...

There are lots and lots and lots of examples. To choose
just one, Java overloads + non-commutatively for strings:

("foo" + "bar").equal("bar" + "foo") // =3D> false
One thing that's okay in programming but not in math is
that 5/2 =3D=3D 2. :)

It's not okay with me. :)

I'd much rather have the =E2=80=98/=E2=80=99 operator not perform any
truncation, and use =E2=80=985.div 2=E2=80=99 to get integer division.
Not much, I don't think. It's a language whose primary use
is processing lists and matrices of numbers, and whose
sole focus is absolute terseness at the expense of
readability in any sense of the word. But hey, maybe I'm
being pessimistic. I shouldn't prevent you from a
potential learning experience:

http://en.wikipedia.org/wiki/APL_programming_language
http://www.thocp.net/software/languages/apl.htm
http://www.thefreecountry.com/compilers/apl.shtml
http://www.engin.umd.umich.edu/CIS/course.des/cis400/apl/apl.html
http://www.users.cloud9.net/~bradmcc/APL.html
http://www.acm.org/sigs/sigapl/

Hmm... maybe some day. :)
..

I'm eager to see when Behaviors is ready for prime-time.
Ruby needs more support for this sort of thing.

I haven't heard of Behaviors before, but it seems
interesting. I'm going to read up on them, thanks.
Also, what do you think of an 'original' keyword for when
you redefine a method (assuming that Behaviors solves your
loaded-twice problem)?

class String
def gsub(*a)
if a.size =3D=3D 1 then original
else original(a[0]).gsub(a[1..-1])
end
end
end

One could use the original keyword like one uses the
super keyword.

That's a great idea. I really like it. The idiom is so
common and ugly that it definitely could use some sugar.

The semantics are straightforward, too: Only redefine a
method when its current body differs from the new one, and
give the redefined method a reference to the old one,
accessible through =E2=80=98original=E2=80=99. (For efficiency, the
original method should probably only be saved if the new
method uses the =E2=80=98original=E2=80=99 keyword.)

--=20
Daniel Brockman <[email protected]>

So really, we all have to ask ourselves:
Am I waiting for RMS to do this? --TTN.
 
Z

zak.wilson

SBCL and CMUCL are mostly public domain, those parts that are not are
BSD licenced. Clisp is GPL, with an LGPL-like exception for saved
images.
 
D

Dave Fayram

=20
Thanks Dave for the interesting post. Would these problems be solved if
Common Lisp went open source?

It already is, but the quality of open source implementations varies
wildly. Not quality as in "are they good." The amount of ego and
expertise that tends to reside in the lisp community assures that the
projects meet their goals. Quality as in, "What problems does this
solve?" Some CMUCL, for example, is an incredibly good compiler when
you need very fast lisp. However, it's harder to use than SBCL, which
has my vote for easiest lisp distro to use in general (and it's what
Peter Seibel distributes as "Lisp In A Box"). On a mac, OpenMCL has a
ton of great features.

The commerical offerings solve enterprise solution problems. Ever seen
a CORBA->Lisp binding? They actually make CORBA usable! But you pay a
lot and LispWorks and Allegro still compile slower mathmatical code.

=20
that suggests there are some promising dialects of Lisp that are open
source, but currently aren't as rich as, say Common Lisp.

They are all common lisp.

And the first thing that drew me to Ruby was its peculiar and very
right-seeming "Ruby Way." Matz has impeccable taste in coding, and
Ruby reflects that taste.
--=20
--=20
Dave Fayram (II)
(e-mail address removed)
 
G

Gavin Kistner

I have a stricter definition. Let's call it "patrician
hooberglobbers." Patrician hooberglobbers, to me, have the
additional quality that the syntax for manipulating a hooberglobber
is the same whether it is referred to statically or by evaluation/
substitution (as through a variable, or return value of a function
call). In this sense, Ruby has patrician classes:


What do you call patrician hooberglobbers that can be invoked with
binding to instances of arbitrary classes, such that 'self' and
instance variables refer to the supplied instance?

That's what I think of when I think of first-class functions, given
my JS background: a single function that may be anonymous, assigned
to a variable, and invoked with a specific binding. (And if it's also
a closure, so much the better.)

There are few things that make me cry about Ruby, but of those that
do, few make me cry more than the current situation with Methods/
UnboundMethods/Procs/blocks/lambdas. It's workable, but it really
isn't elegant. (IMO)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,176
Messages
2,570,950
Members
47,501
Latest member
log5Sshell/alfa5

Latest Threads

Top