Arc Forumnew | comments | leaders | submit | fallintothis's commentslogin
1 point by fallintothis 5782 days ago | link | parent | on: Bug: on doesn't work for tables

But of course you can't access tables by index.

You can if they're indexed by integers.

  arc> (on x (obj 0 'a 1 'b 2 'c 3 'd) (prs index x) (prn))
  0 a
  1 b
  2 c
  3 d
  nil
But using each on a table doesn't guarantee this ordering on the keys.

  arc> (each (k v) (obj 0 'a 1 'b 2 'c 3 'd) (prs k v) (prn))
  2 c
  1 b
  0 a
  3 d
  #hash((3 . d) (0 . a) (1 . b) (2 . c))
I wonder why you'd want index bound if you aren't iterating through integer keys in order. Do you have an example? Seems like there should be one, but I can't think of it.

-----

1 point by akkartik 5781 days ago | link

Yeah here's a use case. I wrote a macro called everyp to overlay atop each with a progress indicator. It prints out the number of iterations at the start and a heartbeat every n iterations. I found this bug when I tried to everyp (implemented using on) over a table.

-----

1 point by fallintothis 5781 days ago | link

Interesting. Arc has essentially that, but implements it directly with each:

  (mac noisy-each (n var val . body)
    (w/uniq (gn gc)
      `(with (,gn ,n ,gc 0)
         (each ,var ,val
           (when (multiple (++ ,gc) ,gn)
             (pr ".") 
             (flushout)
             )
           ,@body)
         (prn)
         (flushout))))
I suppose it depends on if you want index to be captured. Since on is used in your version, index is bound within the macro call. So if

  (everyp 2 c "abcd"
    (prn c)
    (++ index))
expands to

  (on c "abcd"
    (when (multiple index 2)
      (prn "heartbeat"))
    (prn c)
    (++ index))
it prints

  heartbeat
  a
  heartbeat
  c
because on captures index. This might be unexpected if you just want heartbeats in an otherwise normal each.

-----

1 point by akkartik 5781 days ago | link

Ah, thanks for the reminder about noisy-each.

-----

3 points by fallintothis 5783 days ago | link | parent | on: Scheme from Scratch - Introduction

Smart-ass answer: once you build up to mzscheme, you can run Arc. ;)

To elaborate: Scheme and Arc aren't that different to implement. Parsing & literals are largely the same (Arc doesn't use booleans, vectors, et al.), Lisp constructs are fairly standard (quote, if, assign, fn, etc.), and Arc even borrows high-level features like TCO and continuations. Scheme uses hygienic macros, which seem harder to implement than Arc/CL-style macros anyway. Moreover, Arc is simple: the "primitive" things are in ac.scm and the "meat" is in arc.arc. Once you get the Scheme side working, you get the rest of Arc for free.

Good series, though. With the above in mind, it'd be pretty easy to tweak Scheme-from-Scratch into Arc -- and a good exercise, at that.

-----

2 points by fallintothis 5786 days ago | link | parent | on: From zip to smart tokenization

I'd use a different name for nctx because I don't know what it's supposed to mean. You define it as a sliding window, so I call it windows (alternatively sliding-windows, but that's a bit longer).

I notice that it conses a lot for cdrs, which is ultimately useless since (cdrs (- n 1) l) is just used in an apply. Also, the stateful iteration remark reminded me of the discussion at http://arclanguage.org/item?id=11104. So, without studying zipmax at all, I rewrote nctx (in vanilla Arc) using reclist:

  (def windows (n xs)
    (accum a
      (reclist [do (a:firstn n _) nil] xs)))
This doesn't work quite the same way.

  arc> (windows 3 '(1 2 3 4))
  ((1 2 3) (2 3 4) (3 4) (4))
But each list is suitable for destructuring in a let or each, which seems to be your intended use. e.g.,

  arc> (each (a b c) (windows 3 '(1 2 3 4))
         (prs a b c)
         (prn))
  1 2 3
  2 3 4
  3 4 nil
  4 nil nil
  nil
As for efficiency:

  arc> (do1 'ok (= xs (n-of 1000000 'x)))
  ok
  arc> (jtime (nctx 3 xs))
  time: 28047 msec.
  ok
  arc> (jtime (windows 3 xs))
  time: 21909 msec.
  ok
Hm. Not that much faster. Does it still cons less?

  arc> (= cons-count* 0)
  0
  arc> (let old-cons cons
         (def cons (x y)
           (++ cons-count*)
           (old-cons x y)))
  *** redefining cons
  #<procedure: cons>
  arc> (jtime (nctx 3 xs))
  time: 39062 msec.
  ok
  arc> cons-count*
  7000038
  arc> (= cons-count* 0)
  0
  arc> (jtime (windows 3 xs))
  time: 29046 msec.
  ok
  arc> cons-count*
  5000032
It doesn't cons nearly as much, so how else could it be made faster? Turns out reclist bites us.

  (def reclist (f xs)
    (and xs (or (f xs) (reclist f (cdr xs)))))
f is meant to be a boolean test, which we don't even care about: we just want to get past the first or clause. So, I write a more imperative loop.

  (def windows (n xs)
    (accum a
      (a (firstn n xs))
      (whilet xs (cdr xs)
        (a (firstn n xs)))))
This time (in a new session, so cons is back to normal):

  arc> (do1 'ok (= xs (n-of 1000000 'x)))
  ok
  arc> (jtime (nctx 3 xs))
  time: 28850 msec.
  ok
  arc> (jtime (windows 3 xs))
  time: 13012 msec.
  ok
That seems to do the trick! It even conses just as much as the old windows:

  arc> (= cons-count* 0)
  0
  arc> (let old-cons cons
         (def cons (x y)
           (++ cons-count*)
           (old-cons x y)))
  *** redefining cons
  #<procedure: cons>
  arc> (jtime (nctx 3 xs))
  time: 40256 msec.
  ok
  arc> cons-count*
  7000038
  arc> (= cons-count* 0)
  0
  arc> (jtime (windows 3 xs))
  time: 20308 msec.
  ok
  arc> cons-count*
  5000032
The next way I might try speeding it up is to inline firstn, which means we need a macro, but that seems hard to do at expansion time without passing a literal number instead of n. Plus, I think this definition strikes a nice balance between efficiency and self-containment (i.e., we need no new definitions).

I haven't figured out a way to simplify partition-words yet, but when I get a chance later I'll have a look. At first glance, I'd use symbols instead of 0, 1, and 2 for your character classes. e.g.,

  (with (NEVER-WORD* ";\"![]() \n\t\r"
         MAYBE-WORD* ".,'=-/:&?")
    (def charclass(c)
      (let c (coerce c 'string)
        (if (posmatch c NEVER-WORD*)
              'never
            (posmatch c MAYBE-WORD*)
              'maybe
              'always))))
It's more readable simply because words have more meaning than numbers.

-----

1 point by akkartik 5786 days ago | link

That was illuminating, thanks! That final definition of windows is awesome. I wrote these functions about six months ago, when I wasn't aware of reclist. Come to think of it, I still haven't used reclist before, so perhaps this thread should be called reclist not zip.

nctx => short for 'context of n'. For this post I deliberately tried to come up with three different perspectives on each function (description, name, test string) just to see what sticks.

-----

1 point by fallintothis 5786 days ago | link

That was illuminating, thanks!

Sure thing!

nctx => short for 'context of n'

Ah. I had guessed that, but it still seemed clunky. I'm liking sliding-window, but it's kind of long.

As for partition-words, it could be made clearer (less "ball of parens") with shorter definitions and more evenly distributed logic.

(conscar a l) is just (push a (car l)), so we can get rid of a macro.

Notice that charclass is used in two places: once for firstchar, and several times for any subsequent curr character. But each time it's called on curr, the newstate is set to something that's definitely not 'maybe (renamed per my previous comment). So it seems that this logic could be moved into charclass itself.

  (with (NEVER-WORD* ";\"![]() \n\t\r"
         MAYBE-WORD* ".,'=-/:&?")
    (def charclass (c prev next)
      (let c (coerce c 'string)
        (if (posmatch c NEVER-WORD*)
              'never
            (posmatch c MAYBE-WORD*)
              (if (or (whitec prev) (whitec next))
                  'never
                  'always)
              'always))))
This handles the curr characters. Before handling firstchar, we can simplify thus:

  (= never-word* ";\"![]() \n\t\r"
     maybe-word* ".,'=-/:&?")

  (def charclass (c prev next)
    (if (find c never-word*)
          'never
        (find c maybe-word*)
          (if (or (whitec prev) (whitec next))
              'never
              'always)
          'always))
Changes: (1) It's not a big deal, but Arc tends toward lowercase. (2) Since your variables were named like globals (i.e., with asterisks), I made them actually global. There's nothing wrong with the with block, but if you use that you probably shouldn't put asterisks after the names. (3) You can use find instead of the coerce & posmatch stuff. (4) I use prev instead of last to avoid confusion because Arc already defines a last function.

With this abstracted, we can analyze how state changes. Specifically, we see that firstchar can give a 'maybe result, though no other character can. I suspect this is a flaw in the logic, but preserved it anyway. It's cleaner to separate these two cases into their own functions, so I write

  (= never-word* ";\"![]() \n\t\r"
     maybe-word* ".,'=-/:&?")

  (def charclass (c)
    (if (find c never-word*)
          'never
        (find c maybe-word*)
          'maybe
          'always))

  (def charstate (c prev next)
    (caselet class (charclass c)
      maybe (if (or (whitec prev) (whitec next))
                'never
                'always)
            class))
Updating gives us the program:

  (= never-word* ";\"![]() \n\t\r"
     maybe-word* ".,'=-/:&?")

  (def sliding-window (n xs)
    (accum a
      (a (firstn n xs))
      (whilet xs (cdr xs)
        (a (firstn n xs)))))

  (def charclass (c)
    (if (find c never-word*)
          'never
        (find c maybe-word*)
          'maybe
          'always))

  (def charstate (c prev next)
    (caselet class (charclass c)
      maybe (if (or (whitec prev) (whitec next))
                'never
                'always)
            class))

  (def partition-words (s)
    (unless (blank s)
      (with (ans (list:list:s 0) state (charclass s.0))
        (each (prev curr next) (sliding-window 3 (coerce s 'cons))
          (when curr
            (let newstate (charstate curr prev next)
              (if (is newstate state)
                  (push curr (car ans))
                  (push (list curr) ans))
              (= state newstate))))
        (rev:map [coerce (rev _) 'string] ans))))
That's as far as I got. I think the code's clearer, but I'm not even sure how the original was supposed to work. For example, yours and mine both give these results:

  arc> (partition-words "this slash / has spaces")
  ("this" " " "slash" " / " "has" " " "spaces")
  arc> (partition-words "/ this slash doesn't")
  ("/" " " "this" " " "slash" " " "doesn't")
  arc> (partition-words "My parents' car is fast.  It's all like 'vroom'.")
  ("My" " " "parents" "' " "car" " " "is" " " "fast" ".  " "It's" " " "all" " " "like" " '" "vroom'.")
But I defer to your judgment, since it's your program. ;)

-----

2 points by akkartik 5786 days ago | link

Very nice, thanks. I'm leaning toward windows as well. nctx is shorter, but it's not clear I use it often enough to justify the terseness.

Those single quote issues on the last line are def bugs, thanks.

partition-words isn't a tokenizer, it partitions the string along word boundaries. Hence the tokens containing spaces and punctuation. You can easily extract tokens with a single keep, but I found it useful to be able to easily recombine the partitions to reconstruct the original string.

-----


In no particular order:

Why is forever defined with awhile? I can't imagine wanting it bound to t for the whole loop.

I'm trying to decide whether I like awhile. I understand it as "anaphoric while", but the namespace collision with English rubs me the wrong way.

ret is another one like that. I understand what the name is supposed to mean: it's kind of a portmanteau between "let" and "return", since it's a let block that returns the variable. But the "return" context makes me think ret's like a standard return statement you might have in a loop, which it clearly isn't.

I can't think of any better names for them. I suspect they just take some getting used to.

Do you mean for old and result to be bound in before-exec and after-exec, or should those be gensyms?

init is a good name. You might want to rethink the definition:

  arc> (= x 1)
  1
  arc> (init x 5 y 5)
  nil
  arc> x
  1
  arc> y
  Error: "reference to undefined identifier: _y"
I think ifcall should be named callif or call-if to match carif and consif.

-----

1 point by akkartik 5791 days ago | link

Thanks for those comments. Yes, init could be better.

I'd never noticed the collision with english's awhile! And yes, I shouldn't introduce anaphora needlessly.

I did mean to bind result, that seems useful. old could perhaps be a uniq. (Update: I think I was following the precedent of orig in http://awwx.ws/extend)

I have to disagree on ret, though. It's short, and I'm a sucker for puns of all flavors.

Regarding callif: The comment at the top of arc.arc suggests consif isn't satisfactory to pg/rtm. if at start or end seems about equally pleasing. What I really want is for ifcall to suggest bound. Maybe trycall, but that evokes exceptions.

-----

1 point by fallintothis 5791 days ago | link

Yeah, ret isn't a bad name. And puns are okay. For example, I like the name whilet -- probably because I often do the same thing inadvertently while writing (i.e., adjoin the end of one word with the beginning of the next if they have the same letters). I just usually use ret for

  (point ret
    (while cond
      (ret 5)))
Though I prefer full words if they're short, so I actually use return these days. I'd just need to get used to ret being a let instead of a return.

if at start or end seems about equally pleasing.

I don't really think if at the beginning conveys the same idea. The way I read it, if-something implies "if something, then do..."; but I read something-if as "if this thing, then something it". For instance, which looks clearer?

  (if-empty xs
            0
            (+ 1 (len (cdr xs))))
vs

  (empty-if xs
            0
            (+ 1 (len (cdr xs))))
I say the first, since I read it "if xs is empty, then...", whereas the second says "if xs, then empty it".

As it pertains to callif/ifcall, we mean to say "if var, then call it", which implies callif per the above.

The arc.arc comment seemed more about how consif and conswhen aren't distinguishable enough (how is "when" different from "if"?).

-----

1 point by akkartik 5791 days ago | link

Ah, I just figured out you were referring to the CL return keyword inside loop (?). Something to mull, though it should be ok as long as arc doesn't get a loop keyword (a candidate name for forever)

-----

2 points by fallintothis 5791 days ago | link

Incidentally, Arc does have a loop macro that's kind of like a C for-loop:

  (mac loop (start test update . body)
    (w/uniq (gfn gparm)
      `(do ,start
           ((rfn ,gfn (,gparm) 
              (if ,gparm
                  (do ,@body ,update (,gfn ,test))))
            ,test))))
