Arc Forumnew | comments | leaders | submit | almkglor's commentslogin

When someone evil doesn't use safeset:

  (= +
    (fn args
      "I am EVIL!!"))
Hmm. Maybe put the hook in 'set instead?

Also, not sure, but how about when it's given an already-compiled-but-not-optimized function?

  (= foo (fn args "I am EVIL!!"))
  (= + foo)
Not sure about how arco is structured anyway ^^;

-----

1 point by eds 6449 days ago | link

I chose 'safeset only because that is what is used internally in 'def. But I see that you would need to watch 'set to be completely sure no redefinitions had occurred.

So if you put a hook in 'set, and watched for local variables (really function parameters, because 'let is implemented in terms of 'fn) overriding function names, that would probably be enough to know a function hadn't changed. And that would hopefully remove the need for CL style type declarations.

Maybe this should be added as an option to the poll?

-----

1 point by almkglor 6449 days ago | link

In fact, yes you really have to watch for locals either way - it's entirely possible to do this (I have, since I wanted to package Arki in a module-like object):

  (let (localfn localfn2
        help* sig source-file*) nil
    ; protect 'def from bashing Anarki help docstrings
    (= help* (table) sig (table) source-file* (table))
    (def localfn ()
      (prn "localfn!"))
    (def localfn2 ()
      (prn "!2nflacol"))
    (def globalfn ()
      (localfn) (localfn2)
      (prn "haha only global!")))

-----

1 point by eds 6448 days ago | link

Is that multi-variable form of 'let an Anarki thing? I don't remember seeing it before. It does look really cool though.

-----

1 point by almkglor 6448 days ago | link

It's part of the Arc core destructuring thing. For example:

  (let (x y z) (list 1)
    (prn x)
    (prn y)
    (prn z))
...will assign 1 to x, and nils to y and z. Basically it seems that destructuring is done in the following manner:

  (let gs4932 (list 1)
    (let x (car gs4932)
      (let y (car:cdr gs4932)
        (let z (car:cdr:cdr gs4932)
          (body ...)))))
(NOTE: not exact code, but basically this is how ac.scm handles destructuring)

-----

1 point by almkglor 6449 days ago | link | parent | on: CL-Arc: Arc Compiler in Common Lisp

s/CL/brainfuck/

^^ Okay, okay, hahaha j/k.

How about porting the Anarki-specific extensions to the language?

1. defcall

2. FFI - probably take the longest

3. settable-fn (make it builtin, the Anarki version actually drops down to Scheme using $ for this).

And some things that Arc base lacks which is hard to hack around the scheme implementation for:

1. Error reporting. With LINE NUMBERS. And the ability to give macros access to the line numbers, too.

Some of the higher-voted ones here too:

http://www.arclanguage.com/item?id=4070

-----

1 point by eds 6449 days ago | link

I am planning on doing FFI.

How long do you think defcall and settable-fn would take?

Good error reporting would be nice, I'll consider it. (But I'm a little dubious about working on something pg may have already done.)

-----

1 point by almkglor 6449 days ago | link

> How long do you think defcall and settable-fn would take?

