Welcome to the 20th issue of the Chicken Gazette. While the gazette was on hiatus the chicken community was definitely not. We are expecting a new release and lots of bugs have been addressed in the meantime.
Thanks for the recipe go to Alaric. Thanks to the Chicken Team for compiling this issue.
1. Hatching Farm
The following new extensions were added:
- canvas-draw: Bindings to the CanvasDraw graphics library (Thomas Chust)
- bindings: light-weight alternative to the matchable egg together with some enhancements (Felix Winkelmann)
- tuples: a tuple datatype implementation (Felix Winkelmann)
- svn-egg-author: makes it easier for people still using svn to tag/release eggs (Peter Bex)
- memcached: memcached client interface (Ivan Raikov)
- tree-rewrite: initial import of tree-rewrite, an adaptation of Oleg Kiselyov's term rewriting system PostL (Ivan Raikov)
- srfi-71 1.0: import some of srfi-71 (evhan)
The following new versions have been released:
- hen 0.5: Create tag 0.5 (joseph.gay)
- sequences 0.3: bugfixes; replicate (Felix Winkelmann)
- fastcgi 1.1.1: pointer->c-pointer fix; output strings can contain NULs (thanks to Peter Danenberg)
- contracts 0.4: some enhancements (Felix Winkelmann)
- sequences 0.4: performance tuning, some renaming (Felix Winkelmann)
- message-digest 2.3.5: reverted def alloc of ctx & no str use in u8vector restyp creation. (Kon Lovett)
- md5 2.5.1: Rel 2.5.1 w/ minor bug fix. (Kon Lovett)
- sha1 2.3.1: Fix correct context field clear (was not walking over memory since sufficient padding in struct, still it was wrong.) Rmvd ctx clear since unneeded. (Kon Lovett)
- spock 0.03: renamed some API procedures; bugfix in driver (thanks to Supermario) (Felix Winkelmann)
- amb 2.1.4: Wrong dep verno for condition-utils & check-errors in .meta. Missing import for srfi-1 member use in amb-extras [reported by Markus Klotzbuecher]. (Kon Lovett)
- mojo 0.0.1: first release (Moritz Heidkamp)
- sdl 0.5.3: new release (Christian Kellermann)
- tuples 0.2: tuples 0.2 (Felix Winkelmann)
- progress-indicators 0.3: added missing licensing information to meta file (thanks to mario) (Felix Winkelmann)
- spiffy-request-vars 0.13: test fixes (Mario Domenech Goulart)
- html-tags 0.10: added generate-sxml? parameter support (Mario Domenech Goulart)
- blas 3.0: Chicken 4 cleanup (Ivan Raikov)
- atlas-lapack 2.0: Chicken 4 cleanup (Ivan Raikov)
- probdist 1.7: updated use of blas and atlas-lapack (Ivan Raikov)
- hyde 0.15: simpler atom feed generation (Moritz Heidkamp)
- signal-diagram 1.1: added reduce combinator (Ivan Raikov)
- awful-sql-de-lite 0.4: See http://wiki.call-cc.org/egg/awful-sql-de-lite#version-04 for the latest changes. (Mario Domenech Goulart)
- awful-postgresql 0.4: See http://wiki.call-cc.org/egg/awful-postgresql#version-04 for the latest changes. (Mario Domenech Goulart)
- awful-sqlite3 0.4: See http://wiki.call-cc.org/egg/awful-sqlite3#version-04 for the latest changes. (Mario Domenech Goulart)
- awful 0.31: See http://wiki.call-cc.org/egg/awful#version-031 for the latest awful changes. (Mario Domenech Goulart)
- spock 0.04: removed explicit version number from setup script (reported to mario)
- spock 0.05: compiled code runs somewhat on IE; slightly more verbose setup-script (Felix Winkelmann)
- memcached 1.0: first release (Ivan Raikov)
- locale 0.6.11: check-locale-component for 'name had bad value ('name itself rather than value variable). with-tzset was leaving TZ set when no original TZ value. Proc for envvar LANGUAGE (gnu) was using code that deref'ed nonexisting 'language locale component; part of code to substitute primary locale region for possible nonexisting 'country in LANGUAGE locale, which can be subset - just language. (This caused the Error: (string-parse-start+end) bad argument type - not a string: #f from string-upcase.) (Kon Lovett)
- locale 0.6.12: Use 'current locale category for primary locale, rather than 'messages. locale-timezone has proc for offset & name. (Kon Lovett)
- matrix-utils 1.12: updated use of blas (Ivan Raikov)
- iexpr 1.2: fixed unit tests (Ivan Raikov)
- mpi 1.8: ported to Chicken 4 (Ivan Raikov)
- bloom-filter 1.1.4: Use of round -> ceiling (can't lose a bit). Added different way to calc M & K. Added variant signature for make-bloom-filter to take N & P. (Kon Lovett)
- ripemd 1.0.2: Added ident to digest prim. (Kon Lovett)
- setup-helper 1.3.1: Fix for trashing the .o when static+shared module setup. "static module" added. (Kon Lovett)
- slime 1.1: add swank:documentation-symbol (from Jean-Christophe Petkovich) and preliminary inspector implementation (Christian Kellermann)
- format 3.1.5: first release (Felix Winkelmann)
- neuromorpho 1.12: small fixes (Ivan Raikov)
- yelp 1.0.2: add note to tests about Yelp API key (ddp)
- format-compiler-base 17017.1: Replaces "use" of "extras" unit with "import", as the current implementation modified the imported binding to "format" and thus overwrote the toplevel binding. (Felix Winkelmann)
- embedded-test 17018.1: fixed long open bug and tagged 17018.1 (Felix Winkelmann)
- ssax 5.0.4: added export for ssax:warn and tagged 5.0.4 (Felix Winkelmann)
- rpc 1.1.2: removed use of project procedure (Felix Winkelmann)
- flsim 1.4: fixes related to Octave code generation (Ivan Raikov)
- opengl 1.19: opengl 1.19: properly link -lGLU (thanks to Moritz Heidkamp) (Felix Winkelmann)
- iset 1.8: fix typo in optimization option (Felix Winkelmann)
- hen 0.6: various fixes and additions (Joseph Gay)
2. Chicken Talk
Chicken 4.7 is about to be released. The development team is performing some final tests to check if some critical bug shows up before the release. If you want to help testing the code which is going to be the next Chicken version, get the latest development snapshot and give it a try.
A Chicken-based commercial application has been added to the Software wiki page. According to the description, AuScio ''is simple cross-platform metal price monitor combining the qt-light, tcp and srfi-18 multi-threading eggs. The application is deployed as a native executable with Chicken's compiler''.
Evan Hanson reported a Chicken sighting in the Computer Music Journal's DVD.
Thanks go also to John Cowan who brought the Chicken Dance License as a possible new license to our attention :)
Matt Welland announced a new version of chicken-iup here. Also note that the download link has changed since the last Gazette.
YC started a discussion about a Generic RDBMS Interface, where lots of people envisioned an easy to use glue to access RDBMS. The participants argued over the use of URL encoded queries vs. other more lispy forms. Thomas Chust developed a prototype and is looking for feedback. Thanks!
John Magolske shows us a nice trick to use csi within Vim to evaluate visually selected text. He also ran into issues when installing chicken eggs in a nonstandard location w/o hard coding in these paths during compilation. Thanks to the helpful people on chicken-users he could solve his issue.
Matt Welland asks for a way to produce a notification sound in a cross platform way in this mail but until now we don't have a good answer for this yet. Maybe you can help? Matt is also still waiting for an answer to a problem with srfi-19 under windows.
Felix announced the release of the hopefully latest development snapshot before the next major release. Please test 4.6.7 as hard as you can.
John J Foerch asked for a spiffy feature: remote-address should also take the X-Forwarded-For header into account when generating an address. Peter Bex kindly implemented it.
Alex Shinn announced the R7RS draft which we all waited for. Thanks to the scheme-report group!
Steve Graham asked about the possibility of writing android apps in chicken. Moritz Heidkamp promised to write a gazette recipe about it "in the near future".
William Xu asked about a way to upgrade all installed eggs. Felix added a '-reinstall' option to chicken-install which you are invited to test.
Thanks to Alan Post, Mario Goulart has been able to fix the links to the tests.call-cc.org egg feeds.
3. Omelette Recipes
The dream of many Schemers is to write Scheme for a living. Due to the regrettable tendency of employers to frown upon good ideas, the best way to achieve this is to start your own company, so you can be your own boss, and frown upon the good ideas of others instead.
However, running your own company comes at a price; and a big part of that price is the horror of "book keeping"; the requirement to track all flows of money and other, more abstract, forms of value in and out of your company.
Some people will tell you book-keeping is simple. "Just keep all your receipts and bank statements and bills and invoices", they say. "Then send them to your accountant at the end of the year."
"But what about value-added tax?", you ask (or "sales tax" in some countries). "And what about income tax paid at source for my employees (including myself)?". "And why do I need to pay an accountant so much to do a job that a computer can easily do in milliseconds?" And then the smug smile slowly drips from the face of the "Oh it's easy" crowd.
Clearly, book-keeping is complicated. And yet also simple, in that it is determined by sets of rules.
We know what to do, don't we? Let's get coding!
The problem is that book-keeping involves several different kinds of inputs - bills (that people send you), invoices (that you send people), transfers of money (bills and invoices being paid), loans (to and from the company), employees being paid, interest payments from the bank, dividend payments, and so on; while it also involves several different outputs - tax reports for the various taxes involved (in the UK, I had to deal with VAT every three months, income tax and national insurance when paying myself and my wife as employees every month, an annual filing fee, and annual corporation tax and dividend payments), statutory filing of certain financial summaries (generally annually), and internal reporting: How much was I spending? How much did each client owe? How much should be in the bank by when? Plus, it's nice to be able to generate nice invoices to send to folks who owe you money. That's a form of specialised report, too, just reporting on a single invoice.
Each of the output reports depend in complex ways on different information from the inputs. The VAT reports mainly have to add up how much VAT I've paid when being billed by others, and how much VAT I've charged when invoicing - meaning that VAT needs to be tracked on all bills and invoices so it can be extracted. They also want to know totals of actual money in and out of the company in the period (even stuff where VAT isn't an issue), presumably to check up on me. Meanwhile, end of year reports tend to need to know how much I've invoiced for various different kinds of work, and what I've spent on what kinds of things: buying equipment that will last me for several years is handled differently to expenses like travel, or buying stuff that I eventually resell to clients (so in our invoices, we need to keep track of money charged for services separately to money charged for things).
Some reports care about virtual money moving hands. As soon as I invoice somebody, then the company now has a virtual asset - some money owed to it. That's worth as much as cash in the bank from some perspectives (generally, I have to pay tax on it as soon as it's invoiced, even if I've not been paid). And yet some care only about actual cash changing hands (working out my bank balance, for instance).
Sometimes our clients invite us to incur expenses in doing work for them (such as extra travel) and then invoice them on for those expenses, so they pay us back - in which case, expenses need to be able to be tied to invoices, as well. Sometimes we decide to cancel an invoice, which can't be done by just pretending it never existed, for audit-trail reasons; we need to issue a "negative" invoice called a credit note.
Just to complicate matters more, the actual movement of money isn't atomic. If I invoice somebody on date A, they might post me a cheque which arrives on date B, which I pay into the bank on date C, which actually clears into the account (and thereby appears on my bank statement, when I get it) on date D. So at date A the company now has a "we are owed" pretend-money asset, which goes through various stages until it finally turns into money in the bank on date D.
I handled my book-keeping with some hacky scripts written in Chicken Scheme. What I'm going to document here is partly what I've done, and partly what I should have done - it was a very iterative process, refining the best way to handle stuff, and there's lots of improvements I've wanted to make but not had time to. So I'm going to describe the ideal case, not the hacky half-way house I actually have right now!
The approach I took was to have a file called a "ledger" that I enter all my invoices and so on into. This is parsed to build up a bunch of data structures in memory, from which the various reports can easily be obtained. Firstly, for each kind of input object (invoices, bills, etc) there's a list of them, or more often a hashmap to make them easy to find by some identifier (I can give my invoices unique symbolic names, for instance). That contains the raw data as parsed from the ledger file. But then we also create summary structures, which are used by the more general reports to generate their output without having to special-case each and every different input object type, and to enable sharing of common functionality between reports.
The main summary structure is the double-entry transaction list, which models the entire financial activity of the company as transfers between accounts.
Imagine I invoice Widget Corp for setting up and installing a router:
INVOICE INV005: Issued 2011-04-25 Router setup and installation: GBP 800 1 router from my stock: GBP 350 1 train ticket for me to go to their site: GBP 35 (no VAT due) Subtotal: GBP 1,185 VAT on the above: GBP 230 Total due: GBP 1,415
As part of the work, I lose a router (worth GBP 350) from my stock, and have to spend GBP 35 on a train fare.
This might expand into the following transactions:
* 2011-03-02: "Expense for Widget Corp (INV005)" * expenses.travel +35 "Travel to site" * cash -35
* 2011-04-25 "Invoice Widget Corp (INV005)" * income.work -800 (Router set up and installation) * stock.balances -350 (1 of LX300 router, serial number 0343248) * clients.widgetcorp.expenses -35 (Travel 2011-03-02) * taxes.vat -230 * clients.widgetcorp.balance +1415
And, eventually, they might pay me, which hits my bank account some time later:
* 2011-05-07 "Payment from Widget Corp (INV005)" * clients.widgetcorp.balance -1415 * bank.balance +1415
And then one day I'll pay my VAT bill, which will look something like:
* 2011-06-01 "VAT payment for period from 2011-03-01 to 2011-06-01" * taxes.vat 230 * bank.balance -230
Note a few tricky things. Each transaction's "splits", as the lines within them are known, have to sum to zero for everything to balance correctly, which tells us that nothing has gone missing. So when we start being owed GBP 1,415 by Widget Corp, we need to account for where that asset has come from. Special accounts with names such as "income.work" (for value generated by me working) and "clients.widgetcorp.expenses" (for previously-paid expenses that, as of this invoice, I can charge the client for) pop into existence. "taxes.vat" looks as if VAT is a form of income for me, as money comes "from" it in the transaction - which is sort of true; I'm charging Widget Corp for some VAT alongside for the actual work done. Figuring out what signs to put on all the items in the invoice is mind-bending and painful, but if you just concentrate on making it all add up to zero in the end and starting from things that are obvious (is money going into or out of the bank account, or the "owed to me by this customer" account?), you can figure it out.
From the above, we can start to flesh out some data structures:
(define-record txn date customer code description splits) (define-record txn-split account amount notes) (define *txns* (make-hash-table)) (define (register-txn! txn) (if (hash-table-exists? *txns* (txn-date txn)) (begin (set! (hash-table-ref *txns* (txn-date txn)) (cons txn (hash-table-ref *txns* (txn-date txn))))) (begin (set! (hash-table-ref *txns* (txn-date txn)) (list txn)))))
What is an "account"? There's a few kinds, and what kind of account it is matters in reporting. Accounts might be assets within the company - such as "clients.widgetcorp.balance" or "bank.balance" or "stock.balance". Or they may be places where money (be it real or virtual) is created from or destroyed by (from the perspective of the company), such as "income.work" and "expenses.travel". The important difference is that balance-type accounts have a balance that is increased when money is sent to them and decreased when it's taken out, and that balance is part of the value of the company, while the income/expense type accounts don't. In my terminology, these are "balance" accounts and "delta" accounts. Each account also begins to a group, used to aggregate them in reports: there's income accounts, bank accounts, client accounts, and so on. And accounts may be tied to a third party - I've given an example of a client above, but also, the organisations that send me bills have balances (the money I owe them). In general, every third party (be they ones that bill me, or ones that I invoice, or both - I've interacted with other freelancers, sometimes working for them, sometimes vice versa) has a set of accounts attached to them for their balance, expenses I can claim from them, and so on. That implies another set of record types:
(define-record third-party name address balance-account expenses-account) (define-record account name type group third-party) (define *third-parties* (make-hash-table)) (define *accounts* (make-hash-table)) (define (find-account acct-name) (hash-table-ref *accounts* acct-name)) (define (register-account! acct) (set! (hash-table-ref *accounts* (account-name acct)) acct))
An account's third-party slot may be #f if it's not part of a third party.
Accounts are the organisational structure that turns a sea of financial events into something we can start to make sense of. In the next thrilling installment, we will look at actually entering transactions, and turning them into a data structure from which useful reports can be produced...
4. About the Chicken Gazette
The Gazette is produced occasionally by a volunteer from the Chicken community. The latest issue can be found at http://gazette.call-cc.org or you can follow it in your feed reader at http://gazette.call-cc.org/feed.atom. If you'd like to write an issue, consult the wiki for the schedule and instructions!