I like "forever". It's very clear.

-----

6 points by fallintothis 5792 days ago | link | parent | on: Some Arc questions from a beginner

1.

  arc> (when nil (prn "I will not get evaluated, because this is a macro."))
  nil
  arc> (def when2 (test . body) (if test (do body)))
  #<procedure: when2>
  arc> (when2 nil (prn "I get evaluated anyways, because this is a function call."))
  I get evaluated anyways, because this is a function call.
  nil
in is an interesting case, because it's a macro for efficiency reasons: it expands into simpler code with fewer function calls than, say, a call to some. This is kind of how Arc does function inlining, rather than making a compiler infer it. See http://en.wikipedia.org/wiki/Inline_function.

2. Different strokes for different folks, I guess. I don't think I've ever used the f argument of pair, myself. You can accomplish your goal with

  arc> (map [apply + _] (pair '(1 3 5 7 9)))
  (4 12 9)
though that's inefficient.

3. The comment above the definition of join says

  ; Rtm prefers to overload + to do this
Rtm is Robert Morris, who plays a role in Arc's implementation / design. This would indicate that Paul Graham (the "main" designer of Arc) prefers to use join, but is unsure which is best.

4. Ah, but then you'd lose information. e.g., the definition of mem is

  (def mem (test seq)
    (let f (testify test)
      (reclist [if (f:car _) _] seq)))
Here, we want to return the entire sublist, not just the car, but we want to apply f specifically to the car of the sublist. So, we don't want to make reclist only work on the car, since we'd lose said sublist. That is, the current mem behavior is

  arc> (mem 5 '(8 6 7 5 3 0 9))
  (5 3 0 9)
But by adding car to reclist, we'd only be able to do something like

  arc> (mem 5 '(8 6 7 5 3 0 9))
  5
5. Tail calls should be recognizable in the call-graph of the code. For example, the mutually recursive functions

  (def even/r (n)
    (if (is n 0)
        t
        (odd/r (- n 1))))

  (def odd/r (n)
    (if (is n 0)
        nil
        (even/r (- n 1))))
involve tail recursion, even though neither even/r nor odd/r call themselves directly. Since the function in loop is a tail call (the ,gfn call is the last function before a return), it should still be optimized. Someone please correct me if I'm wrong.

6. No significance aside from naming conventions: asterisks follow the names of global variables.

-----

1 point by graphene 5791 days ago | link

Thanks to both of you for your answers; they're very helpful.

I had to take some time to digest them (and my day job got in the way) but I have a few follow-up remarks/questions:

1. is clear now; however I get the feeling that I need to play with macros more to get a real feeling for when and why they are as useful as many people say.

2. refering to fallintothis' answer, do you mean inefficient in execution (why, and as opposed to what?) or simply a bit of a drag to type out?

referring to akkartik's response, It's not that I thought the definition of pair breaks anything, just that it produces non-useful behavior (my original wording of inconsistent probably doesn't describe well what I mean); Is there a use case where you would pass a function to pair, but in the event of an odd number of elements, want the last element simply returned as a one-element list instead of the result of calling the function on it?

5. I get that it should still be optimized, but it just seems strange to me to implement it recursively when that's not the most straightforward (to me at least) way to define a loop macro.

Is the rule in Arc (or lisp in general) that preference is given to functional implementations wherever possible, or am I reading too much into this?

6. Both your explanations seemed strange to me at first (since in other languages, global variables are technically different from normal (is there a term for this?) variables). But it makes sense to me when you consider lisp's lexical scope (which the arc tutorial unfortunately doesn't cover other than mentioning closures); is a global variable simply one that is defined at the highest level of the code, i.e. only enclosed within one (the outermost) pair of parentheses?

-----

5 points by fallintothis 5790 days ago | link

1. My dirty little secret: after enough experience with macros, they seem pretty "normal" to me. They're a natural way to do what they do, so when I pause to write a macro, it doesn't even seem like some deep magic of an ultra-language. There's no need to be a zealot to appreciate macros, though their utility is apparent with time. For example, the definition of the while macro

  (mac while (test . body)
    (w/uniq (gf gp)
      `((rfn ,gf (,gp)
          (when ,gp ,@body (,gf ,test)))
        ,test)))
transforms clear code like

  (while (> x 10)
    (-- x))
into tedious code like

  ((rfn gs1722 (gs1723)
     (when gs1723
       (-- x)
       (gs1722 (> x 10))))
   (> x 10))
before it gets evaluated. We didn't even need to bake a while loop into the language -- we can define it using the macro.

It's not impossible to write while without macros. For instance, in the Factor language, while works by using anonymous functions instead of unevaluated code. It's similar to the Arc function

  (def while (test body)
    ((afn (condition)
       (when condition
         (body)
         (self (test))))
     (test)))
But in Arc, you'd need to write something like

  (while (fn () (> x 10))
         (fn () (-- x)))
Whereas Factor has less syntactic overhead for anonymous functions. So for Arc, a while macro is a clear solution.

2. All of the above! It's clearly longer. One way it's inefficient is in how many cons cells it creates (more cons = more memory):

  arc> (= cons-count* 0)
  0
  arc> (let old-cons cons
         (def cons (x y)
           (++ cons-count*)
           (old-cons x y)))
  *** redefining cons
  #<procedure: cons>
  arc> (pair '(1 3 5 7 9) +)
  (4 12 (9))
  arc> cons-count*
  4
  arc> (= cons-count* 0)
  0
  arc> (map [apply + _] (pair '(1 3 5 7 9)))
  (4 12 9)
  arc> cons-count*
  11
In the map version we first pair up the elements into a new list, then iterate through that to add the pairs, putting those into yet another list. We're doing twice the work. If pair worked right, we'd only go through '(1 3 5 7 9) once, adding the pairs of numbers as we went.

5. Not reading too much into it: functional solutions are generally preferred. My best guess says it's a matter of taste. To me, state is weird to reason about, but recursion is straightforward. Also consider that, to implement a loop statefully, you'd need something like goto. But we still have first-class functions, so if we can model loops as tail calls at no cost to efficiency, then we don't need to add goto to Arc. It keeps the language simpler.

This isn't the case in all Lisps. For example, Common Lisp has tagbody wherein you can use go, which is a goto statement. See http://sunsite.univie.ac.at/textbooks/cltl/clm/node91.html. Implementations often use it for, e.g., the loop macro (which is quite different from Arc's, but still loops).

6. Yes, global variables are the ones "at the top".

  arc> (= global* 10)                                        
  10                                                         
Local variables (the opposite of global variables) only live inside a block of code (i.e., locally), and can be different values during different function calls.

  arc> (def f (local)
         (+ global* local))
  #<procedure: f>
  arc> (f 10) ; during execution, 'local' is bound to 10 inside 'f'
  20
  arc> (f 123) ; during execution, 'local' is bound to 123 inside 'f'
  133
Global variables live everywhere (i.e., globally), and tend to change less frequently -- you set them explicitly to some value.

  arc> global*
  10
  arc> local ; isn't around outside of 'f'
  Error: "reference to undefined identifier: _local"
  arc> (= global* 5)
  5
  arc> (f 10)
  15
  arc> (f 123)
  128
You can alter local variables, too, but they still only live locally.

  arc> (let local 5
         (= local 10)
         (+ global* local))
  15
  arc> global*
  5
  arc> local
  Error: "reference to undefined identifier: _local"

-----

2 points by graphene 5790 days ago | link

Thanks for the explanations, I really appreciate it; everything seems clear now...

Now I'm off to build my own facebook clone :-)

-----

2 points by fallintothis 5801 days ago | link | parent | on: Tiny quiz app

It might be worth noting that ret was unnecessary in this case.

  (mac ret (var val . body)
   `(let ,var ,val ,@body ,var))
   
  (def question (url q a b c d)
    (let id (++ question-id*)
      (ret new (inst 'question
                     'id id 'url (video-url url)
                     'q q 'a a 'b b 'c c 'd d)
        (= (questions* id) new))))
could just be

  (def question (url q a b c d)
    (let id (++ question-id*)
      (= (questions* id)
         (inst 'question
               'id id 'url (video-url url)
               'q q 'a a 'b b 'c c 'd d))))
ret would certainly be useful in general, of course.

-----

3 points by skenney26 5801 days ago | link

I like your rewrite of 'question.

I agree that 'ret would be more useful in other areas than here. In arc.arc 'best, 'summing, 'sum, 'listtab, 'copy, 'inst, 'w/table, 'memtable, and 'evtil all use this idiom of creating a local variable with 'let and then returning it.

-----


I imagine it's the same as http://news.ycombinator.com: editors (e.g., pg, though I'd guess there are others) can change titles, usually to correct grammar. Not as much headline-editorializing can happen in a forum such as this (versus news.yc), so titles probably get edited less here.

-----

1 point by thaddeus 5814 days ago | link

I think that's an incredibly bad idea, particularly when 'they' are not improving the data.

-----

1 point by fallintothis 5814 days ago | link

Welcome to the news.yc discussion circa about 2 years ago ;)

http://news.ycombinator.com/item?id=43635

In the case of this title, the only way it got "worse" is that someone goofed on a space, "onMzScheme". An editor could now step in, add a space, and the only difference would be that proper nouns were capitalized. Not that the edit was wholly necessary, but it's not like the title was censored.

-----

1 point by thaddeus 5814 days ago | link

It's really kinda funny. When I post, I notice the submit function capitalizes the first letter of the first word of the title's sentence.... sometimes I look at that and say to myself - hey! that's not what I typed!. So I go back in and edit the title changing the first letter back to lower case as intended (correct or not). The update function allows this to pass through. So now that I see (more than once) my text being changed I find myself feeling like I have to battle the bots (or the nots!). It just feels wrong.

-----

1 point by aw 5814 days ago | link

That's good to know about being able to edit the first letter back to lowercase -- on occasion I've started a title with a function or macro name that should be uncapitalized.

-----


http://arclanguage.org/item?id=4742

-----

1 point by thaddeus 5816 days ago | link

hmmm... too bad. I have yet to try gambit, but I like the idea that it's fast, supports 64 bit systems and along with termite http://code.google.com/p/termite/ there's concurrency model similar to Erlang. Though I am not sure that would even work with arc, but at a faster version of arc with a concurrency model sounds better to me.

I'm just in this investigating/researching languages + features mode lately :)

-----


Others have answered 2, but to 1: I'm a Vim user, so I used to write Arc code sans syntax highlighting -- the Anarki highlighter wasn't that good. I soon got sick of this, so over the summer I wrote my own highlighter & ftplugin, which I posted at http://arclanguage.org/item?id=10147. It's the most complete/up-to-date syntax highlighter I'm aware of, inasmuch as it works for me. I haven't had much feedback about it, but if you're a Vim user, I'd appreciate any input you have!

-----


Incidentally, they do implement the benchmark game's programs (and then some): http://gitweb.factorcode.org/gitweb.cgi?p=factor/.git;a=tree...

They just don't want to submit them yet -- work being done on the compiler and such: http://www.reddit.com/r/programming/comments/2krih/factor_90... (granted, this link is a year old)

For some hand-spun results, you can check out http://factor-language.blogspot.com/search?q=shootout or http://factor-language.blogspot.com/search?q=benchmark. I think the most recent results for Factor's benchmark suite are at http://factor-language.blogspot.com/2009/08/global-float-unb....

-----

1 point by fallintothis 5819 days ago | link

For the sake of pedantry, the month-old http://www.reddit.com/r/programming/comments/9ukis/improved_... confirms the year-old reddit post. I would've edited my post, but alas, ran out of time. I'll stop flooding with links now.

-----

More