About a week, maybe less ^^. Defcall is reasonably trivial although it requires some rethinking. settable-fn is implementable using defcall (see nex-3's settable-fn2) but I'm personally dubious of such a style, and prefer my own.

> (But I'm a little dubious about working on something pg may have already done.)

We don't have evidence either way - pg hasn't commented on this (none that I've seen, anyway). Up to you to decide whether to act as if pg made it, or act as if pg didn't make it.

-----


Crick, I was beginning to wonder if "kens" was some sort of internet meme.

-----


Suppose instead that we define a basic + operation which always operates on two values:

  (def base-+ (a b)
    (...))
Then we simply define + as:

  (def + rest
    (reduce base-+ (car rest) (cdr rest)))
  (def reduce (f z l)
    (if l
      (reduce f (f z (car l)) (cdr l))
      z))
Then, instead of redefining +, we add a rule: if you want your new type to have a + operation and still be optimizable by arco, then redefine base-+, not +

Then we can make type inferences based simply on pairs of values.

-----

1 point by almkglor 6449 days ago | link | parent | on: CL-Arc: Arc Compiler in Common Lisp

I also suggest that. In fact, looking at Chicken's implementation - stack == heap - is rather inspiring, because it shows exactly how a garbage-collected memory manager should be done: just decrement a pointer, in this case the stack pointer. Brilliant IMO. Wish I'd thought of that.

-----

1 point by almkglor 6450 days ago | link | parent | on: CL-Arc: Arc Compiler in Common Lisp

Regarding tail recursions, aruu, how about trampolines? Of course, trampolines are reputedly slow....

Edit: http://en.wikipedia.org/wiki/Chicken_%28Scheme_implementatio...

As for continuations, if you transform everything (!!) into cps style, then you get continuations for free ^^.

-----

1 point by almkglor 6450 days ago | link | parent | on: IDEA: Syntax checker

Interesting. I suppose this means that (at least for the cps version of treeparse) a fail must also "return" an error value (potentially just a "Expected lit %c, not found"). Of course 'alt parsers would ignore the error message, and generate its own when all alternatives fail ("No alternatives found"). Hmm. I think if the fail continuation returned an error message, we could create a filt-style parser (for the cps case):

  (def onerr (parser msg)
    (fn (remaining pass fail)
      (parser remaining pass
        (fn (_) ; ignored message
          (fail msg)))))
For the monadic version, our old nil-as-fail code would have to be changed I suspect; basically instead of the old type Return = Return parsed remaining actions | nil, we'll need type Return = Return parsed remainig actions | Failed message .

-----

3 points by almkglor 6450 days ago | link | parent | on: CL-Arc: Arc Compiler in Common Lisp

Yes, but if we want quick prototyping, we also want transformation of the prototype to something we'll use, which might need to be faster than our mockup. Take for example Arki: the wikitext parser was written easily using a quick prototype on raymyers' treeparse, but in actual use, the wikitext parser was too slow. Unfortunately, there's no easy way to transform the parser structure to faster techniques (such as state machines), without doing it by hand, which rather undermines the purpose of the quick prototype. By optimizing the underlying parser, however, the prototype was still useable, and by exposing a few more particular combinations (such as nil-returning sequences, for when we only care that a syntax exists or doesn't exist, not the individual charactes of the syntax), we can refine the prototype into something faster.

-----

4 points by almkglor 6450 days ago | link | parent | on: CL-Arc: Arc Compiler in Common Lisp

Why not? Every higher-level language is just a macro on the assembly language of a computer. Model your native code as a list like (__asm (mov 42 ax) (ret)). Consing is just a call to a predefined cons: (__asm (push d) (push a) (call cons) (ret)) - or by applying the lessons of Lambda The Ultimate X (__asm (push d) (push a) (jmp cons)). ^^

Okay, okay, I was actually planning to do something like that a long time ago, haha. But I haven't (yet) found any holes in the basic concept of modelling every function call (f x) as a macroexpansion on (__funcall f x), which expands to an (__asm) form with the function call. Then for functions themselves (fn (x) (f1 x) (f x)), transform the last function call to a tail call: (__asm_let x (esp 4) (__funcall f1 x) (__tail_funcall f x)). Stuff like that ^^.

-----

1 point by eds 6449 days ago | link

If you want to start writing an Arc native code compiler (in Arc), it just brings up a lot of difficult issues that I'm not sure how to deal with. A reader, GC, continuations, tail recursion, etc. all have to be implemented in Arc. You stop getting those for free once you remove the Scheme runtime from the picture.

So quite frankly, I have a lot to learn before I'll be able to take on a project like that.

-----

1 point by almkglor 6449 days ago | link

Encapsulation my friend, encapsulation. Just make a general sketch and leave the details a bit. Then write the details. Besides, you've already done it! Just s/CL/Arc/ your posted article, then s/compile to Arc/compile to assembly/

Sure GC is nontrivial, but Boehm's GC is not bad at all. And if you really need continuations/tail recursion than make everything continuation passing style (you'll probably need to anyway). And I'm sure raymyers' treeparse can help in the reader department.

(IMO the difficulty here in itself is probably the assembly code you'll emit for a given piece of code, not reader/GC/conts/tailrec)

Remember, CL is by itself not so similar to Scheme that you can directly use its reader, as well as its execution model, in your final product. You'll write your own Arc reader in CL anyway (in CL 'arc == 'ARC, in arc 'arc != 'ARC), so you might as well (tada!) write it in Arc and compile it down to assembly. You'll need conts and no, you can't trust CL enough to handle tailrecs.

(Hmm. Maybe I shouldn't be advising you, maybe I should be doing this myself to steal your thunder ^^)

-----

3 points by stefano 6448 days ago | link

CL reader is highly extendable and you can tell it to be case sensitive: (setf (readtable-case readtable) 'sensitive), if I remember correctly. It's possible, I think, to use it to read Arc code.

-----

1 point by eds 6448 days ago | link

Is this portable?

But assuming it works in some form or other, it should remove most of the need to write a custom reader. Though there is still the issue of (for example) complex number syntax, etc.

-----

3 points by stefano 6448 days ago | link

It's in the standard (CLTL2). You can fix everything, because you can tell the reader to use your own functions on particulars characters, as an example this is a piece of code that lets you use Arc [... _ ...] syntax in Common Lisp:

(defun read-square (stream c) (declare (ignore c)) (let ((body (read-delimited-list #\] stream t))) `#'(lambda (_) ,body)))

(set-macro-character #\] #'(lambda (x y) (declare (ignore x y)) (values))) (set-macro-character #\[ #'read-square)

-----

1 point by eds 6449 days ago | link

So would you use the existing (C/C++) implementation of Boehm GC? If so then doesn't that make this not completely implemented in Arc? If not then that's one more piece to write (although I guess it isn't too difficult to translate code that's already been written in another language).

Yes, the assembly part of it looks difficult to me. When I look at Arc or Lisp code I don't see any way to translate that to native code. Obviously has been done, I'm just not educated on such matters.

You have a good point about the reader, I should probably add that to my proposal. And writing it in Arc would be an interesting exercise.

And can't I trust CL about tail recursion? Most decent implementations do tail recursion, right? And can't I tell people to stay away from those that don't?

But suppose I can't trust CL to do tail recursion. What am I supposed to do about it?

-----

1 point by almkglor 6449 days ago | link

> So would you use the existing (C/C++) implementation of Boehm GC? If so then doesn't that make this not completely implemented in Arc?

And neither is Linux completely implemented in C, and C compilers written in C are not completely implemented in C, because bits and pieces of the libraries they link their code to are written in assembly.

> Yes, the assembly part of it looks difficult to me. When I look at Arc or Lisp code I don't see any way to translate that to native code. Obviously has been done, I'm just not educated on such matters.

The Lambda the Lutimate papers are a good place to start if you're interested - they include some hand-written assembly code equivalents to Scheme/Lisp code, largely function calls and prefix/suffix. Given that the most basic axioms of Arc include (fn ...) and a function call syntax, this would be quite of interest.

> But suppose I can't trust CL to do tail recursion. What am I supposed to do about it?

Use 'prog and 'go? ^^ Lambda is the lutimate!!

-----

1 point by sacado 6448 days ago | link

"Yes, the assembly part of it looks difficult to me. When I look at Arc or Lisp code I don't see any way to translate that to native code. Obviously has been done, I'm just not educated on such matters."

I found a good link / tutorial about how to compile a subset of Scheme to C language. The compiler is about 800 lines of Gambit Scheme (blank lines included) and even deals with tail-recursion and continuations ! (well, that's based on the lambda papers...)

No GC, but you can use Boehm and have one for free.

-----

1 point by stefano 6448 days ago | link

You can trust CL to do tail recursion. I'm not sure if the standard requires it but every decent implementation must provide it.

-----

2 points by eds 6448 days ago | link

I think I'll just say that CL-Arc is only compatible with the subset of CL implementation that do tail recursion. (Which happens to be all the implementations I would consider using anyways.)

-----

1 point by kens2 6450 days ago | link

Garbage collection?

-----

3 points by almkglor 6450 days ago | link

The only time you need garbage collection is when you're allocating new memory. This is of course abstracted away into the 'cons procedure you end up calling at each (cons a d) - basically 'cons triggers gc if necessary. You may then very well just use the someone-Boehm garbage collector for C, which will (I think!) helpfully look at registers and stack for you.

The someone-Boehm GC (reportedly) works well with C - I'm reasonably sure that it will work well with assembly.

-----

1 point by sacado 6450 days ago | link

only cons ? What about bignums ? And strings ?

-----

2 points by stefano 6450 days ago | link

If you use the Boehm GC, you can handle everything simply by calling GC_malloc every time you need memory.

-----

1 point by sacado 6449 days ago | link

Yes, you're right. Sorry about that.

Anyway, maybe the right way to do so is by destructuring a Scheme implementation ? Starting from a given implementation, you write your compiler from scratch, but use the facilities of the chosen implementation for the reader and the GC. Then, once it's working, you gradually remove the scaffolding by implementing these things by hand...

-----

1 point by almkglor 6449 days ago | link

Well, if you're going to end up implementing something like my unrolled-lists ideas, then everything can very well be a cons cell underneath. Including bignums and strings.

-----

4 points by stefano 6449 days ago | link

PicoLisp (http://www.software-lab.de/ref.html#cell) uses cons cells to implement everything, from bignums to strings.

-----

1 point by sacado 6449 days ago | link

Hmm, looks like an interesting beast... I'll have a look at it some day...

-----

4 points by almkglor 6450 days ago | link | parent | on: CL-Arc: Arc Compiler in Common Lisp

Well, there are still ways to break the speed barrier. For instance the main reason I made cached-table was in order to cache the results of parsing the wikitext in Arki (but not keeping them for too long, since that would simply be a waste of memory). This is even arguably the "correct" thing to do and I might not have done it yet if Arc hadn't been so slow ^^.

"When I was a noob, I talked like a noob, I thought like a noob, I reasoned like a noob. When I became a hacker, I put noobish things behind me. Now we see but a poor implementation as in an alpha; then we shall see code to code. Now I code in part; then I shall code in full, even as I am full of code. Now these three remain: hubris, impatience, laziness. But the greatest of these is laziness."

-----

1 point by raymyers 6450 days ago | link

Larry Wall, I think.

Yes, you can always optimize your Arc code to mitigate the problem. My point still stands though. If we want to be able to use Arc in production situations, we will eventually crave an industrial-strength Arc compiler.

This becomes even more obvious if you take seriously the notion of "A Hundred-Year Language".

-----

1 point by almkglor 6450 days ago | link

Actually a paraphrase of the Christian Bible's 1 Corinthians 13:11-13, although yes, the three virtues are the Larry Wallian ones ^^

-----

1 point by eds 6450 days ago | link

Wow, did you come up with that yourself? I'd like to quote it if you don't mind.

-----

1 point by almkglor 6450 days ago | link

Err, yeah. I tend to pattern match on lots of things - I've got some weird takes on Buddhist philosophy somewhere on the boards too.

-----

More