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

Actually, you've presented Factor's hello world as though it were a file. They have a REPL, too -- they call it the listener, though. You can either use the GUI version it comes with or from the command line do

  $ factor -run=listener
  Loading ~/.factor-rc
  ( scratchpad ) "Hello word" print
  Hello word
The syntax is aesthetically pleasing in an important way: it's very consistent. While postfix might not look "right" at first, it belies an incredibly simple parsing algorithm -- one that allows for easy definitions of the words like USE: and IN: and even :.

Not that you need to learn Factor. Just sayin'.

-----

1 point by thaddeus 5820 days ago | link

Actually it's not I that present it this way:

http://concatenative.org/wiki/view/Factor/Examples

I presumed that without "USE: io" that "Hello World" was not being sent to the standard output where as my arc/haskell examples actually were. i.e. With arc I could load/run a file/script with (pr "Hello World") and it would output "Hello World", but with Factor?...

I just went to each language site and looked for the Hello World examples. It may be that Factor could do a better job advertising AND that I need to spend more than 5 minutes looking :)

Another language to add to my list to learn....

-----

2 points by fallintothis 5820 days ago | link

Yikes, editing race-conditions. I'll fork this off into a different reply.

I presumed that without "USE: io" that "Hello World" was not being sent to the standard output

Actually, that line's like an import statement in Haskell. I would say it's like load in Arc, but that's not really true; USE: and import have to do with module systems, which Arc doesn't have. If you're already familiar with modules, you can skip this stupid explanation, but...

