As promised in the last post, I am going to share an infix function, that takes a list that looks like (1 + (2 * 3)) and turns it into (+ 1 (* 2 3)) (Prefix).

Creating this function was a perfect place to start playing with Unit Testing as well. Something that I have not used much of until now.

Unit testing is really useful in this situation. We can write a tiny test that checks if our infix/lr (lr because it parses left to right, not that it matters) function gives the appropriate result. That test will look like this:

; Load the lightweight unit testing unit
(use srfi-78)

; And write the test
(check (infix/lr '(1 + (2 * 3) + 4)) ; Check that this
       =>                            ; matches
       '(+ (+ 1 (* 2 3)) 4))         ; this

If all goes well, once the function is written the test should pass.

Here's the complete function itself:

; Parses an infix list into a prefix list
(define (infix/lr lst)
  (when (even? (length lst))
    (error "Wrong number of arguments to infix operator"))
  (let loop ((n (first lst))
             (lst (cdr lst)))
    (if (not (null? lst))
        (loop (list (first lst) n
                    (if (list? (second lst))
                        (infix/lr (second lst))
                      (second lst)))
              (drop lst 2))
      n)))

I firmly believe this can be written to look (and probably function) better than it currently is (*Edit: Using regular let instead of letrec now*), but I'm still learning. Notice I also check the number of arguments; if it is an even number this means we will be missing a value at the end, since obviously we need 3 items to perform the swap (two values and an operator).

So that is the function part taken care of, and this should be perfectly usable as is, but we can take this a step further by binding it to a read macro. This part is really up to you, here's how I do it:

And now we have an infix macro that can be used for easy calculations!

One word of warning though, this function does not take into account operator precedence (to keep it simple) and so you are required to use parentheses to enforce precedence.

And of course because we're simply swapping lists around, it is perfectly possible to infix any scheme function that takes two arguments.

Enjoy! :)


(Maybe) Related posts: