From: Mark Carter
Subject: Forth/APL style in Lisp
Date: 
Message-ID: <48a7480f$0$26084$db0fefd9@news.zen.co.uk>
Hi, Lisp n00b here. I have written a little accounts package in Python, 
and I was experimenting with converting it to Lisp. I'm using SBCL on OS X.

I know almost jack about Forth and APL, but it was occuring to me that 
it would be a very interesting style to try in Lisp. I think it would 
make my programs shorter, and would also be useful for making ad-hoc 
queries.

To set the stage, the app that I am writing from the ground up has two 
classes: account and entry. A ledger is composed of a list of accounts, 
and accounts have a list of entries in them.

I have defined a couple of macros/functions:

(defun foreach-lambda (list func)
   (loop for el in list do (funcall func el)))

(defmacro foreach (list arg &rest body)
   "Process each argument in a list"
   `(foreach-lambda ,list (lambda (,arg) ,@body)))


(defun find-account (code)
   (find-if (lambda (x) (eq code (account-code x)))
	   *accounts*))

(defun accounts (func)
   (foreach *accounts* a (funcall func a)))

(defun account (code func) (funcall func (find-account code)))


There's other bits in it too, but this is all I want to demonstrate just 
now.

Well, the nice thing is, if I want to debug or just do an ad-hoc query 
in the REPL, I can do something like
	(accounts #'print-balance)
to print the balances of all the accounts. If I am only interested in 
one account, I can do
	(account :bank #'print-balance)
Or, I can do other things like
	(account :bank #'describe)

That's pretty neat, and I'm getting quite enthusiastic about this 
mysterious beast called Lisp, as it is not an approach I have tried in 
Python.

Although it's quite nice, the way I have done it is not quite right, 
because if I want descriptions for the entries in an account, the call 
gets muddles with lambdas. My current definition for showing entries is

(defun show-entries (code)
   "Show the entries for an account code"
   (foreach (account-entries (find-account code)) e
	   (describe e)))

Now, I'm thinking if I had a stack-based approach, I could define it as 
something like
	(-account code) (-entries) (-describe)
If you wanted to describe all the entries in all the accounts, then you'd do
	(-accounts) (-entries) (-describe)
where the prefix of '-' denotes a convention that there is a global 
stack that is being twiddled with. And things like -account would work 
differently depending on whether the stack was a list of classes or just 
a class. It also looks really cool; there's no apparent looping 
construct, and it's very convenient and intuitive for the user.

I'm wondering if anyone has adopted a similar or better approach, and 
what came of it.

I'm finding that I can twiddle and fiddle with ideas in Lisp which I 
probably wouldn't have tried to do in Python. Having said that, I 
probably would have produced a finished result more quickly.

From: Rainer Joswig
Subject: Re: Forth/APL style in Lisp
Date: 
Message-ID: <joswig-EDAD38.00303317082008@news-europe.giganews.com>
In article <·························@news.zen.co.uk>,
 Mark Carter <··@privacy.net> wrote:

> Hi, Lisp n00b here. I have written a little accounts package in Python, 
> and I was experimenting with converting it to Lisp. I'm using SBCL on OS X.
> 
> I know almost jack about Forth and APL, but it was occuring to me that 
> it would be a very interesting style to try in Lisp. I think it would 
> make my programs shorter, and would also be useful for making ad-hoc 
> queries.
> 
> To set the stage, the app that I am writing from the ground up has two 
> classes: account and entry. A ledger is composed of a list of accounts, 
> and accounts have a list of entries in them.
> 
> I have defined a couple of macros/functions:

Well, you are basically reinventing already existing
Lisp functionality. ;-)

> 
> (defun foreach-lambda (list func)
>    (loop for el in list do (funcall func el)))

This is called MAP. mapping is a basic concept in Lisp.

(map nil (lambda (item) (do-something item)) list)

There are some other map functions (mapcar, ...).


> 
> (defmacro foreach (list arg &rest body)
>    "Process each argument in a list"
>    `(foreach-lambda ,list (lambda (,arg) ,@body)))

This is called DOLIST.

(dolist (item list) 
  (do-something item))

Btw., if you write a macro like above, you should make a small
change:

(defmacro foreach (list arg &body body)
   "Process each argument in a list"
   `(foreach-lambda ,list (lambda (,arg) ,@body)))

&body informs the Lisp system that body is a sequence
of expressions. It will usually use this information
to format code that uses this macro a little bit better.
You should compare the two. The &rest version
will be indented as if the body were normal arguments.
For the &body version the Lisp system use a different indentation.



> (defun find-account (code)
>    (find-if (lambda (x) (eq code (account-code x)))
> 	   *accounts*))

Instead of FIND-IF use FIND - that's shorter.

CL-USER 68 > (find 3 '((a 1) (b 2) (c 3)) :key #'second)
(C 3)

Don't compare numbers with EQ. Use EQL or =.

(find code *accounts* :key #'account-code)

Above will use EQL , but you can tell it to use another:

(find code *accounts* :key #'account-code :test #'account-number-equal)
You might not need it in your case. But this nice
flexibility is there in Common Lisp via various keyword arguments.


> 
> (defun accounts (func)
>    (foreach *accounts* a (funcall func a)))

(dolist (a *accounts*) (funcall func a))

or shorter

(map nil func *accounts*)

> 
> (defun account (code func) (funcall func (find-account code)))
> 
> 
> There's other bits in it too, but this is all I want to demonstrate just 
> now.
> 
> Well, the nice thing is, if I want to debug or just do an ad-hoc query 
> in the REPL, I can do something like
> 	(accounts #'print-balance)

I would rename this function to do-all-accounts or map-accounts.

> to print the balances of all the accounts. If I am only interested in 
> one account, I can do
> 	(account :bank #'print-balance)
> Or, I can do other things like
> 	(account :bank #'describe)

That makes little sense.

(describe (find-account :bank))

is just as good.


>That's pretty neat, and I'm getting quite enthusiastic about this 
> mysterious beast called Lisp, as it is not an approach I have tried in 
> Python.
> 
> Although it's quite nice, the way I have done it is not quite right, 
> because if I want descriptions for the entries in an account, the call 
> gets muddles with lambdas. My current definition for showing entries is
> 
> (defun show-entries (code)
>    "Show the entries for an account code"
>    (foreach (account-entries (find-account code)) e
> 	   (describe e)))

(map nil #'describe
     (account-entries (find-account code)))
> 
> Now, I'm thinking if I had a stack-based approach, I could define it as 
> something like
> 	(-account code) (-entries) (-describe)
> If you wanted to describe all the entries in all the accounts, then you'd do
> 	(-accounts) (-entries) (-describe)
> where the prefix of '-' denotes a convention that there is a global 
> stack that is being twiddled with. And things like -account would work 
> differently depending on whether the stack was a list of classes or just 
> a class. It also looks really cool; there's no apparent looping 
> construct, and it's very convenient and intuitive for the user.
> 
> I'm wondering if anyone has adopted a similar or better approach, and 
> what came of it.
> 
> I'm finding that I can twiddle and fiddle with ideas in Lisp which I 
> probably wouldn't have tried to do in Python. Having said that, I 
> probably would have produced a finished result more quickly.

I think the Lisp-based functional approach is fine. You just
need to use some of the built in stuff. Check the chapters
about lists, vectors, arrays and sequences in the CLHS to get
an overview about the language. Recently here was posted
a pointer to the Common Lisp Quick Reference, which also
gives a nice overview about existing functionality.

-- 
http://lispm.dyndns.org/
From: Mark Carter
Subject: Re: Forth/APL style in Lisp
Date: 
Message-ID: <48a7ecf3$0$26076$db0fefd9@news.zen.co.uk>
Rainer Joswig wrote:

> Well, you are basically reinventing already existing
> Lisp functionality. ;-)

Thanks for your help - very useful. My code is looking rather neater now!

I'm not what you'd call an OO fanatic, but I find that using classes 
seems to help. I played with Cells, but it wouldn't give me any loving.
From: Michael Weber
Subject: Ledger
Date: 
Message-ID: <f204c73d-0489-4312-bb66-073004b6a676@t54g2000hsg.googlegroups.com>
On Aug 16, 11:35 pm, Mark Carter <····@privacy.net> wrote:
> Hi, Lisp n00b here. I have written a little accounts package in Python,
> and I was experimenting with converting it to Lisp. I'm using SBCL on OS X.
[...]
> I'm finding that I can twiddle and fiddle with ideas in Lisp which I
> probably wouldn't have tried to do in Python. Having said that, I
> probably would have produced a finished result more quickly.

Faster results can often be achieved by using the appropriate building
blocks.  You might be able to leverage John Wiegley's CAMBL for
monetary calculations:
http://github.com/jwiegley/ledger/tree/cambl-20080203

He also used it for a ledger application (a port of his C++ ledger):
http://github.com/jwiegley/ledger/tree/cl-ledger-20080203
From: Mark Carter
Subject: Re: Ledger
Date: 
Message-ID: <48a7f7d3$0$2925$fa0fcedb@news.zen.co.uk>
Michael Weber wrote:
> On Aug 16, 11:35 pm, Mark Carter <····@privacy.net> wrote:
>> Hi, Lisp n00b here. I have written a little accounts package in Python,
>> and I was experimenting with converting it to Lisp. I'm using SBCL on OS X.
> [...]
>> I'm finding that I can twiddle and fiddle with ideas in Lisp which I
>> probably wouldn't have tried to do in Python. Having said that, I
>> probably would have produced a finished result more quickly.
> 
> Faster results can often be achieved by using the appropriate building
> blocks.  You might be able to leverage John Wiegley's CAMBL for
> monetary calculations:
> http://github.com/jwiegley/ledger/tree/cambl-20080203
> 
> He also used it for a ledger application (a port of his C++ ledger):
> http://github.com/jwiegley/ledger/tree/cl-ledger-20080203

Thanks. Actually I was aware of cl-ledger. I used to use Microsoft Money 
(I know, boo hiss), which served my needs quite well, actually. I bought 
a Mac, so I no longer use Windows. I used Linux for quite some time on 
my Mac, but then I got OS X Leopard, and figured that Linux is too much 
like hard work.

It's always a bit of a dilemma - do I use what's already available, or 
do I roll my own? The first thing I tried was GnuCash. The problem is, 
it didn't produce the reports I wanted it to. It can be customised, but 
it's not easy. I saw one report that was about 800 lines of Guile.

I came to the conclusion that it'd be easier to hand-roll a solution in 
Python - which is what I did. The whole shebang came to about 1500 lines 
- although the count tend to go up and down depending on what features I 
decide to add or remove.

Becoming dissatisfied with what I had done (I was originally thinking of 
plopping a UI on top of it), I cast around for other solutions. I came 
across SQLedger, but the whole database deal seemed over the top for 
what I wanted. cl-ledger seemed interesting enough, but probably quite 
an investment in learning it to get it to do the particular things I had 
in mind.

I had thought of rewriting my app in Ruby, but after a series of ums and 
arrs, I decide to have another go at Lisp. So far, the application is at 
132 lines, and already does a fair bit. It doesn't yet do stuff like 
download share prices, keep them in a database, and other fancies; but 
it's surprising what you can accomplish with very little. I thoroughly 
expect it to be smaller than my Python program - although I put that 
down to the inelegance of my solution rather than problems with Python.
From: Pascal J. Bourguignon
Subject: Re: Forth/APL style in Lisp
Date: 
Message-ID: <873al4mssh.fsf@hubble.informatimago.com>
Mark Carter <··@privacy.net> writes:
> Now, I'm thinking if I had a stack-based approach, I could define it
> as something like
> 	(-account code) (-entries) (-describe)
> If you wanted to describe all the entries in all the accounts, then you'd do
> 	(-accounts) (-entries) (-describe)
> where the prefix of '-' denotes a convention that there is a global
> stack that is being twiddled with. And things like -account would work
> differently depending on whether the stack was a list of classes or
> just a class. It also looks really cool; there's no apparent looping
> construct, and it's very convenient and intuitive for the user.
>
> I'm wondering if anyone has adopted a similar or better approach, and
> what came of it.

http://groups.google.com/group/comp.lang.lisp/msg/6cbae7d520fc8c05


Now, the question is what problem would require the FORTH paradigm as
a solution?

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Until real software engineering is developed, the next best practice
is to develop with a dynamic system that has extreme late binding in
all aspects. The first system to really do this in an important way
is Lisp. -- Alan Kay