http://groups.google.co.nz/groups?q=%22lisp+on+lines%22&hl=en
I've always admired Lisp from afar. I wonder what it could do for a web
framework?
Luke
http://www.paulgraham.com/articles.html
specifically:
http://www.paulgraham.com/avg.html
http://lib.store.yahoo.com/lib/paulgraham/bbnexcerpts.txt
cheers.
-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| My religion is very simple. My religion is kindness.
| --Tenzin Gyatso
===============================================================================
Now, how much less readable than Ruby is Lisp? ;)
def accgen (n)
lambda {|i| n += i }
end
foo = accgen(5)
foo.call(5) # returns 10
foo.call(5) # returns 15
accgen function borrowed from http://www.paulgraham.com/accgen.html
Lisp macros are the main area in which Lisp has more power than Ruby,
and are closely related to Lisp's syntax (or non-syntax). Macros allow
for new language constructs much like OOP allows for new types, for
example, if Common Lisp didn't have unless, you could add it like this:
(defmacro unless (test &rest forms)
`(if ,test 'nil
,@forms))
a = "test".length
a() => 4
Instead, you have to do this:
a = lambda {"test".length}
a.call()
To me it seems that the closure is first-class but the actual
function/method is not. You cannot pass non-anonymous functions as
arguments, you cannot assign them to variables, you cannot compare them
for equality, as you can in Lisp (and many other functional languages). No?
Lisp has many more features, in fact the entire language could be
viewed as a feature expression system.
That doesn't mean that Ruby is at a huge disadvantage. Ruby has most
of the important parts of lisp. It does lack macos, but very few
languages have the uniform syntax necessary to make macros as easy and
natural as they are in Lisp. Ruby has higher order functions (albeit
with a keyword massage sometimes), lambdas, closures, garbage
collection, and OO.
Some people would argue that Lisp's Object system, CLOS, is more
powerful than Ruby's because it supports multiple dispatch, and it may
be true that some things express themselves more gracefully in CLOS,
but Ruby's method has a lot of strengths too. Ruby also has a very
strong advantage in the meta-object-programming department. While CL
does have a standard for this, called "the MOP," implementation is
spotty and often subtle details cause incompatibility across Lisp
interpreters, and the MOP itself is often poorly understood even on
comp.lang.lisp.
Actually, that's kind of the story of modern Lisp. "Subtle details
cause incompatibility across Lisp interpreters." It's sad to see such
a fine language ritualistically beat and abuse itself, but its
community insists on a perpetual fork. This fork doesn't just extend
between open source and commerical lisps, which might be
understandable, but also among several open source inheritors, none of
which really could constitute a universal distribution.
--
--
Dave Fayram (II)
dfa...@lensmen.net
dfa...@gmail.com
Kirk Haines
It's the same in Lisp. In your first example, "test".length gets
evaluated, and that value is assigned to a:
Ruby:
a = "test".length
a.class #Fixnum
a #4
a = lambda {"test".length}
a.class #Proc
a.call() #4
Lisp:
(setf a (length "test"))
(a) ;error
(type-of a) ;(INTEGER 4 4)
a ;4
(setf a (lambda () (length "test")))
(type-of a) ;EVAL:INTERPRETED-FUNCTION
(funcall a) ;4
I noticed a post on a site
http://lemonodor.com/archives/000671.html
that suggests there are some promising dialects of Lisp that are open
source, but currently aren't as rich as, say Common Lisp.
When choosing a new and flexible language, one of the deciding factors for
me choosing Ruby was the fact it was open source.
"Dave Fayram" <dfa...@gmail.com> wrote in message
news:6fb0069505072...@mail.gmail.com...
> 1. class Foo; def thing; nil end end
> 2. f = Foo.new; f.thing #=> nil
> 3. m = f.method :thing; m.call #=> nil
> 4. class Foo; def thing; 5 end end
> 5. f.thing #=> 5
> 6. m.call #=> nil
>
> Heh, it seems that Ruby really does have first class
> functions. ;) (Why is this happening, btw? Does this have
> something to do with continuations?)
No... nothing to do with continuations. It's quite simple:
On line 3, a reference to the method body that was defined
on line 1 is stored in the method object bound to ‘m’; the
fact that the Foo#thing method is subsequently replaced on
line 4 does not affect the method object, which still has
its reference to the old method body.
--
Daniel Brockman <dan...@brockman.se>
So really, we all have to ask ourselves:
Am I waiting for RMS to do this? --TTN.
>I noticed a post on a site
>http://lemonodor.com/archives/000671.html
>that suggests there are some promising dialects of Lisp that are open
>source, but currently aren't as rich as, say Common Lisp.
Huh? Is GNU Common Lisp not actually an implementation of Common Lisp?
GCL is not only open source, it's Free Software(TM) in the
Richard Stallman-approved sense.
>It's the same in Lisp. In your first example, "test".length gets
>evaluated, and that value is assigned to a:
>
>Ruby:
>a = "test".length
>a.class #Fixnum
>a #4
>
>a = lambda {"test".length}
>a.class #Proc
>a.call() #4
>
>Lisp:
>(setf a (length "test"))
>(a) ;error
>(type-of a) ;(INTEGER 4 4)
>a ;4
>
>(setf a (lambda () (length "test")))
>(type-of a) ;EVAL:INTERPRETED-FUNCTION
>(funcall a) ;4
>
>
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...?)
Setting a variable to the function itself seems pretty different than
wrapping a call to the function in a lambda, 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}
Are they really, for all intents and purposes, the same?
>This looks like first class functions to me:
>
>def accgen (n)
> lambda {|i| n += i }
>end
>
>foo = accgen(5)
>foo.call(5) # returns 10
>foo.call(5) # returns 15
>
>accgen function borrowed from http://www.paulgraham.com/accgen.html
>
>
Perhaps we need a new term. According to Google, "First class
hooberglobbers" seems to mean hooberglobbers can be assigned to
variables, parameters, and return values, and then, though the assignee,
can be manipulated in all the ways that hooberglobbers can be
manipulated. Under this definition, yes, Ruby has first class functions.
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:
a = String.new
b = String
c = b.new
However, while Lisp, Python (from the examples I've seen), and Unlambda
have patrician functions, Ruby does not. I can think of two simple
enough reasons for this:
1. Because Ruby has a "poetry mode," there is no way to refer to a
function by reference -- simply referring to it invokes it. The closest
you can get is to refer to the Symbol representing its name, or to
create a Method object, which really just wraps an invocation of the
method inside a class.
This could be "fixed" by creating a syntax to "thunk" function names,
and to later apply them. So that, given some function 'foo', you could say:
foo "hello"; ^foo("hello"); a = ^foo; a("hello");
But then ^ is just syntactic sugar for self.method, and () sugar for
Method#call. This doesn't escape the fact that a can't be treated the
same as foo.
2. Actually, when I was writing reason #2, I wrote some example code to
show that a method is just a way for an object to receive messages in
Ruby, but got a surprising result, so there is no #2. Here's the code,
though:
class Foo; def thing; nil end end
f = Foo.new; f.thing #=> nil
m = f.method :thing; m.call #=> nil
class Foo; def thing; 5 end end
f.thing #=> 5
m.call #=> nil
Heh, it seems that Ruby really does have first class functions. ;) (Why
is this happening, btw? Does this have something to do with continuations?)
Now, does a language need patrician functions? I dunno, I seem to be
enjoying Ruby, and my opinion is pretty much all anybody needs to
concern themselves with.
Devin
harp:~ > irb
irb(main):001:0> a = lambda{ p 42 }
=> #<Proc:0xb755d848@(irb):1>
irb(main):002:0> a ()
42
=> nil
irb(main):003:0> a()
42
=> nil
irb(main):004:0> b = a
=> #<Proc:0xb755d848@(irb):1>
irb(main):005:0> b()
42
=> nil
harp:~ > ruby -v
ruby 1.9.0 (2005-05-16) [i686-linux]
harp:~ > irb -v
irb 0.9.5(05/04/13)
getting pretty close...
> class Foo; def thing; nil end end
> f = Foo.new; f.thing #=> nil
> m = f.method :thing; m.call #=> nil
> class Foo; def thing; 5 end end
> f.thing #=> 5
> m.call #=> nil
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. Lisp does the same thing:
(defun foo () 'nil)
(foo) ;nil
(setf bar #'foo)
(funcall bar) ;nil
(defun foo () 5)
(foo) ;5
(funcall bar) ;nil
>
> Thanks Dave for the interesting post. Would these problems be
> solved if
> Common Lisp went open source?
Er, there are quite a few open source CL implementations
http://www.cliki.net/Common%20Lisp%20implementation
-Brian
> 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...?)
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 = :length
"foo".send(a)
This is because in Ruby, polymorphism is implemented by
having different ‘length’ methods for different objects,
whereas in Lisp, there is just one function ‘length’ that
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.)
> Setting a variable to the function itself seems pretty
> different than wrapping a call to the function in a lambda,
Again, there is not just a single ‘length’ method in Ruby,
so you can't “set a variable to the function itself.” The
closest analogy to the “function itself” is the method name.
> 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}
You could actually define the equivalent of Lisp's ‘+’
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 ‘+’ operator,
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:
Function = 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 ‘foo.each &:bar’ equal ‘foo.each { |x| x.bar }’.
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, ‘[1,2,3].inject &-:+’ is starting to look rather
much like line noise.)
> Devin Mullins wrote:
>
>> class Foo; def thing; nil end end
>> f = Foo.new; f.thing #=> nil
>> m = f.method :thing; m.call #=> nil
>> class Foo; def thing; 5 end end
>> f.thing #=> 5
>> m.call #=> nil
>
> 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 “just pointing a
variable at it,” except it would be slower.
My point is that ‘def a.b ; 1 end ; def a.b ; 2 end’ is more
like ‘a.b = lambda {1} ; a.b = lambda {2}’ and less like
‘a.b = lambda {1} ; a.b.body = "2"’. (Of course, this 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. :-)
Is 1.9 going to be 2.0 when it's released?
BM> On Jul 25, 2005, at 8:55 PM, luke wrote:
>>
>> Thanks Dave for the interesting post. Would these problems be
>> solved if
>> Common Lisp went open source?
BM> Er, there are quite a few open source CL implementations
BM> http://www.cliki.net/Common%20Lisp%20implementation
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.
--
Best regards, emailto: scholz at scriptolutions dot com
Lothar Scholz http://www.ruby-ide.com
CTO Scriptolutions Ruby, PHP, Python IDE 's
OpenMCL has native threads doesn't it? Now if you want unicode /and/
threads you're out of luck ;-)
Adrian
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
actually use this libary; just came up with it to make a point about
Ruby to somebody. :P)
(I would've overloaded /, but Ruby kept thinking I was trying to
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 Brockman wrote:
>to have ‘foo.each &:bar’ equal ‘foo.each { |x| xbar }’.
>Hi Joe,
>
>
>
>>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...?)
>>
>>
>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.
>
>
Interesting--that's the first I've heard of it. Do you have a link to
some documentation about functions? I don't see anything in the PickAxe
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 = :length
> "foo".send(a)
>
>This is because in Ruby, polymorphism is implemented by
>having different ‘length’ methods for different objects,
>whereas in Lisp, there is just one function ‘length’ that
>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.)
>
>
I understand. I was not concerned about polymorphic methods vs.
functions, but rather the ability to directly capture a reference to a
[method|function].
Let me try illustrating in Boo instead:
class Foo:
def bar():
print("hello")
a = Foo() # calling Foo constructor
b = a.bar
b() # same as calling a.bar()
This is different than what you are trying to accomplish in your post,
and admittedly, even pretty different from what my Lisp example was in
terms of functionality.
>>Setting a variable to the function itself seems pretty
>>different than wrapping a call to the function in a lambda,
>>
>>
>Again, there is not just a single ‘length’ method in Ruby,
>so you can't “set a variable to the function itself.” The
>closest analogy to the “function itself” is the method name.
>
>
I was looking for something like the above example in Boo. Although
using lambda/proc, send(:symbol), or method(:symbol), they all seem to
accomplish the task (with useful differences in behavior between the
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}
>>
>>
>You could actually define the equivalent of Lisp's ‘+’
>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(:+)
>
>
That is actually pretty close. I've never seen the &-syntax (that is,
not from the caller)... I can see there are a lot of possibilities with
that.
Wow, that is really cool. Although one problem... my irb is complaining
about Binding.of_caller not being defined. Do I need to require
something first?
>By the way, a more popular definition of Symbol#to_proc is
>to have ‘foo.each &:bar’ equal ‘foo.each { |x| xbar }’.
>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, ‘[1,2,3].inject &-:+’ is starting to look rather
>much like line noise.)
>
>
I didn't mean to emphasize #'+, it is just the canonical example in the
Lisp tutorials I've read... :)
Thanks for the very interesting response, I learned a lot.
> 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—
[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 ‘[*foo] * "bar"’ as joining
the elements of ‘foo’ by "bar". Analogously, we can think
of ‘[*foo] * :bar’ as joining, or more correctly *recuding*,
the elements of ‘foo’ using :bar.
This strikes me as highly intuitive:
[1,2,3] * "+" #=> "1+2+3"
[1,2,3] * :+ #=> 1 + 2 + 3
As does this (though perhaps slightly less so):
[1,2,3] * "foo" #=> "1foo2foo3"
[1,2,3] * :foo #=> 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, ‘:+[1,2,3]’ is too cryptic and ‘+[1,2,3]’ is
better written as ‘[1,2,3].sum’, 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 == 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 = entries).each_index { |i| a[i, n] = [a[i, n]] }
end
end
"Hello!".gsub(/Hell/ => "Good", /o!/ => "bye.") #=> "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.") #=> "Goodbye."
Anyway, thanks for sharing your cool inventions, Devin. :-)
What do you mean by "image based system"? And what does that have to
do with the GPL?
>Wow, I really like it! Why didn't I think of that?
>
>
You weren't being challenged by someone showing you a code snippet
claiming that APL is a superior language. :) BTW, change *b to b, in my
code.
>This *so* needs to be put in the standard library. :-)
>
>
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—
>
> [1,2,3] * "+" means [1,2,3].join("+"),
>
>so it makes sense for
>
> [1,2,3] * :+ to mean [1,2,3].inject(&:+).
>
>
Actually, I like that a lot more than :+ * [1,2,3].
>>(I would've overloaded /, but Ruby kept thinking I was
>>trying to construct a regular expression.)
>>
>>
>Hmm, what would you have had that do?
>
>
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. 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.
>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. 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
gsubs = YAML::load [[/Hell/,"Good"],[/o!/,"bye."]].to_yaml #your config
file here
some_words_ive_got_lying_around = %w{cat dog tree Hello! french oreo!}
some_words_ive_got_lying_around.map! {|word| [word,*gsubs] ** :gsub }
#=> ["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
>
>
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.)
> "Hello!".gsub(/Hell/ => "Good", /o!/ => "bye.") #=> "Goodbye."
> "Hello!".gsub(/Hell/, "Good", /o!/, "bye.") #=> "Goodbye."
>
>
Hehe, neat. I actually haven't used gsub a lot, so I can't comment on
its usefulness, but I see a lot of other people gsubbing a lot, so I bet
it would be a pretty desired addition.
>Anyway, thanks for sharing your cool inventions, Devin. :-)
>
>
You're welcome, and thanks for calling my inventions cool! Makes me feel
better for not contributing a library or toolkit or whatever to the Ruby
community. :)
Random aside: I learned something about #map just now:
irb(main):001:0> [1,2,3].map
=> [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
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
----
Bob Hutchison -- blogs at <http://www.recursive.ca/hutch/>
Recursive Design Inc. -- <http://www.recursive.ca/>
>> Wow, I really like it! Why didn't I think of that?
>
> 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—
>>
>> [1,2,3] * "+" means [1,2,3].join("+"),
>>
>> so it makes sense for
>>
>> [1,2,3] * :+ to mean [1,2,3].inject(&:+).
>>
>>
> 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 ‘"+" * [1,2,3]’ doesn't work.
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.
>>> (I would've overloaded /, but Ruby kept thinking I was
>>> trying to construct a regular expression.)
>>
>> Hmm, what would you have had that do?
>
> 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 ‘end’s
like that. I have my Emacs coloring them really dimly.
> gsubs = YAML::load [[/Hell/,"Good"],[/o!/,"bye."]].to_yaml
> #your config file here
> some_words_ive_got_lying_around = %w{cat dog tree Hello! french oreo!}
> some_words_ive_got_lying_around.map! {|word| [word,*gsubs] ** :gsub }
> #=> ["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) }
>> 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
>
> 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 “alias
and redefine” idiom is loaded twice, I always try to make
sure my (declarative) code is resistant to being loaded
multiple times.
> How much less powerful than Lisp is Ruby?
BTW: did anyone try to write a Ruby interpreter in Lisp?
Might be challenging...
benny
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.
no, but there were some scheme implementations in ruby ;)
>>BTW, change *b to b, in my code.
>>
>>
>Why?
>
[[1,2,3],[4,5,6],[7,8,9]] * :+ should => [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.
>
>
Well, in Ruby it's completely normal. I can't think of any other
language that does that by default...
One thing that's okay in programming but not in math is that 5/2 == 2 :)
>Ah. In light of this thread, I'm actually a little curious
>about what other insights one might get from learning APL.
>
>
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/
My favorite quote from the wikipedia page:
"APL is a mistake, carried through to perfection. It is the language of
the future for the programming techniques of the past: it creates a new
generation of coding bums."
--Edsger Dijkstra
>Nice to see someone else stuffing away those pesky ‘end’s
>like that. I have my Emacs coloring them really dimly.
>
>
I did that just for you. :) Also because it was an email, and I was
going for fewness of lines.
>Okay, but with my modified String#gsub, that's better
>written like this: <snip>
>
>
True.
>Yeah. Having been bitten a few times by the double-aliasing
>bug that comes into play when a file that uses the “alias
>and redefine” idiom is loaded twice, ...
>
>
I'm eager to see when Behaviors is ready for prime-time. Ruby needs more
support for this sort of thing.
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 == 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
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
> 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.
============================================================
>>> BTW, change *b to b, in my code.
>>
>> Why?
>
> [[1,2,3],[4,5,6],[7,8,9]] * :+ should => [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(&:+) #=> [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(&:+) #=> [1..9].to_a
It only matters when the iterator (‘inject’, in this case)
passes more than two arguments to the block. ...right?
>> 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.
>
> 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") // => false
> One thing that's okay in programming but not in math is
> that 5/2 == 2. :)
It's not okay with me. :-)
I'd much rather have the ‘/’ operator not perform any
truncation, and use ‘5.div 2’ to get integer division.
>> Ah. In light of this thread, I'm actually a little
>> curious about what other insights one might get from
>> learning APL.
>
> 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. :-)
>> Yeah. Having been bitten a few times by the
>> double-aliasing bug that comes into play when a file that
>> uses the “alias and redefine” idiom is loaded twice, ..
>
> 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 == 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 ‘original’. (For efficiency, the
original method should probably only be saved if the new
method uses the ‘original’ keyword.)
Sorry to be so negative about the language. I really haven't
looked into it much so I shouldn't be so harsh to judge. Didn't
fully understand the example, but I appreciated it, anyhow.
Point taken, however.
Though I may not (yet) dig using APL as a language to write
anything longer than one line, it is really good at many one-liners,
and certain things that require a lot of typing to say something
stupid could easily be abstracted into a more comprehensive
Array library, say. That's where array * :+ came from, and there
are probably more like it.
>It only matters when the iterator (ãàÏÊnjectãà in this case)
>passes more than two arguments to the block. ...right?
Yeah, right. I'm on crack, nevermind.
>There are lots and lots and lots of examples. To choose
>just one, Java overloads + non-commutatively for strings:
Yeah, okay, I'm still on crack.
>It's not okay with me. :-)
>I'd much rather have the ãàãàoperator not perform any
>truncation, and use ãà.div 2ãàto get integer division.
Ditto. Doesn't Pascal act like this?
>> 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.
Great! Now go write an RCR for me. :Q
Devin
I have no idea where my webmail gets all those funky "ãàãà"
characters from.
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.
> 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.
--
--
Dave Fayram (II)
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)
> 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)
As a relative newcomer to Ruby, I would appreciate hearing you elaborate
on this point.
Thanks!
John
Search the ruby-talk archives and you'll find a good bit about it.
Basically we have four/five differnt entities that are all almost but
not quite the same things. Hopefully Rite/Ruby2 will simplify this
some.
T.