How to work with immutability

clojure

#1

I’m trying to write a simple Lisp interpreter as described here: http://norvig.com/lispy.html
The series of transformation described there are something like:

"(+ 1 ( * 2 2))" ->
['(', '+', '1', '(', '*', '2', '2', ')', ')'] ->
['+', '1', [' *', '2' , '2']]

I could transform from step 1 to 2.

For the transformation from 2 to 3, here’s the Python code described on the blog:

def read_from_tokens(tokens: list) -> Exp:
    "Read an expression from a sequence of tokens."
    if len(tokens) == 0:
        raise SyntaxError('unexpected EOF')
    token = tokens.pop(0)
    if token == '(':
        L = []
        while tokens[0] != ')':
            L.append(read_from_tokens(tokens))
        tokens.pop(0) # pop off ')'
        return L
    elif token == ')':
        raise SyntaxError('unexpected )')
    else:
        return atom(token)

I’m finding it difficult to do similar transformation in Clojure without mutating the resulting list L and tokens. How to go about such cases, what is the idiomatic Clojure way.

Progress till now: https://github.com/anuragpeshne/elisp-evaluator/blob/master/src/elisp_evaluator/parser.clj#L11
Any reviews about the code is welcome.


#2

Try to use recursion.


#3

For code like:

a = 0
while a < 10
  a = a + 1
console.log a

A tail recursion is capable of simulating the a changing a by creating a new function scope with a new a:

increase10 = (a) ->
  if a < 10
    increase (a + 1)
  else
    a

console.log (increase10 0)

#4

Thanks @jiyinyiyong and @didibus I ended up using loop and recur and kept an accumulator as a parameter.
Here’s my solution for reference: https://github.com/anuragpeshne/elisp-evaluator/blob/master/src/elisp_evaluator/parser.clj#L32