Hacker News new | ask | show | jobs
by karmakaze 840 days ago
It would be helpful if the Features were separated by language vs library. I don't know what to make of

  No memory side effects, all collections are persistent.
This can't be relevant when the objects referenced by these collections are mutable.
1 comments

> separated by language vs library

You're totally new to Lisp, right? There is no such clear boundary in Lisp languages.

> This can't be relevant when the objects referenced by these collections are mutable.

Why not? Explain your reasoning. E.g. why is not not relevant that we can make a longer list by adding an element to the front of a shorter list, without mutating that shorter list, if the elements are objects that support mutation?

How so? Tail-call optimization would be a language feature. The math/graph operations in a lib/module etc.

An example would be if presence in a collection is dependent on mutable properties of its entries.

> Tail-call optimization would be a language feature.

Most lisps generally do it this way (except maybe emacs lisp?), but there's not really a requirement for it to be a language feature. TCO is really just AST manipulation, and lisp macros are more than capable of that, although you might want to hook into the reader as well if Kamila supports it (I didn't see anything about that in the github readme).

> TCO is really just AST manipulation

While it is true that tail call relationships can always be represented using goto, it requires that all related code is known to make this conversion. For instance:

  (defun f (x) (a x) (g x))
  (defun g (x) (b x) (h x))
  (defun h (x) (c x) (f x))
You cannot remove the tail call by altering the AST of F, G, or H. Instead, a third function must be instroduced that contains the bodies of all functions in the loop.

  (defun fgh-loop (start-at x)
    (tagbody
     (case start-at
           ((f) (go f))
           ((g) (go g))
           ((h) (go h)))
       f (a x) (go g)
       g (b x) (go h)
       h (c x) (go f)))
  (defun f (x) (fgh-loop 'f x))
  (defun g (x) (fgh-loop 'g x))
  (defun h (x) (fgh-loop 'h x))
You can only apply such optimisations in retrospect, but a macro would only have access to the body of F at the point of definition for F. And even then, you cannot TCO any lambdas that are passed around. A simple example is the Y combinator:

  ((lambda (x) (x x)) (lambda (x) (x x)))
> You can only apply such optimisations in retrospect, but a macro would only have access to the body of F at the point of definition for F.

There's no actual reason for this, you can get the symbol tree for the functions in question, assuming the runtime allows this (several do), and re-compile them and blow over the old definitions. You can only apply the optimization once all of f, g, and h are defined, there's no rule saying that a macro can only modify the function being defined, or that other functions can't be defined (the CLOS would be impossible if that were the case).

Both this and the lambda example should be doable with function-lambda-expression, although it's not exactly standardized. It should be possible in principal with the right implementation.

> It should be possible in principal with the right implementation

Most implementations that do this also support TCO, and I think the process itself goes a little beyond AST manipulation. It's basically just manually combining the entire program into one function to get a version of unconstrained goto. It isn't a macro in the traditional lisp-sense of the word, more of a compiler for a new programming language that uses lisp as a host. Practically speaking, it doesn't have many of the properties that are important in macros. It is not defined in a composable way, and it needs deep integration with the language runtime. Tor instance to handle definitions that mutually recur between different packages, it would need to be installed globally in the implementation rather than locally in a given package. So if two packages tried to use different recursion macros, they would likely be incompatible. While it could hypothetically be implemented on top of another lisp, it is really only possible to do so properly as a language feature.

cons is a graph operation and + is a math operation. Go on ...