Home > Archive > Scheme > January 2008 > Announcing a new release of Lisp1
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Announcing a new release of Lisp1
|
|
| Blake McBride 2008-01-27, 4:40 am |
|
Announcing a new release of Lisp1.
Located at: http://blake.mcbride.name
From the documentations:
Lisp1
A portable (ANSI) Common Lisp program that makes Common Lisp operate
as a LISP1 Lisp.
Written and placed in the public domain by:
Blake McBride
blake@mcbride.name
========================================
========================================
The problem:
Common Lisp (CL) is a LISPn language. This means that symbols can
hold normal values, functions, property lists, etc. at the same time.
Different functions are used to manipulate these different qualities
associated to a given symbol. The problem with this is that code
becomes more complex and API's become large just to support these
concurrent aspects.
In real life using the same symbol to represent a function _and_ a
value (in the form of a variable) at the same time would be really bad
practice. It would make the code very difficult to understand. For
this reason, programmers rarely do this. So, in effect, CL has a lot
of extra facilities and complexity just to support a feature that
programmers generally avoid.
LISP1 dialects associate a symbol with a single value. This single
value can be any value e.g. a number, a list, or a function. Since
functions are treated just like any other value, they can be passed or
assigned as is any other value. In effect, functions become first
class citizens.
(Historical note: CL is a LISPn language mainly for historical reasons
- to be compatible with Lisp's that came before it, not necessarily
because it was generally believed that LISPn was better - although
opinions vary widely as to which is better.)
For example, in CL one would have to write the following:
--------------------------------------------------------------------------------
(defun add (a b)
(+ a b))
(defun subtract (a b)
(- a b))
(defun perform-function (fun a b)
(funcall fun a b))
(perform-function (function add) 5 6)
(perform-function (function subtract) 10 3)
--------------------------------------------------------------------------------
If, on the other hand CL was a LISP1 language you could just do the
following:
--------------------------------------------------------------------------------
(defun add (a b)
(+ a b))
(defun subtract (a b)
(- a b))
(defun perform-function (fun a b)
(fun a b))
(perform-function add 5 6)
(perform-function subtract 10 3)
--------------------------------------------------------------------------------
Note the differences between the definition of perform-function, and
note the difference in how perform-function is used. In fact, in a
LISP1 dialect you can even do the following:
--------------------------------------------------------------------------------
(defun add (a b)
(+ a b))
(setq myadd add)
(myadd 5 6)
(let ((a 5)
(b 10)
(fun (lambda (x y) (+ x y))))
(fun a b))
(setq another-add (lambda (a b) (+ a b)))
(another-add 5 6)
--------------------------------------------------------------------------------
There shouldn't be a need for flet, function, symbol-value, funcall or
even defun.
========================================
========================================
Lisp1 has been tested with the following Lisp systems:
CLISP
SBCL
ABCL
ECL
| |
| Rainer Joswig 2008-01-27, 4:40 am |
| In article <13pofi7f8s711c@news.supernews.com>,
Blake McBride <blake@mcbride.name> wrote:
> Announcing a new release of Lisp1.
>
> Located at: http://blake.mcbride.name
>
> From the documentations:
>
>
> Lisp1
>
> A portable (ANSI) Common Lisp program that makes Common Lisp operate
> as a LISP1 Lisp.
>
> Written and placed in the public domain by:
>
> Blake McBride
> blake@mcbride.name
>
> ========================================
========================================
>
> The problem:
>
> Common Lisp (CL) is a LISPn language. This means that symbols can
> hold normal values, functions, property lists, etc. at the same time.
> Different functions are used to manipulate these different qualities
> associated to a given symbol. The problem with this is that code
> becomes more complex and API's become large just to support these
> concurrent aspects.
Symbols are a feature. Get over it.
Where do APIs (!!!) become large because of a Lisp2? I don't
see that.
>
> In real life using the same symbol to represent a function _and_ a
> value (in the form of a variable) at the same time would be really bad
> practice. It would make the code very difficult to understand. For
> this reason, programmers rarely do this. So, in effect, CL has a lot
> of extra facilities and complexity just to support a feature that
> programmers generally avoid.
FUD and incorrect.
>
> LISP1 dialects associate a symbol with a single value. This single
> value can be any value e.g. a number, a list, or a function. Since
> functions are treated just like any other value, they can be passed or
> assigned as is any other value. In effect, functions become first
> class citizens.
FUNCTIONS are first class citizens in Common Lisp, thank you.
>
> (Historical note: CL is a LISPn language mainly for historical reasons
> - to be compatible with Lisp's that came before it, not necessarily
> because it was generally believed that LISPn was better - although
> opinions vary widely as to which is better.)
>
> For example, in CL one would have to write the following:
>
> --------------------------------------------------------------------------------
>
> (defun add (a b)
> (+ a b))
>
> (defun subtract (a b)
> (- a b))
>
> (defun perform-function (fun a b)
> (funcall fun a b))
>
> (perform-function (function add) 5 6)
>
> (perform-function (function subtract) 10 3)
>
> --------------------------------------------------------------------------------
>
> If, on the other hand CL was a LISP1 language you could just do the
> following:
>
> --------------------------------------------------------------------------------
>
> (defun add (a b)
> (+ a b))
>
> (defun subtract (a b)
> (- a b))
>
> (defun perform-function (fun a b)
> (fun a b))
>
> (perform-function add 5 6)
>
> (perform-function subtract 10 3)
From a readability standpoint, the Common Lisp code looks
much more readable, since the FUNCTIONal aspects
are explicit in the code. I can see that a function
is involved and I can see that a function passed
in as a variable is called.
This is one of the worst aspects of Scheme, that code tends
to obfuscated: (((foo a) (((foo b))))) What is it?
> --------------------------------------------------------------------------------
>
> Note the differences between the definition of perform-function, and
> note the difference in how perform-function is used. In fact, in a
> LISP1 dialect you can even do the following:
>
> --------------------------------------------------------------------------------
>
> (defun add (a b)
> (+ a b))
>
> (setq myadd add)
>
> (myadd 5 6)
>
> (let ((a 5)
> (b 10)
> (fun (lambda (x y) (+ x y))))
> (fun a b))
>
> (setq another-add (lambda (a b) (+ a b)))
>
> (another-add 5 6)
In a Lisp2 I write:
(defun add (a b)
(+ a b))
(deff myadd (function add))
(myadd 5 6)
(let ((a 5)
(b 10)
(fun (lambda (x y) (+ x y))))
(funcall fun a b))
(deff another-add (lambda (a b) (+ a b)))
(another-add 5 6)
Hardly much worse.
>
> --------------------------------------------------------------------------------
>
> There shouldn't be a need for flet, function, symbol-value, funcall or
> even defun.
I don't agree with the stuff you are writing. Plus, Common Lisp
is the way it is. Better swim with the water, not against it.
If you want a Lisp1, use Scheme.
I think it is also not correct to write above while not listing
any advantages of Lisp2.
>
> ========================================
========================================
>
> Lisp1 has been tested with the following Lisp systems:
> CLISP
> SBCL
> ABCL
> ECL
| |
| Xah Lee 2008-01-27, 7:52 pm |
| Dear Blake McBride,
Thanks for your post.
Please ignore Rainer Joswig, he's one of those old Common Lisp warden
that perpetually smite any progress on innovation that lisp might
have.
Also, from my personal view, please don't use the jargon =E2=80=9Clisp1=E2=
=80=9D,
=E2=80=9Clisp2=E2=80=9D. Instead, say multi-meaning-space and single-meaning=
-space, or
Common Lisp's model of symbol cell or Scheme's lisp's model of symbol
cell. This, will communicate the concept clearly, and can have some
effect in lessening this old political gash among the lisp factions.
During recent debate here, i outline the reasons here:
=E2=80=A2 The Jargon =E2=80=9CLisp1=E2=80=9D vs =E2=80=9CLisp2=E2=80=9D
http://xahlee.org/emacs/lisp1_vs_lisp2.html
Xah
xah@xahlee.org
=E2=88=91 http://xahlee.org/
=E2=98=84
On Jan 27, 12:19 am, Blake McBride <bl...@mcbride.name> wrote:
> Announcing a new release of Lisp1.
>
> Located at: http://blake.mcbride.name
>
> From the documentations:
>
> Lisp1
>
> A portable (ANSI) Common Lisp program that makes Common Lisp operate
> as a LISP1 Lisp.
>
> Written and placed in the public domain by:
>
> Blake McBride
> bl...@mcbride.name
http://blake.mcbride.name/software/lisp1/index.html
| |
| Maciej Katafiasz 2008-01-27, 7:52 pm |
| Den Sun, 27 Jan 2008 06:32:23 -0800 skrev Xah Lee:
> Also, from my personal view, please don't use the jargon “lisp1”,
> “lisp2”. Instead, say multi-meaning-space and single-meaning-space, or
> Common Lisp's model of symbol cell or Scheme's lisp's model of symbol
> cell. This, will communicate the concept clearly, and can have some
> effect in lessening this old political gash among the lisp factions.
Right, because personal made-up terminology will be perfectly clear from
get-go just by the virtue of being invented by the infallible Xah Lee,
and calling names is a well-known technique widely applied for lowering
political tensions. Ad-hominem attacks on Rainer are not even worth
commenting on.
You, sir, are a flaming idiot and it never ceases to amaze me how
competent people I respect find the time and energy to put up with your
offensively arrogant ignorance. Guess I'm not becoming saint anytime soon.
Maciej
| |
| Ray Blaak 2008-01-27, 7:52 pm |
| Blake McBride <blake@mcbride.name> writes:
> Announcing a new release of Lisp1.
[...]
> A portable (ANSI) Common Lisp program that makes Common Lisp operate
> as a LISP1 Lisp.
Not to diminish your efforts, but I wonder why you would bother doing this, or
why one would bother using this.
If the use of Lisp1 is important to a programmer, they should just use a real
Lisp1 language. Pick a decent scheme implementation.
If the use of Common Lisp is important, than it makes no sense but to use
anything else but the real thing. CL is LispN, and you need to get your head
around that to use it properly.
Otherwise all one is doing is creating an artificial problem to work around,
and that seems like a waste of time to me.
--
Cheers, The Rhythm is around me,
The Rhythm has control.
Ray Blaak The Rhythm is inside me,
rAYblaaK@STRIPCAPStelus.net The Rhythm has my soul.
| |
| Xah Lee 2008-01-27, 7:52 pm |
| Doing it is important, because it provides a solution that people may
want. e.g. people who wants to use Common Lisp but want Scheme lisp's
model of the symbol cell.
If it so happens that enough people use it, it paves way for future
change for Common Lisp.
Xah
xah@xahlee.org
=E2=88=91 http://xahlee.org/
=E2=98=84
On Jan 27, 10:43=C2=A0am, Ray Blaak <rAYbl...@STRIPCAPStelus.net> wrote:
> Blake McBride <bl...@mcbride.name> writes:
> [...]
>
> Not to diminish your efforts, but I wonder why you would bother doing this=
, or
> why one would bother using this.
>
> If the use of Lisp1 is important to a programmer, they should just use a r=
eal
> Lisp1 language. Pick a decent scheme implementation.
>
> If the use of Common Lisp is important, than it makes no sense but to use
> anything else but the real thing. CL is LispN, and you need to get your he=
ad
> around that to use it properly.
>
> Otherwise all one is doing is creating an artificial problem to work aroun=
d,
> and that seems like a waste of time to me.
>
> --
> Cheers, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0The=
Rhythm is around me,
> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0The Rhythm has control.
> Ray Blaak =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0The Rhy=
thm is inside me,
> rAYbl...@STRIPCAPStelus.net =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0The Rhythm has my soul.
| |
| Blake McBride 2008-01-27, 7:52 pm |
| Ray Blaak wrote:
> Blake McBride <blake@mcbride.name> writes:
> [...]
>
> Not to diminish your efforts, but I wonder why you would bother doing this, or
> why one would bother using this.
>
> If the use of Lisp1 is important to a programmer, they should just use a real
> Lisp1 language. Pick a decent scheme implementation.
>
> If the use of Common Lisp is important, than it makes no sense but to use
> anything else but the real thing. CL is LispN, and you need to get your head
> around that to use it properly.
>
> Otherwise all one is doing is creating an artificial problem to work around,
> and that seems like a waste of time to me.
>
I have been using one type of Lisp or another since 1980. I have a
personal preference for a LISP1 Lisp. I have spent most of my Lisp time
with Scheme for the last ten years mainly for this reason. In the
language space offered by Common Lisp and Scheme I have the following
_personal_ opinions. Again these are just personal opinions.
1. LISP1 is the most important thing to me which is why I have been
using Scheme.
2. There are a number of design decisions associated with Scheme which
I strongly disagree with.
3. I find that the only important (to me) design decision I don't like
about CL is the LISPn thing.
This situation leaves me with a number of choices as follows:
A. Just pick one language and use it as-is.
B. Pick one and fix the things I don't like.
C. Write my own language.
I like option C the best but (like everyone else) have time limitations.
I'll probably end up doing this in the very long run.
Option A is just not in my nature.
Ten years ago I picked Scheme and have been fixing it ever since (with
packages similar to the Lisp1 thing I wrote for CL). After all this
time I am now beginning to think that fixing the one thing I don't like
about CL is easier than fixing the N number of things in Scheme.
On another note, I'd sure appreciate not getting beaten up all the time.
I mean no one any harm or ill will. I clearly don't know as much CL as
many of you out there, nor am I capable of wording every comment in the
most technically precise and politically correct way. I have personal
preferences and opinions just like everyone else. I love Lisp as much
as any of you. In my own way I am trying to help the cause so to speak.
I appreciate your help when you care to give it, and I offer what help
I can when I can. Everyone of us has different opinions, levels of
knowledge and experience, and preferences. It would be great if we
could help one another when we can and care to, and allow for those of
us who have less expertise or capability, or a different opinion.
Blake McBride
| |
| Blake McBride 2008-01-27, 7:52 pm |
| Xah Lee wrote:
> Doing it is important, because it provides a solution that people may
> want. e.g. people who wants to use Common Lisp but want Scheme lisp's
> model of the symbol cell.
>
> If it so happens that enough people use it, it paves way for future
> change for Common Lisp.
>
> Xah
> xah@xahlee.org
> ∑ http://xahlee.org/
>
Well put.
| |
| Pascal Costanza 2008-01-27, 7:52 pm |
| Ray Blaak wrote:
> Blake McBride <blake@mcbride.name> writes:
> [...]
>
> Not to diminish your efforts, but I wonder why you would bother doing this, or
> why one would bother using this.
Common Lisp is a very good basis for multiparadigm programming. It
supports imperative, object-oriented and functional programming really
well. However, a certain higher-order programming style works a bit
better in a Lisp-1 than in a Lisp-n. It would be nice to be able to
switch "worlds" in that regard.
> If the use of Lisp1 is important to a programmer, they should just use a real
> Lisp1 language. Pick a decent scheme implementation.
....or Dylan. If it only had s-expression syntax.
Pascal
--
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
| |
| Rainer Joswig 2008-01-27, 7:52 pm |
| In article <13pponsd15a5ca0@news.supernews.com>,
Blake McBride <blake@mcbride.name> wrote:
> Xah Lee wrote:
>
> Well put.
But bullshit. The 'Symbol Cell' has nothing to do with that.
(lambda (b)
(let ((foo 10))
(flet ((foo (bar)
(+ bar 10)))
(foo (+ foo b)))))
This is Lisp2 (Common Lisp) code. In the code the name
FOO is used to reference a variable and a function.
THERE ARE NO SYMBOLS INVOLVED. ZERO. Not even one.
+ can be open-coded by the compiler. Symbol gone.
FOO will be replaced by references. Symbol gone.
BAR will be replaced by a reference. Symbol gone.
b will be replaced by a reference. Symbol gone.
CL-USER> (disassemble *)
48782EF0: .ENTRY "LAMBDA (B)"(b) ; (FUNCTION (T) NUMBER)
F08: POP DWORD PTR [EBP-8]
F0B: LEA ESP, [EBP-32]
F0E: CMP ECX, 4 ; [:NON-LOCAL-ENTRY]
F11: JNE L0
F13: MOV [EBP-12], EDX
F16: MOV EDX, [EBP-12] ; No-arg-parsing entry point
; [:NON-LOCAL-ENTRY]
F19: MOV EDI, 40
;;; [12] (+ FOO B)
F1E: CALL #x100001D0 ; #x100001D0: GENERIC-+
; [:CALL-SITE]
F23: MOV ESP, EBX ; [:SINGLE-VALUE-RETURN]
;;; [6] (FLET ((FOO (BAR)
;;; (+ BAR 10))) ..)
F25: MOV EDI, 40 ; [:BLOCK-START]
;;; [10] (+ BAR 10)
F2A: CALL #x100001D0 ; #x100001D0: GENERIC-+
; [:CALL-SITE]
F2F: MOV ESP, EBX ; [:SINGLE-VALUE-RETURN]
F31: MOV ECX, [EBP-8] ; [:BLOCK-START]
F34: MOV EAX, [EBP-4]
F37: ADD ECX, 2
F3A: MOV ESP, EBP
F3C: MOV EBP, EAX
F3E: JMP ECX
F40: L0: BREAK 10 ; Error trap
F42: BYTE #x02
F43: BYTE #x1A ; INVALID-ARGUMENT-COUNT-ERROR
F44: BYTE #x4F ; ECX
;
Do you see any SYMBOL in the compiled code? I don't see any.
The compiler will compile it to machine code and no
lookup whatsoever will be done on symbols. This
is in Common Lisp. There are no 'Symbol Cells' that
will be used here.
Please get this straight before you guys talk again over
symbols.
Symbols come into play when one uses symbols in a Lisp2.
For example as global names for functions.
Lisp1 or Lisp2 is an issue that exists independent of symbols.
| |
| Maciej Katafiasz 2008-01-27, 7:52 pm |
| Den Sun, 27 Jan 2008 22:06:51 +0100 skrev Rainer Joswig:
> The compiler will compile it to machine code and no lookup whatsoever
> will be done on symbols. This is in Common Lisp. There are no 'Symbol
> Cells' that will be used here.
>
> Please get this straight before you guys talk again over symbols.
>
> Symbols come into play when one uses symbols in a Lisp2. For example as
> global names for functions.
>
> Lisp1 or Lisp2 is an issue that exists independent of symbols.
And, as has been recently explained in great detail, Scheme symbols don't
even have cells. So no matter how hard you try, you can't get the "Scheme
model of the symbol cell".
Cheers,
Maciej
| |
| Ray Blaak 2008-01-27, 7:52 pm |
| Blake McBride <blake@mcbride.name> writes:
> On another note, I'd sure appreciate not getting beaten up all the time. I
> mean no one any harm or ill will.
Nor do I. I don't believe I was beating up on you, but if you think I was
then, hey, I apologize.
> I have personal preferences and opinions just like everyone else.
And you state them. And responses are stated back.
My opinion is that major language work arounds like trying to make CL to be
Lisp1 are not worth the effort. This is nothing personal against you, but only
based on technical reasons.
Consider that your Lisp1 CL code will have to be used in conjunction with 3rd
party libraries. People have to maintain your code after you have moved on. If
you are doing something different from the fundamental style of the language,
your code will be hard to use for other CL programmers.
In the case of your language preferences, the "correct" thing would be for you
to make your own language. But languages cannot really be used in isolation,
and your code fundamentally will need to work with other programmer's code.
So, in practice, finding the using the language with the least amount of warts
is the only effective solution.
Or just use your Lisp1 CL package. Hey, you might luck out and it might catch
on. But you have to be prepared to be pratical if it doesn't, since you can't
program in isolation.
--
Cheers, The Rhythm is around me,
The Rhythm has control.
Ray Blaak The Rhythm is inside me,
rAYblaaK@STRIPCAPStelus.net The Rhythm has my soul.
| |
| Maciej Katafiasz 2008-01-27, 7:52 pm |
| Den Sun, 27 Jan 2008 13:54:37 -0600 skrev Blake McBride:
> On another note, I'd sure appreciate not getting beaten up all the time.
> I mean no one any harm or ill will. I clearly don't know as much CL as
> many of you out there, nor am I capable of wording every comment in the
> most technically precise and politically correct way. I have personal
> preferences and opinions just like everyone else. I love Lisp as much
> as any of you. In my own way I am trying to help the cause so to speak.
The problem is not with your preferences. The problem is with your widely
inaccurate and plain wrong assessments of how LispN is a problem and a
wart on the language your package fixes. It's not a wart in the opinion
of the overwhelming majority of c.l.l denizens, and so your claims to the
contrary get rightly bashed. Stop claiming things that are demonstrably
false, and you'll stop getting flak for doing that.
Cheers,
Maciej
| |
| mikael.jansson@gmail.com 2008-01-28, 4:56 am |
| On Jan 27, 9:03=A0pm, Pascal Costanza <p...@p-cos.net> wrote:
> Ray Blaak wrote:
> [...]
real[color=darkred]
>
> ...or Dylan. If it only had s-expression syntax.
>
=46rom what I understand, the reason most languages don't have macros is
because they don't have s-exps. Now, IIRC Dylan has that. It'd seem
that's one of the most compelling reasons to use Lisp.
So, what does Dylan offer that CL does not?
(I'm sorry if I come across as offensive, however I'm just curious!)
--
Mikael
http://mikael.jansson.be
| |
| Pascal Costanza 2008-01-28, 4:56 am |
| mikael.jansson@gmail.com wrote:
> On Jan 27, 9:03 pm, Pascal Costanza <p...@p-cos.net> wrote:
> From what I understand, the reason most languages don't have macros is
> because they don't have s-exps. Now, IIRC Dylan has that. It'd seem
> that's one of the most compelling reasons to use Lisp.
S-expressions are not a strict requirement for having macros in a
language. You can even add a full AST-based macro system to a highly
syntactically irregular language, like Java. The more regular the
syntax, though, the easier it is and, IMHO, the easier it is to actually
define and use macros. S-expressions are as regular as it gets, and thus
make macros very straightforward.
> So, what does Dylan offer that CL does not?
Not much. It has a somewhat nicer integration of its object system with
the base language. Common Lisp distinguishes between generic functions,
plain functions and methods. If I understand correctly, in Dylan they
are all integrated into the same unified notion of a method. On the
other hand, CLOS still has more complete support for metaprogramming in
terms of its metaobject protocol and user-defined method combinations.
(I am not aware of any object system that it as complete as CLOS, not
even any of the CLOS derivatives in other Lisp dialects, like Scheme.)
Apparently, Dylan's iteration framework seems to be very nice (but that
could already be added as a plain library, like
http://common-lisp.net/project/cl-containers/ ).
Maybe there's more, but I wouldn't know off the top of my head.
Nevertheless, I think it would be a much better Scheme than the R6RS
mess, if it only were based on s-expressions. However, some of the Dylan
supporters really like the more mainstream Dylan syntax, so it's not
very likely to happen...
Pascal
--
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
| |
| Rainer Joswig 2008-01-28, 9:00 am |
| In article <605q0sF1phenkU1@mid.individual.net>,
Pascal Costanza <pc@p-cos.net> wrote:
> mikael.jansson@gmail.com wrote:
>
> S-expressions are not a strict requirement for having macros in a
> language. You can even add a full AST-based macro system to a highly
> syntactically irregular language, like Java. The more regular the
> syntax, though, the easier it is and, IMHO, the easier it is to actually
> define and use macros. S-expressions are as regular as it gets, and thus
> make macros very straightforward.
It also should be noted that ANSI CL lacks the access to
the environment information during macro expansion.
Much of that was in CLtL2, but didn't make it into ANSI CL.
http://lispm.dyndns.org/documentati...000000000000000
>
>
> Not much. It has a somewhat nicer integration of its object system with
> the base language. Common Lisp distinguishes between generic functions,
> plain functions and methods. If I understand correctly, in Dylan they
> are all integrated into the same unified notion of a method. On the
> other hand, CLOS still has more complete support for metaprogramming in
> terms of its metaobject protocol and user-defined method combinations.
> (I am not aware of any object system that it as complete as CLOS, not
> even any of the CLOS derivatives in other Lisp dialects, like Scheme.)
>
> Apparently, Dylan's iteration framework seems to be very nice (but that
> could already be added as a plain library, like
> http://common-lisp.net/project/cl-containers/ ).
>
> Maybe there's more, but I wouldn't know off the top of my head.
>
> Nevertheless, I think it would be a much better Scheme than the R6RS
> mess, if it only were based on s-expressions. However, some of the Dylan
> supporters really like the more mainstream Dylan syntax, so it's not
> very likely to happen...
>
>
> Pascal
| |
| Pascal Costanza 2008-01-28, 9:00 am |
| Rainer Joswig wrote:
> In article <605q0sF1phenkU1@mid.individual.net>,
> Pascal Costanza <pc@p-cos.net> wrote:
>
>
> It also should be noted that ANSI CL lacks the access to
> the environment information during macro expansion.
> Much of that was in CLtL2, but didn't make it into ANSI CL.
>
> http://lispm.dyndns.org/documentati...000000000000000
That's a bit harsh. Yes, something like what is described in CLtL2 would
be very nice here, but you can already do a lot (really a lot) with what
is already provided in ANSI Common Lisp.
The trick is to use symbol-macrolet / macrolet to pass around
information, and macrolet / macrolet-1 to retrieve that information
again. (It's actually pretty close to expansion-passing style.)
Pascal
--
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
| |
| Rainer Joswig 2008-01-28, 7:43 pm |
| In article <6067i6F1p1cuaU1@mid.individual.net>,
Pascal Costanza <pc@p-cos.net> wrote:
> Rainer Joswig wrote:
>
> That's a bit harsh. Yes, something like what is described in CLtL2 would
> be very nice here, but you can already do a lot (really a lot) with what
> is already provided in ANSI Common Lisp.
>
> The trick is to use symbol-macrolet / macrolet to pass around
> information, and macrolet / macrolet-1 to retrieve that information
> again. (It's actually pretty close to expansion-passing style.)
Would you use that to write a portable code walker that would be
able to identify variables, functions, declarations, variable types, ...?
>
>
> Pascal
| |
| Ron Garret 2008-01-28, 7:43 pm |
| In article <6067i6F1p1cuaU1@mid.individual.net>,
Pascal Costanza <pc@p-cos.net> wrote:
> Rainer Joswig wrote:
>
> That's a bit harsh. Yes, something like what is described in CLtL2 would
> be very nice here, but you can already do a lot (really a lot) with what
> is already provided in ANSI Common Lisp.
>
> The trick is to use symbol-macrolet / macrolet to pass around
> information, and macrolet / macrolet-1 to retrieve that information
> again. (It's actually pretty close to expansion-passing style.)
You mean macroexpand/macroexpand-1 I presume.
rg
| |
|
|
| Pascal Costanza 2008-01-28, 7:43 pm |
| Rainer Joswig wrote:
> In article <6067i6F1p1cuaU1@mid.individual.net>,
> Pascal Costanza <pc@p-cos.net> wrote:
>
>
> Would you use that to write a portable code walker that would be
> able to identify variables, functions, declarations, variable types, ...?
I'm not sure, because I don't have that much experience with code
walkers, but I guess I would give it a try. My gut feeling is that it
should be doable.
ANSI CL's environment objects are primarily good for passing information
from outer scopes to inner scopes (like "This variable has the following
declared type."), and for that you don't need a code walker, you just
need symbol-macrolet / macrolet and macroexpand. Passing information
from inner scopes to outer scopes (like "Is this function ever used as a
first-class value inside this body?") is definitely harder.
It is possible to additionally use *macroexpand-hook* to embed a code
walker inside a macro, but that's quite shaky. (That's the only way I
tried to implement a code walker myself so far.)
Pascal
--
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
| |
| Johann Hchtl 2008-01-28, 7:43 pm |
| Blake McBride wrote:
> Ray Blaak wrote:
>
> I have been using one type of Lisp or another since 1980. I have a
> personal preference for a LISP1 Lisp. I have spent most of my Lisp time
> with Scheme for the last ten years mainly for this reason. In the
> language space offered by Common Lisp and Scheme I have the following
> _personal_ opinions. Again these are just personal opinions.
>
> 1. LISP1 is the most important thing to me which is why I have been
> using Scheme.
I would appreciate you to elaborate more on this point and If those
warts may be cured by R6RS?
>
> Blake McBride
Johann
| |
| Johann Hchtl 2008-01-28, 7:43 pm |
| Blake McBride wrote:
> Ray Blaak wrote:
> 2. There are a number of design decisions associated with Scheme
> which I strongly disagree with.
>
>
I would appreciate you to elaborate more on this point and If those
warts may be cured by R6RS?
> Blake McBride
| |
| Ray Dillinger 2008-01-28, 7:43 pm |
|
Interesting.
I'm doing Lispy design too, and I came down with a slightly
different split between the Lisp-1 and Lisp-2 questions. I
guess you might call it a Lisp-H if you have to have names for
things.
I'm using hierarchical naming, where subfields or "attributes"
are name extensions. "vehicle", "vehicle|motor",
"vehicle|motor|displacement", "vehicle|wheels", etc, can all have
different values, but when I pass "vehicle" to a function, and
it gets bound to a local name like "fredscar", all the
hierarchical extensions are automatically available in that
function, as "fredscar|motor", "fredscar|motor|displacement"
etc.
One interesting bit that falls out is that I can pass a
partial hierarchical name instead of a simple name, like
"vehicle|motor", and if it gets bound to a local name like
"vroom", then "vroom" and "vroom|displacement" are available
in the function.
There's no multiplicity of mutators and accessors as in a
typical Lisp-N, because the information about what attribute
(what hierarchical subfield) to set and access is carried in
the extended name rather than in the name of the mutator or
accessor. Even things like scheme's "set-car!" and "set-cdr!"
go away, because (assuming your cons cell is named "place"),
you just call (set! place|car) or (set! place|cdr) instead.
Bear
| |
| Blake McBride 2008-01-28, 7:43 pm |
| Johann Hchtl wrote:
> Blake McBride wrote:
>
>
> I would appreciate you to elaborate more on this point and If those
> warts may be cured by R6RS?
I'd be happy to. In fact I have posted articles about some of the
things in the past. May I suggest that rather than me posting this,
perhaps I can e-mail these comments to you. I can't imagine the beating
I'd take if I posted it. Perhaps you can e-mail me your e-mail address.
If I have to post it, though, I'll just post it to c.l.scheme and not .lisp.
Blake McBride
| |
| Abdulaziz Ghuloum 2008-01-28, 7:43 pm |
| Blake McBride wrote:
> I'd be happy to. In fact I have posted articles about some of the
> things in the past. May I suggest that rather than me posting this,
> perhaps I can e-mail these comments to you. I can't imagine the beating
> I'd take if I posted it. Perhaps you can e-mail me your e-mail address.
I was also going to ask you a similar thing. You said you liked
everything in CL except the lisp-2-ness of it. You also said you
disagreed with some of the design decisions of Scheme but did not
elaborate on those. So, yes, I too am interested in knowing what
those are.
Aziz,,,
PS. I would leave any mention of R6 vs. R5 in the thread if we're
going to get anywhere in c.l.s.
PS2. You can leave c.l.l. out if you think it's better that way.
PS3. Or you can CC me in your email :-)
| |
| Edi Weitz 2008-01-28, 7:43 pm |
| On Mon, 28 Jan 2008 15:35:50 +0100, Pascal Costanza <pc@p-cos.net> wrote:
> The trick is to use symbol-macrolet / macrolet to pass around
> information, and macrolet / macrolet-1 to retrieve that information
> again. (It's actually pretty close to expansion-passing style.)
Could you provide a small example? I don't think I fully understand
what you mean.
Thanks,
Edi.
--
European Common Lisp Meeting, Amsterdam, April 19/20, 2008
http://weitz.de/eclm2008/
Real email: (replace (subseq "spamtrap@agharta.de" 5) "edi")
| |
| Blake McBride 2008-01-28, 10:35 pm |
| Abdulaziz Ghuloum wrote:
> Blake McBride wrote:
>
>
> I was also going to ask you a similar thing. You said you liked
> everything in CL except the lisp-2-ness of it. You also said you
> disagreed with some of the design decisions of Scheme but did not
> elaborate on those. So, yes, I too am interested in knowing what
> those are.
>
>
> Aziz,,,
>
> PS. I would leave any mention of R6 vs. R5 in the thread if we're
> going to get anywhere in c.l.s.
>
> PS2. You can leave c.l.l. out if you think it's better that way.
>
> PS3. Or you can CC me in your email :-)
Okay here is one (which R6 doesn't fix).
Contradiction in separation of NIL and #f
Lisp has long used NIL as "false" or #f. This was very convenient
since lisp is a list processing language, traversing through a list is
very often done. Having NIL and #f equal means one could use:
(while lst ...
or
(if lst ...
With the separation of NIL and #f in scheme one is forced into:
(while (not (null? lst)) ...
or
(if (not (null? lst)) ...
The argument for separating NIL and false was in the name of clarity
as opposed to depending on a coincidence. It would be much more clear
(to a beginner?) what was going on. (Although, if you really want to
be clear, perhaps we should all program in ADA. ADA is a language in
which virtually every line of code has to do with clarity and
virtually none has to do with solving the problem at hand!)
The problem is that scheme has eliminated, rather arbitrarily, one
instance of dependence on a trick but left so many others that it
renders the NIL / false separation no more than a constant annoyance.
For example, if NIL and #f are kept apart, why allow anything except
#f equal true? Yes, I know it is very convenient (just like #f and
NIL being equal), but it is also "unclear". Having:
(if "abc" 6 7)
return 6 is absolute nonsense. Scheme has chosen clarity and
correctness in one instance and convenience in another. It is very
inconsistent. If you wanted to be truly consistent:
(+ "abc" 6)
returns a type error. So:
(if "abc" 6 7)
should also return a type error. The same is true for scheme's:
and
or
not
cond
etc.
Look, ADA already has the market on clarity and correctness. Lisp and
scheme have the elegant, expressiveness, and power market. Why
arbitrarily go down the clarity path with the separation of NIL and #f
- it is a mistake. The only other "consistent" choice is to separate
#t from all else, make all logic operations require #t or #f, and make
scheme the ADA of lisp.
Blake McBride
blake@mcbride.name
| |
| Xah Lee 2008-01-28, 10:35 pm |
| Blake McBride <bl...@mcbride.name> wrote:
=C2=AB[Scheme's] Contradiction in separation of NIL and #f=C2=BB
Great point! I fully agree.
A bit rambling of this issue with regards to Mathematica.
In Mathematica, there's symbols True and False. If a predicate expect
a boolean but something other than True or False is given, then the
expression evaluates to itself. (i.e. without resolving into anything)
Example:
In[1]:=3D
If[True,3,4]
Out[1]=3D
3
In[2]:=3D
If[False,3,4]
Out[2]=3D
4
In[3]:=3D
If[something,3,4]
Out[3]=3D
If[something,3,4]
---------------------
Here's some personal story about how i ventured into lisp.
The path of my computing experience is kinda unusual like most other
things about me. In 1991, i was 23, and was attending a 2-year
community college in California. (DeAnza College and Foothill college)
(i have never had highschool (more or less never had a _chance_ to,
actually.))
During these college years (which is about 1991-1994, rather unusually
long for a 2-year community college), i've took all math courses they
offered (roughly equivalent to math classes of first 2 years in a 4
years university; culminating in multi-var calculus and a intro course
on Differential Equations and Linear Algebra, but no Abstract Algebra
nor Analysis proper), but i've never took any computer science
courses. (i think i might have taken a Pascal course)
It is also during the early 1990s, i started to learn programing on my
own. My first =E2=80=9Clanguage=E2=80=9D is the one in HP-28s programable sc=
ientific
calculator. I remember having wrote a program to solve the 8-queens
problem all on my own. (without knowing or heard of the term back-
tracking) (see http://xahlee.org/prog/hp28s/hp28s.html )
And, during these years i bought Mathematica (because i heard it's the
best math tool and i love math and wanted to have the best tool). I
taught myself Mathematica and wrote some programs for visualizing
plane curves. ( see http://xahlee.org/SpecialPlaneCurve...pecialPlaneCur=
ves.html
)
By 1997, i'm one of the world's top Mathematica application-programing
expert. But the curious thing is that, i have absolutely no idea what
is a compiler, parser, lexer, and absolutely have no faintest idea how
Operating System worked or its basic structure or purpose in technical
terms, and have absolutely no idea how networking worked. Do not even
have a practical concept of what's a computing protocol (as in TCP/
IP). Absolutely do not know anything about =E2=80=9Cunix=E2=80=9D, and vivid=
ly
remember that i don't know what is =E2=80=9Ctar=E2=80=9D and =E2=80=9Cgzip=
=E2=80=9D (just know that
these are something in =E2=80=9Cunix workstations=E2=80=9D and some mysterio=
us GNU).
(during all these years up to 1997, i was using Mac, being what a Mac
fan might call a =E2=80=9Cpower user=E2=80=9D (as a computer user (as oppose=
d to a
programer); and using the mouse; in the days when Macs are just Finder
and Multi-Finder, and used by Desktop publishing, with MacUser and
MacWorld magazinings publishing tricks and software application
reviews etc. (e.g. Microsoft Word, Word Perfect, Nesus Writer,
Spreadsheets...etc)))
I must stress, i have absolutely no concrete idea about anything that
a normal computer science student would know in his first year. I do
not have any concrete idea what IS a language specification (such as
Java lang spec or Common Lisp =E2=80=9CHyperspec=E2=80=9D or Emacs Lisp Refe=
rence
Manual, etc) I have close to absolutely no knowledge to how ANY other
computing languages. Put in another way, i wouldn't know how to write
a Hello Word in any other language. I have no notion of what's a
=E2=80=9Cwhite paper=E2=80=9D, =E2=80=9Cfunctional programing=E2=80=9D, and =
DO NOT understand (or even
heard of) the meaning of =E2=80=9Cside effect=E2=80=9D (in the context of fu=
nctional
programing). (i vividly recall, the first time i heard the term =E2=80=9Csid=
e
effect=E2=80=9D, is in 1995 when i was trying to describe a nature of the co=
de
i wrote in some verbose manner, to Stephen Wolfram (in the sense a
student is trying to present his idea), and he said =E2=80=9C[you mean] side=
effect=E2=80=9D, and i was like =E2=80=9CYeah, exactly, =E2=80=98side effect=
=E2=80=99!=E2=80=9D (and feeling
enlightened how the phrase described the situation well).)
The gist of this is that, from my programing experience from 1991 to
about 1997, i learned programing only in HP-28s and Mathematica, by
the shear reading of their manual from cover to cover (practically
several times), while having just about no concept of any programing a
1st year computer science student would know. (I do know, of course
the concept of algorithm, as that is essential to programing and is
also a fundamental concept in math and discrete math, which i have
learned a lot mostly by myself too. (But i do not at the time know
anything actual, typical Algorithms that are taught, such as sorting
algorithms, tree walkers, etc) (i have tried to read Knuth's Art Of
Programing but it was pretty imcomprehensible))
=46rom about 1997 onwards, i started to study most of these things,
starting with unix and perl, by sheer reading of the manuals and
documentations and books and hands on coding in them. (by 2000, i'm
fairly a unix admin and perl expert, with knowledges in SQL/database,
working knowledeg of IP protocols... etc, actually working in start-
ups in Sillicon Valley's tech boom since late 1998.)
Ok, the main point i started to write this personal history, is my
first encounter with Lisp. (the previous paragraphs are just intro.)
Although lacking a formal or conventional education, i'm by birth
fairly intelligent and by nature very curious. This means i have read
a lot of books or texts or literatures i have in contact with and in
library (was a avid library visitor), such as the massive number of
programing FAQs and FAQs of other subjects (such as BDSM) etc. So, it
is very present in my awareness, that there is a language called Lisp,
and is supposed to be extremely powerful and beautiful. And, at the
time, i have heard, that Scheme, is the most beautiful and elegant
language that exists. (this is my reading impression, anyway) And, i
heard that the book =E2=80=9CThe Structure and Interpretation of Computer
Programs=E2=80=9D by Harold Abelson et al, is the best computer science book=
..
So, i started to read it and learn Scheme.
Remember, at the time i'm a master of Mathematica _the language_
itself, yet do not know much about the basics of computer science.
When i started to learn Scheme, the first thing that hit me is the
cons business. To me, who are accustomed to Mathematica, finding the
cons business weird and unwieldy. It puzzled me. I was thinking, how
can a elegant language have this? Certainly in Mathematica i can
extract and manipulate tree structure far more easily. At the time,
since i barely have basic knowledge of any computer science subjects,
i was greatly puzzled about the situation. (in fact made a newsgroup
post in comp.lang.scheme (and was flamed by one Erik Naggum) (this is
1998 or 1999, i think))
Of course, today, with various levels of expertise in several
languages (Mathematica, emacs lisp, perl, php, javascript, sql, java,
Linden Scripting Lang (Second Life virtual world), inert langs (HTML/
CSS/LaTeX,POV-Ray ...)) and have read countless tech papers and worked
in complex software, data centers, and wallowed in all kinds of
industrial spaghetti code with non-existent documentations, i know for
a certainly, that Mathematica, which perchance to be my first
language, is in fact the world's _most_ advanced and high-level
language, bar none.
(this short personal account is not supposed to be a pitch for
Mathematica. It just came out that way. There are, of course other
langs, depending on context and area of application, are equal quality
as Mathematica. For example, i would think Haskell, erlang, ML/OCaml
family etc would qualify, but i just have not actually learned these)
(gee, i just typed as quickly as possible and it came out to be over 1
thousand words of a brief personal bio of my computing experiences.
Good for me! The orginial intention was just to describe my first
impression of Scheme)
Xah
xah@xahlee.org
=E2=88=91 http://xahlee.org/
=E2=98=84
On Jan 28, 5:48 pm, Blake McBride <bl...@mcbride.name> wrote:
> Okay here is one (which R6 doesn't fix).
>
> Contradiction in separation of NIL and #f
>
> Lisp has long used NIL as "false" or #f. This was very convenient
> since lisp is a list processing language, traversing through a list is
> very often done. Having NIL and #f equal means one could use:
>
> (while lst ...
> or
> (if lst ...
>
> With the separation of NIL and #f in scheme one is forced into:
>
> (while (not (null? lst)) ...
> or
> (if (not (null? lst)) ...
>
> The argument for separating NIL and false was in the name of clarity
> as opposed to depending on a coincidence. It would be much more clear
> (to a beginner?) what was going on. (Although, if you really want to
> be clear, perhaps we should all program in ADA. ADA is a language in
> which virtually every line of code has to do with clarity and
> virtually none has to do with solving the problem at hand!)
>
> The problem is that scheme has eliminated, rather arbitrarily, one
> instance of dependence on a trick but left so many others that it
> renders the NIL / false separation no more than a constant annoyance.
> For example, if NIL and #f are kept apart, why allow anything except
> #f equal true? Yes, I know it is very convenient (just like #f and
> NIL being equal), but it is also "unclear". Having:
>
> (if "abc" 6 7)
>
> return 6 is absolute nonsense. Scheme has chosen clarity and
> correctness in one instance and convenience in another. It is very
> inconsistent. If you wanted to be truly consistent:
>
> (+ "abc" 6)
>
> returns a type error. So:
>
> (if "abc" 6 7)
>
> should also return a type error. The same is true for scheme's:
>
> and
> or
> not
> cond
> etc.
>
> Look, ADA already has the market on clarity and correctness. Lisp and
> scheme have the elegant, expressiveness, and power market. Why
> arbitrarily go down the clarity path with the separation of NIL and #f
> - it is a mistake. The only other "consistent" choice is to separate
> #t from all else, make all logic operations require #t or #f, and make
> scheme the ADA of lisp.
>
> Blake McBride
> bl...@mcbride.name
| |
| Duane Rettig 2008-01-29, 7:41 pm |
| Pascal Costanza <pc@p-cos.net> writes:
> Rainer Joswig wrote:
>
> I'm not sure, because I don't have that much experience with code
> walkers, but I guess I would give it a try. My gut feeling is that it
> should be doable.
But why bother, when it's already been done for you? ...
http://www.lispwire.com/entry-proganal-envaccess-des
This package is portable in the sense that it compiles, loads, and
provides information on many major CL implementations (though I'm told
by Raymond Toy that there are some diffs for CMUCL that need to be
applied; I haven't seen them yet, but I'll put them in as soon as I
do. And Ray and Carl Shapiro have been working to get this (or
similar) functionality into CMUCL to the point where the compiler
actually uses it for its environment information.
> ANSI CL's environment objects are primarily good for passing
> information from outer scopes to inner scopes (like "This variable has
> the following declared type."), and for that you don't need a code
> walker, you just need symbol-macrolet / macrolet and
> macroexpand. Passing information from inner scopes to outer scopes
> (like "Is this function ever used as a first-class value inside this
> body?") is definitely harder.
and fairly soon you find that you've reimpemented first-class
environments.
To be fair, environments are already first-class for most
implementations; it is just that their interfaces are either not
public or not portable, and the above module is an attempt to inject
the Environments chapter of CLtL2 back into CL implementations.
> It is possible to additionally use *macroexpand-hook* to embed a code
> walker inside a macro, but that's quite shaky. (That's the only way I
> tried to implement a code walker myself so far.)
Well, you get the environment object, but that's no different than
defining your macro with the &environment element in the lambda list.
And I suspect that unless you know the format of the environment
object you can't portably reason about the environment nor make all of
the changes that are possible with a true portable interface.
--
Duane Rettig duane@franz.com Franz Inc. http://www.franz.com/
555 12th St., Suite 1450 http://www.555citycenter.com/
Oakland, Ca. 94607 Phone: (510) 452-2000; Fax: (510) 452-0182
| |
| Pascal Costanza 2008-01-29, 7:41 pm |
| Duane Rettig wrote:
> Pascal Costanza <pc@p-cos.net> writes:
>
>
> But why bother, when it's already been done for you? ...
>
> http://www.lispwire.com/entry-proganal-envaccess-des
Sure, that would be better.
>
> Well, you get the environment object, but that's no different than
> defining your macro with the &environment element in the lambda list.
> And I suspect that unless you know the format of the environment
> object you can't portably reason about the environment nor make all of
> the changes that are possible with a true portable interface.
*macroexpand-hook* allows you to see all macroexpansions, not just those
for your own macros. That can make a difference in some cases (but
that's probably only a theoretical advantage).
Pascal
--
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
| |
| Kaz Kylheku 2008-01-30, 4:57 am |
| On Jan 27, 11:26=A0am, Xah Lee <x...@xahlee.org> wrote:
> Doing it is important, because it provides a solution that people may
> want. e.g. people who wants to use Common Lisp but want Scheme lisp's
> model of the symbol cell.
Wanting some other model of the symbol cell is just idle nonsense
which has nothing to do with shipping an application.
A different model of the symbol cell doesn't help you write software
in any way, it's just different.
You gain absolutely no expressive power, nor do you lose any.
What you do lose is your personal effort by thinking about this and
dicking around with bullshit code to do it.
|
|
|
|
|