Tuesday 30 June 2020

(practical-python->racket approach)

Superficially, it seemed logical to start at the beginning. But upon reading the first few pages, it soon became clear to me that attempting to "translate" them requires a deeper knowledge of Racket than I have today. I thought it best to start with some easier material. So, I started with the introductory material about numbers, strings and lists that was easier to translate. I'll come back to the start later.

Each section of the course includes examples and exercises. My approach is to write a single Racket script which includes all the examples. (Is it even correct to refer to a short Racket program as a script?). I write a separate Racket program for each of the exercises. I'll write any notes I might have in this blog. I'll store the Racket programs in GitHub.

After a few false starts I managed to work out how to get the Racket that I've written to run in both Dr Racket and the Racket repl. I had written a few short Racket functions to reduce the amount of typing to complete the example scripts.

For example, instead of writing (displayln "Python: a = True") I can write (python "a = True"). It's basic text substitution. 

The function that I use to "expand" (racket value) is a little more sophisticated / complicated depending on you point of view.

(define-namespace-anchor anchor)
(define ns (namespace-anchor->namespace anchor))
(define (racket rkt)
  (cond
    [(list? rkt) (display "Racket: ")
                 (writeln rkt)
                 (eval rkt ns)]
    [(string? rkt) (displayln (string-append "Racket: " rkt))]
    [else          (displayln "Racket: Oops")])) 

The racket function will display its arguments and also evaluate the argument if it is a list. 

What took the time to figure this out was that you don't need to provide the namespace to the eval function when you run code in the repl unless you  specify #lang racket. It seems that Dr Racket insist on you specifying a language. So the code wouldn't run in Dr Racket.

I couldn't see a quick solution staring at me from the pages of the documentation. As I was really just performing text substitution, I thought I'd be better off writing a macro.

It took me number of attempts but I did eventually manage to get a macro to do pretty much the same thing. The issue that I came across was that I couldn't work out how to just expand the code with the macro and not evaluate it. So when I ran the script, all the macros were run before the rest of the code and the output was not in the order I wanted. (I guess I could have translated all my "expander" function to macros but I'll leave that for another time).

I went back to the docs and found that what I need to get my racket function working was to create and provide it a namespace. I first used make-base-namespace to create the namespace. I later found that I needed more modules than provided in racket/base to emulate the Python examples. Section 15.1 eval in The Racket Guide had a simple example of creating a namespace based on the "language" being used.

On to the first translation 1.3 Numbers.



No comments: