Lisp on Lines

A

Ara.T.Howard

Read on the comp.lang.lisp group that someone is developing 'Lisp on Lines'

http://groups.google.co.nz/groups?q="lisp+on+lines"&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
===============================================================================
 
L

luke

Yes, I've read Paul Graham's book "Hackers and Painters", which is what
inspired me to think programming could be for me in first place.
 
J

Joe Cheng

I've only had passing experience with Lisp but the macro facility seems
incredibly powerful and useful, especially for defining mini-languages.
Also functions are real first-class constructs in Lisp and not in Ruby,
afaict. I'm sure there's other stuff but those are the features I envy
from Lisp.

Now, how much less readable than Ruby is Lisp? ;)
 
Z

zak.wilson

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

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))
 
J

Joe Cheng

Perhaps I'm misunderstanding here, please bear with me. Ruby doesn't
have the ability to do this:

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?
 
D

Dave Fayram

How much less powerful than Lisp is Ruby?
=20


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.

--=20
--=20
Dave Fayram (II)
(e-mail address removed)
(e-mail address removed)
 
K

Kirk Haines

Perhaps I'm misunderstanding here, please bear with me. Ruby doesn't
have the ability to do this:

a = "test".length
a() => 4

Instead, you have to do this:

a = lambda {"test".length}
a.call()
a = "test".method:)length)
a.call
=> 4


Kirk Haines
 
Z

zak.wilson

Joe said:
Perhaps I'm misunderstanding here, please bear with me. Ruby doesn't
have the ability to do this:

a = "test".length
a() => 4
Instead, you have to do this:

a = lambda {"test".length}
a.call()

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
 
L

luke

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

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.




How much less powerful than Lisp is Ruby?


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.
 
Z

zak.wilson

Common Lisp is an open standard. There are implementations of it that
are proprietary, and implementations that are open source. Clisp, CMUCL
and SBCL are popular open source implementations; Allegro CL and
LispWorks are popular proprietary implementations, and a number of
others exist. Problems arise where the standard isn't quite specific
enough, but these are usually fairly trivial; Common Lisp offers reader
macros to conditionally read code depending on which implementation is
in use.
 
D

Devin Mullins

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
 
D

Daniel Brockman

Devin Mullins said:
1. class Foo; def thing; nil end end
2. f =3D Foo.new; f.thing #=3D> nil
3. m =3D f.method :thing; m.call #=3D> nil
4. class Foo; def thing; 5 end end
5. f.thing #=3D> 5
6. m.call #=3D> 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 =E2=80=98m=E2=80=99; th=
e
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.

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

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

Joe Cheng

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?
 
A

Ara.T.Howard

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.

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...

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
===============================================================================
 
J

Joe Van Dyk

On Tue, 26 Jul 2005, Devin Mullins wrote:
=20
Perhaps we need a new term. According to Google, "First class hooberglo= bbers"
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 s= yntax
for manipulating a hooberglobber is the same whether it is referred to
statically or by evaluation/substitution (as through a variable, or ret= urn
value of a function call). In this sense, Ruby has patrician classes:

a =3D String.new
b =3D String
c =3D 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 re= asons
for this:

1. Because Ruby has a "poetry mode," there is no way to refer to a func= tion
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 obj= ect,
which really just wraps an invocation of the method inside a class.
=20
harp:~ > irb
irb(main):001:0> a =3D lambda{ p 42 }
=3D> #<Proc:0xb755d848@(irb):1>
=20
irb(main):002:0> a ()
42
=3D> nil
=20
irb(main):003:0> a()
42
=3D> nil
=20
irb(main):004:0> b =3D a
=3D> #<Proc:0xb755d848@(irb):1>
irb(main):005:0> b()
42
=3D> nil
=20
harp:~ > ruby -v
ruby 1.9.0 (2005-05-16) [i686-linux]
=20
harp:~ > irb -v
irb 0.9.5(05/04/13)

Is 1.9 going to be 2.0 when it's released?
 
Z

zak.wilson

Devin said:
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
 
D

Daniel Brockman

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.

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 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 =E2=80=98length=E2=80=99 method in Ruby=
,
so you can't =E2=80=9Cset a variable to the function itself.=E2=80=9D Th=
e
closest analogy to the =E2=80=9Cfunction itself=E2=80=9D is the method na=
me.
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 =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 operato=
r,
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 rather
much like line noise.)

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

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

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
473,773
Messages
2,569,594
Members
45,118
Latest member
LatishaWhy
Top