Archive for February, 2008

Modules

I noticed there's a new version of Arc. According to the web page, "The most dramatic change is probably the ability to use x.y and x!y as abbreviations for (x y) and (x 'y) respectively."

The x.y syntax reminds me of one of the things I miss in Scheme: a "Pythonic" module system. By "Pythonic" I mean, that you can import modules, and get a module object back, that you can access using x.y syntax. I'm mostly interesting in the namespace issue here, as the convention in Scheme seems to be, to just stick everything in the global namespace.

In other words, I am somewhat uncomfortable that it's not possible to do this:

;; --- foo.scm ---

(define (bar x)
  (+ x 1))

;; --- REPL ---

> (import foo)
> foo
#<module foo>
> (foo.bar 3)
4
> foo.bar
#<procedure (foo.bar x)>

...or something to that effect.

Maybe this is an irrational "need", but I like namespaces, and have gotten used to them over the years, and loading the toplevel namespace with lots and lots of definitions just seems a bit "unsafe" to me.

I found a comparison of Python's and PLT Scheme's module systems, which explains the issue better:

Once we've done '(require (lib "math.ss"))', we have access to the internals of the math library. But there's one surprise: unlike Python, 'math' itself is not a first-class object. By default, the require form has the same semantics as Python's "from [module] import *"!

The article then mentions the following technique to add a prefix to the names imported from a module:

> (require (prefix math. (lib "math.ss" "mzlib")))
> math.e
2.718281828459045

I suppose this would not be too bad as an alternative, although you still cannot do things like inspecting a module, pass it around, etc. Chicken does not seem to support it though, and Schemers generally don't seem to miss the feature. (Or maybe there's a reason why it would be a bad idea in Scheme.) So maybe I should just learn to live without it. Thoughts welcome...

:: Comments (4)

Representin'

852-01.gif

855-01.gif

(Yeah I know, nobody cares about "speed skating" outside of the Netherlands. But still... :-)

:: Comments

SRE regular expression syntax

Looking for eggs that handle regular expressions, I found scsh-regexp. It implements most of the regexp API, as described in "Proposed SRE regular-expression notation".

Now, I'm not particularly interested in the API, as Chicken already supports regular expressions out of the box (see the regex unit). What I find much more interesting is the part of the proposal that *isn't* implemented. It also defines a syntax for describing regular expressions. This part isn't available in the egg; according to scsh-regexp's documentation, it was only implemented in SCSH.

Many questions arise. Why wasn't this implemented elsewhere? Would it be useful (i.e. compared to usual regex notation)? Would it be hard to port to Chicken? Would it be hard to write from scratch, going by the documentation only?

Most likely, I'm not up to the task, but that doesn't stop me from dreaming about things like a sed-like stream editor using this kind of syntax for regular expressions. It would be super verbose, but also more readable... at least, that is the assumption.

:: Comments (3)

Making s1 code shorter

More efforts to make s1 code shorter...