Basically, modules let you structure your functions into different places so that they don't mess with each other. As a silly example, maybe you write a text adventure in Arc and name a function get, as in (get 'ye-flask). But Arc already defines a function called get, as in (map (get 'a) list-of-hash-tables). You want to be able to use both of them at the same time, but would rather not rename your new function. If Arc had modules, you could qualify the function name with the name of the module in which it's defined. Something like

  (use 'game)
  (game.get 'ye-flask)
  (map (get 'a) list-of-hash-tables)
But when you don't want to use Arc's get, you could still overwrite it with the text adventure's get and not need to prefix it with the module name.

This is a vast oversimplification, of course, but that's essentially what they do. So, in languages like Factor, all the I/O routines are in a module called "io". In the io library is a function called print. If you don't need to print things, you don't need to USE: io, which helps keep the "surface area" of your code small.

i.e. With arc I could load/run a file/script with (pr "Hello World") and it would output "Hello World", but with Factor?...

Because Arc doesn't separate anything into modules, you don't need to import things like pr since it's already there by default. The reason the Haskell code in my other reply could do without the import is that putStrLn is similarly defined in Haskell by default: it's in the so-called "standard prelude". That's what the Prelude> prompt tells you in GHCi. You can import other libraries in GHCi, and the prompt will tell you what you're using:

  Prelude> :m + Control.Monad
  Prelude Control.Monad> :m + System.IO
  Prelude Control.Monad System.IO> :m + Foreign.C.Types
  Prelude Control.Monad System.IO Foreign.C.Types>
Hope that helps.

-----

1 point by thaddeus 5820 days ago | link

> Yikes, editing race-conditions. I'll fork this off into a different reply.

yup... I should really write then post :)

> Hope that helps.

It really does. Thanks for taking the time to reply.

-----

1 point by fallintothis 5820 days ago | link

It may be that Factor could do a better job advertising

True. After all, transliterating the Factor example to Haskell looks something like

  module Main where
  import System.IO (putStrLn)

  hello :: IO ()
  hello = putStrLn "Hello world"

  main = hello
Of course, in Haskell you would just write

  module Main where

  main = putStrLn "Hello world"
My point here is that the Factor code doesn't do any real magic. When you give it a chance, the syntax is quite powerful.

It's really neither here nor there: picking a language and getting at least somewhat comfortable with it is going to be better than endlessly deliberating. They all have their merits (even bad languages!).

I'm babbling. Move along. :)

-----


Interesting idea, but I'm having some trouble seeing the consistency -- probably since I've never used PicoLisp. Please feel free to blind me with science, because my brain's not being a team player right now. (I suppose I could just, y'know, install PicoLisp, but asking dumb questions is much more fun.)

Arc has a handful of special forms (quote, quasiquote, if, fn, assign), each there because they specifically have less-than-normal evaluation rules (though at least quasiquote can be implemented as a macro: http://arclanguage.org/item?id=9962). How does PicoLisp handle expressions like the following (pseudo-)Arc code?

  (map if '(t nil) '((pr "a") (pr "b")))
My first thought is that it might correspond to

  (list (if 't   '(pr "a"))
        (if 'nil '(pr "b"))) ; => (list '(pr "a") nil)
which makes sense if if is supposed to be a "normal" function. But this hardly seems useful, since the whole point of if is to conditionally evaluate one of its branches. So, my next thought is that perhaps it's the same as

  (list (if t   (pr "a"))
        (if nil (pr "b"))) ; => prints "a" and returns (list "a" nil)
but why would I want if evaluating the arguments it's passed? It certainly shouldn't evaluate every argument, otherwise it'd be executing each branch (e.g., (if (signed treaty) (world-peace) (unleash-the-nukes))). So then, if this is the case, it's just evaluating some of its arguments? So if I wanted to return '(pr "a"), would I need to do something akin to the following?

  (if something
      ''(pr "a"))
Or is the whole idea of "everything is a function, even special forms" just kind of a pun? How do you start dealing with the other cases, like assign and quote (and fn I suppose, which is just quote in PicoLisp)?

Is the idea just that it'd be cool to pass around special forms as first-class objects? This is a well-tread path, in some ways, since the topic of first-class macros comes up every now and then (http://www.google.com/search?q=site:arclanguage.org+first-cl...).

If anyone could enlighten me, I'd appreciate it. (Read: make mine brain am thinking goodly!)

-----

1 point by diiq 5829 days ago | link

Your first thought is correct.

    (map if '(t nil) '((pr "a") (pr "b")))
returns

    ((pr "b"))
because you've quoted the arguments. This is consistent; if you quote the arguments to if, you will get the same result (as you pointed out). Why would you expect a quoted argument to be evaluated?

The point is, just as you say, that you can pass functions which are normally considered 'special' and they will behave like any other function. Yeah, it's been done before (though you'll notice that picolisp comes up pretty often in your Google search; it's a canonical example) --- but that doesn't make it a bad idea; it's one less thing for the user to keep track of. I watched a person give up learning CL when they tried to pass a special form and discovered, after much frustration, that it was impossible.

-----

1 point by fallintothis 5826 days ago | link

This is consistent [...] Why would you expect a quoted argument to be evaluated?

I misspoke regarding consistency. What I meant was that the "useful" way (conditionally evaluating the branches) would be inconsistent, but the consistent way doesn't seem very useful (because the point of special forms is to behave specially).

Yeah, it's been done before [...] but that doesn't make it a bad idea

Certainly not! I didn't mean to imply first-class macros/special forms are a bad idea --- let alone just because they've been done before. I meant that the ideas are similar; since there's been more discussion about first-class macros, it might be useful to ponder those.

Even so, first-class special forms seem less promising than first-class macros. rntz already pointed out that functions can mimic PicoLisp's behavior for special forms, but you can even mimic the "useful" behavior for certain cases of if:

  arc> (def iffn (x y z) (if (eval x) (eval y) (eval z)))
  #<procedure: iffn>
  arc> (iffn '(prn "test") '(prn "then") '(prn "else"))
  test
  then
  "then"
  arc> (iffn '(do1 nil (prn "test")) '(prn "then") '(prn "else"))
  test
  else
  "else"
But that's still kind of a joke. And what about ones that don't even evaluate their arguments, like fn? If

  (car:map if '(t) '((pr "a")))
corresponds to

  (if 't '(pr "a"))
then does

  (car:map fn '(t) '((pr "a")))
correspond to

  (fn 't '(pr "a"))
which isn't even valid syntax? (At least by the way Arc's quote and fn interact; I understand PicoLisp's quote and fn are unified to just quote.)

I'm not against first-class special forms iff we can reason about them. It's just that reasonable interpretations look like solutions in search of the problem.

-----

1 point by rntz 5828 days ago | link

It's consistent, but it means that passing special forms to higher-order functions is essentially just a form of punnery - it lends you no more expressiveness. There is no way (unless I'm mistaken) to get (map if '(t nil) X), where X is some expression, to evaluate the first element of X (or its evaluation) but not the second. So I could as well just define a function:

    (def iffn a
      (iflet (c . a) a
        (iflet (x . a) a
          (if c x (apply iffn a))
          c)))
    
    (map iffn '(t nil) '(1 2) '(5 6))
    => (1 6)

-----


At a loss for something useful to contribute (sorry), I thought it might help discussion to rewrite the code to be simpler -- people won't need to wrestle as much with the auxiliary definitions that way.

I know you probably meant to use things like merge-tables in the large, but in the example you only use it for a degenerate case that happens to be fill-table. I also assume all the unbound things in the macro are defined elsewhere (i.e., you define nav somewhere, param is bound (is it supposed to be arg?), req is gotten from macro-expansion context, etc.). So, I'm left with

  (mac paginate(url numitems . block)
    (let (params body) (kwargs block 'nextcopy "next" 'prevcopy "prev")
       `(withs (start-index (param req "from")
                end-index   (+ start-index ,numitems))
          ,@body
          (nav ,url start-index end-index ',params))))

  (def kwargs (args-and-body . defaults)
    (let (kws body) (regroup args-and-body)
      (list (fill-table (listtab:pair defaults) kws)
            body)))

  (def regroup (seq)
    (let (kws body) (split seq (or (pos ':do seq) (len seq)))
      (list kws (cdr body))))
On a side note, you might consider changing alist? so that it doesn't cons/compute every length needlessly:

  (def an-alist (l)
    (and (acons l)
         (all (andf acons [is (len _) 2]) l)))

  arc> (do1 nil (= xs (coerce (rand-string 10000) 'cons)))
  nil
  arc> (time (repeat 1000 (alist? xs)))
  time: 11948 msec.
  nil
  arc> (time (repeat 1000 (an-alist xs)))
  time: 8 msec.
  nil

-----

2 points by akkartik 5850 days ago | link

Awesome comments, thanks! I'm new to lisp. Not reading about lisp, but actually hacking on it :)

Yes I was aware I was leaving nav, etc. unspecified, I was trying to evoke say the 'Goooogle' nav line in searches. I've been using 'req' purely as the arg to defops, which wasn't clear at all, sorry.

Thanks for the pointers to fill-table and arg. I just wasn't aware of them.

-----

2 points by akkartik 5850 days ago | link

Speeding up alist? along a different dimension - on really long lists:

  (def pair? (l)
    (and (acons l)
         (acons:cdr l)
         (no:acons:cddr l)))

  (def alist? (l)
    (and (acons l)
         (all pair? l)))
Thanks for the inspiration!

-----


srv.arc isn't configured to serve static Javascript. You'll need to patch it:

  $ diff -u old-srv.arc new-srv.arc                           
  --- old-srv.arc      2009-08-04 11:51:09.000000000 -0700
  +++ new-srv.arc     2009-10-10 16:11:21.000000000 -0700        
  @@ -152,10 +152,11 @@                                      
   Connection: close"))                                      
                                                             
   (map (fn ((k v)) (= (type-header* k) (gen-type-header v)))
  -     '((gif       "image/gif")                            
  -       (jpg       "image/jpeg")                           
  -       (png       "image/png")                            
  -       (text/html "text/html; charset=utf-8")))           
  +     '((gif             "image/gif")                      
  +       (jpg             "image/jpeg")                     
  +       (png             "image/png")                      
  +       (text/html       "text/html; charset=utf-8")       
  +       (text/javascript "text/javascript")))              

   (= rdheader* "HTTP/1.0 302 Moved")

  @@ -242,6 +243,7 @@
              "htm"  'text/html
              "html" 'text/html
              "arc"  'text/html
  +           "js"   'text/javascript
              ))))

   (def respond-err (str msg . args)
Then it should work.

-----

3 points by revorad 5881 days ago | link

Ah thanks! I did try the second change but missed the first one. Finally, I can use js properly with arc. Joy to the world.

-----


Excellent! I love projects that directly make programming more productive. Is this implemented solely in Java? How hard do you think it'd be to write a decent profiler in vanilla Arc (if only for the sake of portability)?

-----

1 point by conanite 5908 days ago | link

This one's only in java, sorry :(

There was a vanilla arc profiler pushed to anarki a while ago - see http://arclanguage.org/item?id=5318 ... it requires you to specify which functions to profile. Which could be more or less useful, depending on what you need.

I'd guess that any kind of decent profiler has to get in under the hood somehow - so to get something similar working for vanilla arc you'd need to go hacking ac.scm, probably somewhere inside

  (define (ac-call fn args env)
    ...

-----

7 points by fallintothis 5908 days ago | link | parent | on: To Hyphenate or Not to Hyphenate

It'd be interesting if there was a pattern to hyphenated names. I assume there isn't because I just hyphenate when it seems like I "should". i.e., Names are often broken up by hyphens because they're easier to read that way. No real algorithm for that. Things like the length of the name can play a factor (e.g., expand-metafn-call doesn't run together like expandmetafncall). Now that I think of it, that's probably why Common Lisp has so many hyphens: its long names would run together otherwise. Even so, it has butlast, notany, notevery, pushnew, and the p vs -p inconsistency.

Arc tends to avoid hyphens:

  arc> (do1 nil
         (= hyphenated     (keep [find #\- (string _)] (keys sig))
            non-hyphenated (rem  [find #\- (string _)] (keys sig))))
  nil
  arc> (len hyphenated)
  103
  arc> (len non-hyphenated)
  386
  arc> (sort < hyphenated)
  (-- abusive-ip admin-gate admin-page app-path bad-newacct clean-url
  code-block code-density common-operators common-tokens cook-user create-acct
  create-handler date-nums days-since defop-raw defopr-raw disable-acct
  edit-app end-tag english-date english-time enq-limit ensure-dir esc-tags
  expand-metafn-call failed-login fill-table fnid-field gen-type-header
  get-user good-login handle-post handle-request handle-request-1
  handle-request-thread harvest-fnids hello-page hours-since indented-code
  insert-sorted load-table load-tables log-request logfile-name login-form
  login-handler login-page logout-user md-from-form minutes-since n-of
  new-bgthread new-hspace next-parabreak noisy-each parse-date parse-format
  parse-time ppr-call ppr-progn pr-escaped precomputable-tagopt prompt-page
  rand-choice rand-elt rand-key rand-string read-app read-table reassemble-args
  reinsert-sorted rem-app respond-err run-app safe-load-table save-optime
  save-table set-pw single-input space-eaters start-tag static-filetype tag-if
  tag-options text-rows text-type timed-fnid tree-subst unique-id url-for
  user-exists username-taken valid-date vars-form view-app w/link-if
  when-umatch when-umatch/r write-app write-spaced write-table)
Just from this, I see names that work well with hyphens: I can't parse createacct on first glance, hourssince & dayssince are awkward with the two S characters, responderr looks like "responder" with an extra R, pprprogn has too many similar letters jammed together, logfilename could be parsed as either "name of the logfile" or "log the filename", nof is just weird, etc. But there are names that don't strictly need hyphens: I think endtag, filltable, getuser, loadtable, loadtables, randkey, and others look fine, which indicates to me that the issue really is just aesthetic.

-----

4 points by fallintothis 5913 days ago | link | parent | on: IP Source Domain Bug

In the style of my previous response, the offending code from news.arc:

  (def parse-site (url)
    (rev (tokens (cadr (tokens url [in _ #\/ #\?])) #\.)))

  (defmemo sitename (url)
    (and (valid-url url)
         (let toks (parse-site (rem #\space url))
           (if (isa (saferead (car toks)) 'int)
               (tostring (prall toks "" "."))
               (let (t1 t2 t3 . rest) toks  
                 (if (and (~in t3 nil "www")
                          (or (mem t1 multi-tld-countries*) 
                              (mem t2 long-domains*)))
                     (+ t3 "." t2 "." t1)
                     (and t2 (+ t2 "." t1))))))))
In particular,

  (tostring (prall toks "" "."))
will generate a reversed IP because toks is already reversed:

  arc> (= toks (parse-site "http://74.125.95.132/"))
  ("132" "95" "125" "74")
  arc> (isa (saferead (car toks)) 'int)
  t
  arc> (tostring (prall toks "" "."))
  "132.95.125.74"

-----

3 points by profquail 5913 days ago | link

Thanks for your detective work fallintothis!

-----

2 points by pg 5912 days ago | link

oops, fixed

-----

2 points by fallintothis 5916 days ago | link | parent | on: No faster, and call for benchmarks

An easy source of ideas is, of course, the Benchmarks Game: http://shootout.alioth.debian.org/. Someone would still need to implement them, but there are plenty of Lisp examples (e.g., http://shootout.alioth.debian.org/u32q/lisp.php).

-----

2 points by fallintothis 5916 days ago | link

Another benchmark ported from an SBCL version (http://shootout.alioth.debian.org/u32q/benchmark.php?test=pi...), pidigits:

  (= digits-per-line*     10
     default-stop-digits* 1000)

  (def make-digit-generator ()
    (with (zq 1 zr 0 zt 1 k 0 4k+2 2 2k+1 1)
      (with (extract [trunc:/ (+ (* zq _) zr) zt]
             comp    (fn (aq ar at bq br bt)
                       (= zq (* aq bq)
                          zr (+ (* aq br) (* ar bt))
                          zt (* at bt))))
        (fn ()
          (let y (extract 3)
            (until (is y (extract 4))
              (comp zq zr zt (++ k) (++ 4k+2 4) (++ 2k+1 2))
              (= y (extract 3)))
            (comp 10 (* -10 y) 1 zq zr zt)
            y)))))

  (def spigot ((o digits default-stop-digits*))
    (with (digits-printed 0
           next-digit     (make-digit-generator))
      (while (> digits 0)
        (if (>= digits digits-per-line*)
            (do (repeat digits-per-line* (pr (next-digit)))
                (++ digits-printed digits-per-line*))
            (do (repeat digits (pr (next-digit)))
                (sp (- digits-per-line* digits))
                (++ digits-printed digits)))
        (prn "\t:" digits-printed)
        (-- digits digits-per-line*))))

  (= benchmark time:spigot)
Then

  Use (quit) to quit, (tl) to return here after an interrupt.
  arc> (load "pidigits.arc")
  nil
  arc> (benchmark)
  3141592653      :10
  5897932384      :20
  6264338327      :30
  9502884197      :40
  1693993751      :50
  0582097494      :60
  4592307816      :70
  4062862089      :80
  9862803482      :90
  5342117067      :100
  9821480865      :110
  1328230664      :120
  7093844609      :130
  5505822317      :140
  2535940812      :150
  8481117450      :160
  2841027019      :170
  3852110555      :180
  9644622948      :190
  9549303819      :200
  6442881097      :210
  5665933446      :220
  1284756482      :230
  3378678316      :240
  5271201909      :250
  1456485669      :260
  2346034861      :270
  0454326648      :280
  2133936072      :290
  6024914127      :300
  3724587006      :310
  6063155881      :320
  7488152092      :330
  0962829254      :340
  0917153643      :350
  6789259036      :360
  0011330530      :370
  5488204665      :380
  2138414695      :390
  1941511609      :400
  4330572703      :410
  6575959195      :420
  3092186117      :430
  3819326117      :440
  9310511854      :450
  8074462379      :460
  9627495673      :470
  5188575272      :480
  4891227938      :490
  1830119491      :500
  2983367336      :510
  2440656643      :520
  0860213949      :530
  4639522473      :540
  7190702179      :550
  8609437027      :560
  7053921717      :570
  6293176752      :580
  3846748184      :590
  6766940513      :600
  2000568127      :610
  1452635608      :620
  2778577134      :630
  2757789609      :640
  1736371787      :650
  2146844090      :660
  1224953430      :670
  1465495853      :680
  7105079227      :690
  9689258923      :700
  5420199561      :710
  1212902196      :720
  0864034418      :730
  1598136297      :740
  7477130996      :750
  0518707211      :760
  3499999983      :770
  7297804995      :780
  1059731732      :790
  8160963185      :800
  9502445945      :810
  5346908302      :820
  6425223082      :830
  5334468503      :840
  5261931188      :850
  1710100031      :860
  3783875288      :870
  6587533208      :880
  3814206171      :890
  7766914730      :900
  3598253490      :910
  4287554687      :920
  3115956286      :930
  3882353787      :940
  5937519577      :950
  8185778053      :960
  2171226806      :970
  6130019278      :980
  7661119590      :990
  9216420198      :1000
  time: 94562 msec.
  nil
Versus the same run in GNU clisp with the Shootout's SBCL code:

  > (time (spigot 1000))

  [OUTPUT ELIDED]

  Real time: 1.022299 sec.
  Run time: 0.888055 sec.
  Space: 104310256 Bytes
  GC: 133, GC time: 0.420025 sec.
  NIL
Their outputs were the same, so the Arc program seems to be working (to say nothing of its optimality; I basically did a straight port). This benchmark's fun if only because you get to watch pi being calculated before your eyes. Nifty algorithm.

-----

2 points by conanite 5909 days ago | link

This is an awesome reference, thanks. I'll be using a few of these. The pi calculation uncovered a rainbow weakness: rainbow relies on java "long" integers for 'int types; but these are 64-bit signed integers and the algorithm fails at the 5th digit. So I'll need to think of a way to incorporate arbitrary-precision maths before I can run this benchmark. One thing is certain: using java's BigXXX family of numeric types is going to hurt.

-----

1 point by fallintothis 5916 days ago | link

For instance, here's a (pretty direct) port of the SBCL nbody benchmark (http://shootout.alioth.debian.org/u32q/benchmark.php?test=nb...):

  (= pi             (* 4 (atan 1))
     days-per-year* 365.24d0
     solar-mass*    (* 4d0 pi pi))

  (def make-body (x y z vx vy vz mass)
    (obj x x y y z z vx vx vy vy vz vz mass mass))

  (= jupiter* (make-body 4.84143144246472090d0
                         -1.16032004402742839d0
                         -1.03622044471123109d-1
                         (* 1.66007664274403694d-3 days-per-year*)
                         (* 7.69901118419740425d-3 days-per-year*)
                         (* -6.90460016972063023d-5  days-per-year*)
                         (* 9.54791938424326609d-4 solar-mass*)))

  (= saturn* (make-body 8.34336671824457987d0
                        4.12479856412430479d0
                        -4.03523417114321381d-1
                        (* -2.76742510726862411d-3 days-per-year*)
                        (* 4.99852801234917238d-3 days-per-year*)
                        (* 2.30417297573763929d-5 days-per-year*)
                        (* 2.85885980666130812d-4 solar-mass*)))

  (= uranus* (make-body 1.28943695621391310d1
                        -1.51111514016986312d1
                        -2.23307578892655734d-1
                        (* 2.96460137564761618d-03 days-per-year*)
                        (* 2.37847173959480950d-03 days-per-year*)
                        (* -2.96589568540237556d-05 days-per-year*)
                        (* 4.36624404335156298d-05 solar-mass*)))

  (= neptune* (make-body 1.53796971148509165d+01
                         -2.59193146099879641d+01
                         1.79258772950371181d-01
                         (* 2.68067772490389322d-03 days-per-year*)
                         (* 1.62824170038242295d-03 days-per-year*)
                         (* -9.51592254519715870d-05 days-per-year*)
                         (* 5.15138902046611451d-05 solar-mass*)))

  (= sun* (make-body 0.0d0 0.0d0 0.0d0 0.0d0 0.0d0 0.0d0 solar-mass*))

  (def apply-forces (a b dt)
    (withs (dx    (- (a 'x) (b 'x))
            dy    (- (a 'y) (b 'y))
            dz    (- (a 'z) (b 'z))
            d     (sqrt (+ (expt dx 2) (expt dy 2) (expt dz 2)))
            mag   (/ dt (expt d 3))
            dxmag (* dx mag)
            dymag (* dy mag)
            dzmag (* dz mag))
      (-- (a 'vx) (* dxmag (b 'mass)))
      (-- (a 'vy) (* dymag (b 'mass)))
      (-- (a 'vz) (* dzmag (b 'mass)))
      (++ (b 'vx) (* dxmag (a 'mass)))
      (++ (b 'vy) (* dymag (a 'mass)))
      (++ (b 'vz) (* dzmag (a 'mass)))))

  (def advance (solar-system dt)
    (on a solar-system
      (for i (+ index 1) (- (len solar-system) 1)
        (apply-forces a (solar-system i) dt)))
    (each b solar-system
      (++ (b 'x) (* dt (b 'vx)))
      (++ (b 'y) (* dt (b 'vy)))
      (++ (b 'z) (* dt (b 'vz)))))

  (def energy (solar-system)
    (let e 0.0d0
      (on a solar-system
        (++ e (* 0.5d0
                 (a 'mass)
                 (+ (expt (a 'vx) 2)
                    (expt (a 'vy) 2)
                    (expt (a 'vz) 2))))
        (for i (+ index 1) (- (len solar-system) 1)
          (withs (b  (solar-system i)
                  dx (- (a 'x) (b 'x))
                  dy (- (a 'y) (b 'y))
                  dz (- (a 'z) (b 'z))
                  d  (sqrt (+ (expt dx 2) (expt dy 2) (expt dz 2))))
            (-- e (/ (* (a 'mass) (b 'mass)) d)))))
      e))

  (def offset-momentum (solar-system)
    (with (px 0.0d0
           py 0.0d0
           pz 0.0d0)
      (each p solar-system
        (++ px (* (p 'vx) (p 'mass)))
        (++ py (* (p 'vy) (p 'mass)))
        (++ pz (* (p 'vz) (p 'mass))))
      (= ((car solar-system) 'vx) (/ (- px) solar-mass*)
         ((car solar-system) 'vy) (/ (- py) solar-mass*)
         ((car solar-system) 'vz) (/ (- pz) solar-mass*))))

  (def nbody (n)
    (let solar-system (list sun* jupiter* saturn* uranus* neptune*)
      (offset-momentum solar-system)
      (prn (energy solar-system))
      (repeat n (advance solar-system 0.01d0))
      (prn (energy solar-system))
      nil))
I didn't have the patience to wait for Arc to finish the benchmark's n = 50,000,000 (gives you an idea of how well it performs!), but on smaller values it seems correct.

  arc> (load "nbody.arc")
  nil
  arc> (time (nbody 50000))
  -0.16907516382852447
  -0.16907807065934496
  time: 30905 msec.
  nil
The reference implementation, run from a GNU clisp REPL (though I suppose I should use SBCL for a fairer time comparison, I'm just interested in the accuracy of the Arc results with this run):

  > (time (nbody 50000))
  -0.169075164
  -0.169078071
  Real time: 37.575706 sec.
  Run time: 32.862053 sec.
  Space: 374412048 Bytes
  GC: 477, GC time: 1.836092 sec.
  NIL

-----


The offending code from news.arc:

  (def parse-site (url)
    (rev (tokens (cadr (tokens url [in _ #\/ #\?])) #\.)))

  (defmemo sitename (url)
    (and (valid-url url)
         (let toks (parse-site (rem #\space url))
           (if (isa (saferead (car toks)) 'int)
               (tostring (prall toks "" "."))
               (let (t1 t2 t3 . rest) toks  
                 (if (and (~in t3 nil "www")
                          (or (mem t1 multi-tld-countries*) 
                              (mem t2 long-domains*)))
                     (+ t3 "." t2 "." t1)
                     (and t2 (+ t2 "." t1))))))))
The isa test is thrown off by the port number

  arc> (parse-site "http://99.60.16.192:8080/")
  ("192:8080" "16" "60" "99")
  arc> (isa (saferead "192:8080") 'int)
  nil
which leads down the first else-clause of sitename, where

  arc> (and (~in t3 nil "www")
            (or (mem t1 multi-tld-countries*)
                (mem t2 long-domains*)))
  nil
leads to

  arc> (and t2 (+ t2 "." t1))
  "16.192:8080"

-----

2 points by pg 5912 days ago | link

thanks, fixed

-----


The way you get a REPL circa mzscheme 4 is to pass -i, but

  -i, --repl : Run interactive read-eval-print loop; implies -v
  -v, --version : Show version
and they changed the -m flag to mean

  -m, --main : Call `main' with command-line arguments, print results
So, using -i will still display the banner, and there doesn't seem to be an option to mute it.

  $ mzscheme -if as.scm
  Welcome to MzScheme v4.1.5 [3m], Copyright (c) 2004-2009 PLT Scheme Inc.
  Use (quit) to quit, (tl) to return here after an interrupt.
  arc> ^Cuser break

   === context ===
  ~/arc/ac.scm:1141:4

  > (tl)
  Use (quit) to quit, (tl) to return here after an interrupt.
  arc>

-----

1 point by conanite 5920 days ago | link

cool, thanks, that's exactly it.

-----

More