2011-02-22

Experiments with Racket

In the last weeks I have played with Racket (formerly PLT Scheme), a powerful language derived from Scheme. Here I describe a couple of problems I solved using Racket, in order to underline the difference between this language and Python.

First, let me say that I am really impressed by the quality of the implementation of Racket. It is fast (apart from the execution times for the GUI), it has a huge set of libraries, it is easy to use and it has a number of nice facilities.

Project Euler again!

The first script I wrote was to solve one of the easiest problems proposed in the Project Euler site, that is problem 15. This kind of problem can be solved using a divide-and-conquer algorithm, so here comes my first attempt:

(define (num-of-solutions width height)
  (+ (if (> width 1)
         (num-of-solutions (sub1 width) height)
         1)
     (if (> height 1)
         (num-of-solutions width (sub1 height))
         1)))

Such solution relies on the fact that at any point in the grid one can only move left or down (provided that there is room to move in that direction), and that once you make a move you are trying to solve the same problem for a rectangular grid with a smaller size.

This solution however has a problem: when running num-of-solutions on a 20x20 grid, the function takes forever to evaluate. The problem lies in the fact that each non-trivial call to num-of-solutions spawns two recursive calls to itself, so that the number of calls grows quickly.

There is a simple solution: since many of the calls share the same parameters (and hence return the same number), we can use a technique called memoization: when calling num-of-solutions with some parameters for width and height, save the return value in a table so that subsequent calls to the function with the same parameter will simply look up the table instead of re-running the function. (See SICP for an example applied to the calculation of Fibonacci's numbers, a problem stunningly similar to the one we are solving here.)

In order to memoize num-of-solution I might have relied on standard techniques available for the Scheme language, but I instead had a look in the excellent Racket documentation and in PLaneT (the collection of separate packages available for Racket). In a few seconds I found the memoize package, which does exactly what I wanted: just changing define into define/memo will make num-of-solution orders of magnitude faster:

(require (planet dherman/memoize:3:1))

(define/memo (num-of-solutions width height)
  (+ (if (> width 1)
         (num-of-solutions (sub1 width) height)
         1)
     (if (> height 1)
         (num-of-solutions width (sub1 height))
         1)))

(num-of-solutions 20 20)

And here comes a nice touch. I did not know how to install this additional package in Racket, so I wrote the example above in the IDE and compiled it, hoping that any error message would help me to understand what to do. Guess what? The IDE automatically connected to PLanetT, downloaded and installed the package and continued the execution: in a few seconds I had the answer! (Compare this with Python: it is like if any time you import some library not available the interpreter downloads and installs it automatically. How nice!)

A more complex example

The second program I wrote was considerably longer. I had a problem with a TWiki site I am administering: every user would attach huge PDF files to wiki pages instead of properly using a separate site (I shall not bother you with details about how this site works: let just assume it is a FTP site). This caused any backup of the TWiki site to be quite huge, so I decided to fix this by manually moving the biggest PDF files to the FTP site and then change each link to the new place. As there are potentially thousands of links to fix, this clearly required an automated solution. And here comes Racket.

My plan was to download each page containing huge attachments in a text file, search for the TWiki markup signalling a link to any file already moved to the FTP site and modify the link properly. The caveats for such task are:

  1. I am not going to move all the files, just the biggest ones. So the program should be smart enough to decide which links to change and which not.
  2. So far I have considered the remote site as a FTP site, but this is not really the case. Specifically, to get a file from there the URL must contain the file name and a unique integer ID. So links to this site cannot be created automatically, they must be specified one by one. An example might be http:/foo/bar/filename.pdf?node=1234. Thankfully the file name is always present!

The program I created relies heavily on Racket's regular expressions, an addition of Racket over the Scheme language (note that regexps are native in Racket – like Ruby but unlike Python, which requires you to use import re at the beginning of your script). It takes two input files: the first one contains the wiki page, the second one contains a list of links to the remote site. The code extracts bare file names from the links and produces an associative list (similar to dictionaries in Python), which then uses to fix links in the wiki page.

The most difficult thing for me was to think how to implement iterations using recursion instead of for loops (and such code has a lot of iterations: looping over links, looping over markups…): however, I am willing to master this technique as the use of recursion is common in functional languages.

So far the code has worked like a charm. I have not benchmarked it, but it works so fast that execution times are negligible (of course I created a compiled executable in order not to start Racket every time I need to use it).

9 comments:

  1. Very interesting, I've checked also the introductory tutorial to racket, functional programming is really fascinating.
    I have a curiosity, does racket have a module for manipulating arrays? Might it be used for data analysis?

    ReplyDelete
  2. Hi Andrea, the PLaneT website shows a list of ll the available packages for PLaneT, if you look at the section "Mathematical & Scientific" you will find something.

    But I dare say there is nothing comparable with GNU R or NumPy (at the moment), as the GSL bindings are very embrional and the plt-linalg package only implements a few bindings from BLAS.

    IMHO the main strength of Scheme/Racket lies in the easiness of testing complex algorithms (i.e. more complex than a simple "for" loop), rather than doing conceptually straightforward number crunching (like e.g. doing a weighted linear fit).

    ReplyDelete
  3. I’m usually to blogging and site-building and i really adore your articles.

    Microsoft Office 365

    ReplyDelete
  4. This is really interesting, You are a very skilled blogger.

    I have joined your rss feed and look forward to seeking
    more of your magnificent post. Also, I’ve shared your site in my social networks!
    microsoft office 2007 keys
    IDM
    Easeus Data Recovery
    Windows 7 activator
    4k video downloader
    Microsoft office 365
    Windows 10 activator
    xforce keygen

    ReplyDelete
  5. The FDA believes that organized criminal networks control many on-line pharmacies that
    promote illegal pharmaceutical products with out prescriptions.reloader activator
    avg driver updater
    driver booster
    Revo Uninstaller

    ReplyDelete
  6. I am sure this post has touched all the internet viewers,
    its really really fastidious piece of writing on building up new
    website.mixed in key
    push video wallpaper
    3d lut creator
    IDM
    grids for Instagram

    ReplyDelete
  7. You made some good points there. I checked on the
    internet for additional information about the issue and found most individuals will go
    along with your views on this web site.mixed in key
    push video wallpaper
    3d lut creator
    IDM
    grids for Instagram
    4K YouTube To MP3
    Express VPN
    HD tune pro
    utorrent pro
    Adguard premium

    ReplyDelete
  8. La maternità surrogata è una grandissima svolta nella medicina riproduttiva che permette alle coppie con problemi di fertilità avere il loro figlio biologico.
    Per la maggior parte delle famiglie sterili la maternità surrogata attualmente è una smisurata opportunità di sperimentare la felicità di essere genitori.
    maternità surrogata ucraina

    ReplyDelete