I added/changed the following:

  • slice function (this will come in handy for string manipulation, although (slice s a b) is still longer than s[a:b]
  • nf variable (indicates the number of fields in a line)
  • $ now accepts any expression, not just a number literal (so we can say $nf or $(- x 1) or whatever)
  • -f command line option to quickly set the field separator
  • created an alias s1 for 'csi -ss /path/to/s1.scm' (OK, this is not a change to the tool proper, but it helps... nobody wants to type csi -ss with the full path, all the time)

None of this is particularly original (as it's all borrowed from Awk and Python), but it does help to make code much shorter. I can now write a one-liner like this:

find "${1-.}" -type d | s1 -f/ '(print "   |" (make-string nf #\-) $nf)'

...which produces almost the same tree as described here. Almost, because it uses one "-" for each directory rather than two. We can fix that by making the example somewhat longer (and less readable to non-Schemers, although admittedly the Awk example isn't very readable to non-Awkers either):

find "${1-.}" -type d | s1 -f/ '(print "   |" (make-string (* (- nf 1) 2) #\-) $nf)'

Next up: regular expressions...

:: Comments

I can has scripting?

Brainstorming a bit here...

So I saw this cool one-liner script. It displays a directory tree:

ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/   /' -e 's/-/|/'

I have been hacking (on and off) on an Awk-like tool that uses Chicken for scripting. Its working title is s1, and so far it supports begin/main/end blocks like Awk, and $N-notation for quick access to fields.

The real problem is not, adding Awk-like functionality as Scheme functions, but rather, making the Scheme concise enough that it can be used for one-liners. For example, the following works, but is still too verbose:

ls -l | csi -ss s1.scm '(before (set! total 0)) (set! total (+ total (as-number $5))) (after (print total))'

(It shows the total size of files in the current directory, in case it wasn't obvious. :-)

It gets even worse when we try to emulate the ls/grep/sed script mentioned above. Writing this as a one-line just isn't feasible at this point; rather, I have to use a script:

;; tree.s1
;; Call with: ls -aR | csi -ss s1.scm -s tree.s1

(define (branch parts)
  (let* ((parts (reverse parts))
         (dirname (string-trim-right (first parts) #\:))
         (line (apply conc (map (lambda (s) "--") (cdr parts)))))
    (conc "|" line dirname)))

(when (string-suffix? ":" $0)
  (let* ((parts (string-split $0 "/")))
    (print "   " (branch parts))))

Much of the work goes into processing strings and lists, but even without that the code probably still would not fit on one line.

Granted, it's hard to beat the conciseness of regular expressions (as used by grep and sed), but if I want s1 to be useful, it needs to support (much) shorter code. (Maybe I should rewrite it in Arc? ;-)

Here are some thoughts about making this shorter:

1. I dearly miss slicing. In Python, I would have used s[:-1] to chop off the trailing colon. Adding a slice function to the toolbox would probably be useful.

2. I could leverage some of the Awk-like features. This Reddit comment does just that:

find "${1-.}" -type d | awk -F/ '{printf "  |%*s%s\n",(NF-1)*2,"",$NF}'

It takes advantage of the following features:

  • using "/" as a field separator (effectively splitting the path with no extra code)
  • using NF (indicating the number of fields in a line) to compute the indentation level
  • using $NF to display the last field (i.e. the directory name we want to see)

As it happens, s1 can do all these things as well, but it won't be quite as concise. This is something to work on. Maybe there could be a special variable (or symbol) that translates to (length *fields*). I would have to hack the current $-literal to accept any expression, not just a number literal.

The tricky part is to make things concise while still keeping the spirit of Scheme. :-/ s1 will never automagically coerce numbers to strings (or vice versa), for example. I can, however, make it easy to convert them explicitly. (This is also the Pythoneer in me speaking... explicit is better than implicit, and all that good stuff.)

Anyway, there was really no point to this post, except letting the world know that I am tinkering with a new toy. :-) If it ever actually becomes useful, I'll release it... Until then, I might talk more about it here.

:: Comments (3)

Chicken / SDL

Well, I managed to build SDL (and a number of related libraries) on Mac OS X... it was a bit of work, but eventually everything compiled. This page was a great help. (It's aimed at Ruby users, but most of it still applies.)

I also built and installed the sdl egg. So far, so good.

The next question is: what do I do with it? :-) I've never used SDL before, and the official docs and tutorials all use C, which is different enough that I don't know how to use it from Chicken.

If anybody has tips, or better yet, some simple example code to get me started, that would be very welcome. ^_^

:: Comments

4us

This is quite an interesting read: Virology 101 (gzipped postscript; via). In it, Doug McIlroy describes how to write a simple "virus", in Unix shell script.

Back in the MS-DOS days, I thought of viruses as "viral code, usually written in assembly, that attaches to executables", and while there were many viruses of that kind in that time, the definition is much too narrow. All a program needs to do to qualify as a virus, is:

1. do something.
2. replicate.

In fact, it doesn't even need to "do anything"; replication is enough. And it doesn't take very complex code to accomplish this, as demonstrated by the simple scripts in the paper. Nor does it require an "unsafe" system like Windows (although it helps in case the virus writer intends to do a lot of damage :-).

(No, I'm not going to try and write one in Scheme...)

:: Comments

(Slightly more than) A month of Chicken

So, I've been learning (Chicken) Scheme for over a month now. Let's look back.

  • I'm currently hacking on two projects in Chicken; one is a translation of an existing Python program, the other is something written from scratch. Neither will be very large. If they become somewhat useful/usable, I will probably make them available.
  • I'm using vim, but looking for an editor that gets along better with Scheme (in terms of autoindent etc... I don't like scheme.vim too much). Of course Emacs would be an obvious candidate, but I'm reluctant because of several reasons. (Less than stellar OS X support, unwillingness to learn many new keybindings and/or beat the editor into doing what I want, unwillingness to learn elisp at this point.)
  • Even though succinctness is power, so far my Scheme code is almost twice as long as equivalent Python code. 1) I'm not yet drawing any conclusions based on this; there are many possible explanations, like the fact that I am still learning and therefore tend to use more verbose code (for clarity, or simply because I don't know a shorter idiom), while my Python code does not suffer from the same problem. So, we'll just have to see if this changes over time.
  • On the other hand, my Scheme code seems to be cleaner than the Python I had. Scheme really encourages rigorously splitting up code into smaller functions. (This is probably true for most, if not all, functional languages, by the way.)
  • Chicken has been a joy to program in. It has a lot of useful functions out of the box. I do find that you don't get very far if you only have vague ideas about what your code should do. :-) Functional languages seem to have this feature (?) more than, for example, Python or Ruby.
  • I am impressed with the availability of Chicken libraries (eggs) so far. Granted, I haven't needed very complex stuff so far (testing framework, command line argument parsing, etc), but what I did need was there, often in several flavors. Installation is stupid easy too.

When my initial projects are done, I plan to look at stuff that is a little more "real world", like game development (using SDL?), OS X hacking, maybe web programming. (I also would like to contribute an egg at some point -- but I need to write useful code first! :-)

1) I'm just looking at file sizes here. Maybe I'll do a more meaningful comparison later, when I have more code to compare.

:: Comments (1)

Next entries »