Arc Forumnew | comments | leaders | submit | zck's commentslogin
3 points by zck 3483 days ago | link | parent | on: How Lisp is going to save the world!

Make sure to click on the blue flashing text; they're hyperlinks. Arc is discussed in the "Brevity Guild" section; the first of the three new Lisp guilds.

-----

2 points by zck 3488 days ago | link | parent | on: Multiple Return Values

I'll explain a little further, because Arc's let is unusual. Unlike most Lisps, the variable-value pairs are not themselves enclosed in parentheses.

In this code:

    (let (latitude longitude) (func1 a b c)
We're not binding latitude to the value of longitude, but binding that whole thing to the return value of (func1 a b c).

A simpler example:

    (let (name score) '("Steve Wiebe" 1064500)
      (prn name " was the first person to score over a million points in Donkey Kong, with a score of " score))
This prints:

    Steve Wiebe was the first person to score over a million points in Donkey Kong, with a score of 1064500

-----

3 points by jsgrahamus 3488 days ago | link

And, of course, the "regular" form of arc has no parentheses:

  arc> (let hat 5 (prn "hat = " hat))
  hat = 5
  "hat = "
  arc>

-----

2 points by jsgrahamus 3488 days ago | link

I thought that let looked odd, because I thought that with a let in arc, you had 1 variable/value pair. Thanks, zck, for pointing out the difference. And thanks, akkartik, for repeatedly telling me this.

-----

2 points by waterhouse 3485 days ago | link

The corresponding macro in Common Lisp has an 18-character name.

  ; SBCL
  * (destructuring-bind (x y) '(1 2) (+ x y))
  3
  ; Arc
  arc> (let (x y) '(1 2) (+ x y))
  3

-----

2 points by zck 3490 days ago | link | parent | on: Odd errors

Oh, here's what's going on. Alist is already a function (https://arclanguage.github.io/ref/predicates.html#alist). So redefining it makes code using it fail.

If you restart Arc, and rename the variable to something else (e.g., a-list), you won't see this.

-----

1 point by akkartik 3490 days ago | link

Ah, thanks for spotting that so quickly. Arc warns when we replace a function with another. Perhaps it should also do so when we replace a function with anything else?

Edit 28 minutes later: this is now done.

  arc> (= alist t)
  *** redefining alist
  t
https://github.com/arclanguage/anarki/commit/b7d17d8c13

Let me know if y'all run into any problems. Unit tests pass, but we can always add more..

-----

2 points by jsgrahamus 3490 days ago | link

Will anarki run on Windows?

-----

1 point by akkartik 3490 days ago | link

I did see it running momentarily on Windows a few weeks ago: http://arclanguage.org/item?id=19458. It might have a few issues, but if you report them I'll try to fix them.

-----

2 points by jsgrahamus 3490 days ago | link

Thanks, zck!

-----

1 point by zck 3490 days ago | link

No problem! Glad to help.

-----

2 points by zck 3491 days ago | link | parent | on: Unit-test.arc 1.0 incoming

Interesting. I like the consistency. I don't love how it makes the most common case (I think the no-setup case is most common) and adds more code to it.

Maybe I can come up with a simpler, less awful thing.

Perhaps:

    (suite foo (setup a 1
                      b 2)
           (test must-bar
                 (assert-same b (+ a a))))
It does seem relatively simple. Hrm.

-----

2 points by akkartik 3491 days ago | link

I'm kinda growing to like my idea the more I think about it. You're right that it adds 3 characters to the common case, but lisp has a long tradition of empty parens in various places. Saving characters shouldn't be a high priority, IMO. Paul Graham's notion of conciseness counts tokens, not characters.

But yeah, happy to see what other ideas we can come up with. I think the setup keyword above is worse; lisps don't tend to have keywords that aren't functions or macros. Then again, test is already a keyword that's not a function.. Hmm, I like it better if you indent it like this:

  (suite foo
         (setup a 1
                b 2)
         (test must-bar
               (assert-same b (+ a a))))
The benefit of this approach is that it makes the syntax seem extensible. It's obvious how new features should be added.

Ok, I could live with this :)

-----


You can use n-of:

    arc> (n-of 3 "hi")
    ("hi" "hi" "hi")
Documentation here: https://arclanguage.github.io/ref/list.html#n-of

Although be careful -- n-of will evaluate your default value multiple times. This could be bad if it either takes a while or does IO:

    arc> (n-of 3 (rand 10))
    (7 8 1)

-----

3 points by jsgrahamus 3491 days ago | link

Thanks, zck.

Didn't know there was a built-in function, so tried creating one on my own.

  arc> (def make-list (size val)
         (let alist nil
           (def make-list2 (alist size val)
             (if (is size 0)
               alist
               (make-list2 (cons val alist) (- size 1) val)))
           (make-list2 alist size val)))
  *** redefining make-list
  #<procedure: make-list>
  arc> (make-list 5 -1)
  *** redefining make-list2
  (-1 -1 -1 -1 -1)
  arc>
Comments?

-----

2 points by jsgrahamus 3491 days ago | link

Shouldn't be redefining, right?

This seems better:

  arc> (def make-list (alist size val)
         (if (is size 1)
           (cons val alist)
           (make-list (cons val alist) (- size 1) val)))
  #<procedure: make-list>
  arc> (make-list nil 5 -1)
  (-1 -1 -1 -1 -1)
  arc> (make-list nil 11 -1)
  (-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1)
  arc> (make-list nil 111 -1)
  (-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1   -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1   -1 -1 -1 -1 -1
   -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1   -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1   -1 -1 -1 -1 -1
   -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1   -1 -1 -1 -1)
  arc>
But I shouldn't have to invoke make-list with a nil list to begin with.

-----

2 points by zck 3491 days ago | link

> But I shouldn't have to invoke make-list with a nil list to begin with.

You can use a helper function:

    (def make-list (size val)
         (make-list-helper nil size val))
    
    (def make-list-helper (alist size val)
         (if (is size 1)
             (cons val alist)
           (make-list-helper (cons val alist) (- size 1) val)))
But this clutters up the namespace. We can use a local helper function to move make-list-helper inside the body of make-list, and wrap it in afn to make it able to recurse.

    (def make-list (size val)
         (let helper (afn (alist size val)
                          (if (is size 1)
                              (cons val alist)
                            (self (cons val alist) (- size 1) val)))
              (helper nil size val)))

-----

2 points by akkartik 3491 days ago | link

Yes you don't need the nil argument. Since make-list returns a list, do the conses on the way out of recursive calls rather than on the way in:

  (def make-list (size val)
    (if (> size 0)
      (cons val
            (make-list (- size 1) val))))
This is identical to your version, except I dropped the now-unnecessary base case (if now generates the initial list at the bottom-most recursive call) and moved the cons outside the call to make-list.

-----

2 points by jsgrahamus 3491 days ago | link

Great. Still wrapping my head around recursion.

Thanks.

-----

1 point by akkartik 3491 days ago | link

I'm surprised by the redefinition warnings. They don't happen for me. Perhaps you have some of your own code being loaded? Or maybe you have an old version? (Though I don't remember make-list ever being a thing.)

-----

2 points by jsgrahamus 3491 days ago | link

I'm caught. Still using the old version of arc 3.1 on Windows 7 with racket.

-----

2 points by jsgrahamus 3490 days ago | link

How did you know that (n-of) was a function? Where is there a list of all the functions in arc?

-----

1 point by akkartik 3490 days ago | link

Discoverability is a perennial issue. Arc 3.1 is pretty comprehensively documented at https://arclanguage.github.io/ref (even if it's a lot to read). n-of is in the page on list operations: http://arclanguage.github.io/ref/list.html Unfortunately changes to Arc 3.1 in Anarki are harder to find; nobody's gotten around to building a copy of Ken Shirriff's reference for Anarki. One good place to the first order is the https://github.com/arclanguage/anarki/tree/master/CHANGES directory on Github.

-----

2 points by zck 3491 days ago | link | parent | on: ASK: Emacs inferior-arc on Windows

I'm a big Emacs fan. I'll check this out when I'm home.

-----

3 points by archie 3487 days ago | link

No answer, huh? It's really an annoying problem...

-----

2 points by zck 3487 days ago | link

Ah, sorry I missed that. Right now (on Linux), I'm not even getting as far as you are. Upon M-x run-arc, I'm getting this error:

    emacs: /home/zck/programs/arc/arc3.1/arc.sh: Exec format error

    Process arc exited abnormally with code 126

-----

2 points by archie 3487 days ago | link

Hmmm, interesting. But I don't have any problem on my linux machine, only Windows is problematic. Here's mine .emacs setup on linux:

  (add-to-list 'load-path "~/.racket/6.4/pkgs/anarki/extras")
  (autoload 'arc-mode "arc"
    "Major mode for editing Arc." t)
  (add-to-list 'auto-mode-alist '("\\.arc$" . arc-mode))
  (setq arc-program-name "~/.racket/6.4/pkgs/anarki/arc -n")
  (add-hook 'inferior-arc-mode-hook
  	    (lambda ()
	      (set (make-local-variable 'comint-use-prompt-regexp) t)
	      (set (make-local-variable 'comint-prompt-read-only) t)))

-----

1 point by zck 3485 days ago | link

Oh, weird. Then I'm less able to help you, as I don't have a Windows computer. Sorry about that.

-----

1 point by akkartik 3485 days ago | link

Are you able to get inferior-lisp working on Windows? Maybe the appropriate forum could help with any gotchas there?

If you do figure this out don't forget to come back and tell us!

-----

2 points by zck 3495 days ago | link | parent | on: Unit-test.arc 1.0 incoming

`hg checkout run-test` will do it.

If you want to view all branches, `hg branches`. There are some old ones I need to finish and merge back in. To view the current branch, `hg branch`.

Or if you want to look at it online, the link above (https://bitbucket.org/zck/unit-test.arc/src/8b9dbe91702c3866...) should take you to the right branch. (Edit: you'll know you're on the right branch if the second code block runs tests with (test), not (run-suite))

-----

1 point by akkartik 3495 days ago | link

Ah, thanks. Crazy that https://www.mercurial-scm.org/wiki/GitConcepts doesn't mention hg checkout.

-----

2 points by akkartik 3494 days ago | link

I just tried running the 'run-test' branch with the Anarki tests, but I get an error. Is it expected to be backwards-incompatible?

-----

2 points by zck 3493 days ago | link

It's not backwards compatible. Hence me trying to get feedback before pushing the 1.0.

The specific backwards incompatibility (I assume you got "We can't parse this as a suite body") is moving from this format for the tests:

    (suite suite-name
           test-name (test-body))
to the format you suggested last year:

    (suite suite-name
           (test test-name (test-body)))
I don't think supporting both ways of writing tests is useful. I'm also planning on migrating the anarki tests when I roll out the 1.0. Actually, I could get started on a branch even before. That'd be something to do.

-----

1 point by akkartik 3493 days ago | link

Ah, I'd forgotten :)

Yeah, no reason to be compatible. I was just confused. I'll migrate the tests to the new format, and update Anarki publicly once you release 1.0.

-----

2 points by zck 3492 days ago | link

If you start doing some of the migration work, push the in-progress stuff to a branch and I'll help work on it. I'll do the same if I get to it before you. Thanks.

-----

2 points by akkartik 3491 days ago | link

I spent a few minutes trying to build an automatic script to upgrade our tests -- and found a bug in Arc's serialize/unserialize (my fault) :)

https://github.com/arclanguage/anarki/commit/9efd58992d

What's the equivalent of (run-all-suites) in 1.0? I didn't see this covered in the Readme.

Other than that my script seems to be barfing on nested suites at the moment. I'll continue working on it tomorrow.

-----

2 points by zck 3491 days ago | link

Oh, fancy writing a script to do the upgrade. It'd be cool to see it.

You can run all tests with (test). I should add that to the instructions, thanks.

-----

2 points by akkartik 3491 days ago | link

This must be the most fun thing on my radar right now, because I got to it first thing this morning :)

  ; translate.arc
  (def translate (expr)
    (accum acc
      (translate-2 expr acc)))

  (def translate-2 (expr acc)
    (if (atom expr)
          (acc expr)
        (is car.expr 'suite)
          (do (acc 'suite)
              (let (suite-name . suite-body)  cdr.expr
                (acc suite-name)
                (translate-suite-body suite-body acc)))
        (is car.expr 'suite-w/setup)
          (do (acc 'suite-w/setup)
              (let (suite-name suite-setup . suite-body)  cdr.expr
                (acc suite-name)
                (acc suite-setup)
                (translate-suite-body suite-body acc)))
        'else
          (map acc expr)))

  (def translate-suite-body (suite-body acc)
    (if suite-body
      (if (acons car.suite-body)
        ; nested suite
        (let (nested-suite . rest) suite-body
          (acc (accum acc2
                  (translate-2 nested-suite acc2)))
          (translate-suite-body rest acc))
        ; test name must be atomic
        (let (test-name test-body . rest)  suite-body
          (acc `(test ,test-name ,test-body))
          (translate-suite-body rest acc)))))

  ; bootstrap tests for a test harness :)
  ; suite with tests
  (assert:iso '(suite a (test t1 b1) (test t2 b2))
              (translate '(suite a t1 b1 t2 b2)))

  ; suite with tests and nested suites
  (assert:iso '(suite a (test t1 b1) (suite s2 (test t3 b3)) (test t2 b2))
              (translate '(suite a t1 b1 (suite s2 t3 b3) t2 b2)))

  ; suite with setup and tests
  (assert:iso '(suite-w/setup a (x 1 y 2) (test t1 b1) (test t2 b2))
              (translate '(suite-w/setup a (x 1 y 2) t1 b1 t2 b2)))

  ; suite with setup and tests and nested suites
  (assert:iso '(suite-w/setup a (x 1 y 2) (test t1 b1) (suite s2 (test t3 b3)) (test t2 b2))
              (translate '(suite-w/setup a (x 1 y 2) t1 b1 (suite s2 t3 b3) t2 b2)))

  ; run
  (each f cdr.argv
    (prn f)
    (fromfile string.f
      (tofile (+ string.f ".2")
        (each expr (drain:read)
          (let out translate.expr
            (ppr out))))))

Run it like so:

  $ arc translate.arc *.t lib/*.t lib/tests/*
I haven't committed it anywhere yet because I'm not too happy with the state of Anarki's pretty-printer. Would you mind if I change the indentation style for suites and tests in Anarki? I was thinking something like this:

  (suite atom
    (test includes-int (assert-t (atom 3)))
    (test includes-float
      (assert-t (atom 3.14159)))
    (test includes-exact (assert-t (atom 3/16)))
    (test includes-symbol (assert-t (atom 'a)))
    (test includes-char (assert-t (atom #\a)))
    (test includes-string
      (assert-t (atom "hello")))
    (test includes-nil (assert-t (atom nil)))
    (test excludes-list
      (assert-nil (atom '(1 2 3))))
    (test excludes-table
      (assert-nil (atom (obj a 1 b 2))))
    (test excludes-tagged-types
      (assert-nil (atom (annotate 'foo 34)))))
..rather than this current output:

  (suite atom
         (test includes-int (assert-t (atom 3)))
         (test includes-float
               (assert-t (atom 3.14159)))
         (test includes-exact (assert-t (atom 3/16)))
         (test includes-symbol (assert-t (atom 'a)))
         (test includes-char (assert-t (atom #\a)))
         (test includes-string
               (assert-t (atom "hello")))
         (test includes-nil (assert-t (atom nil)))
         (test excludes-list
               (assert-nil (atom '(1 2 3))))
         (test excludes-table
               (assert-nil (atom (obj a 1 b 2))))
         (test excludes-tagged-types
               (assert-nil (atom (annotate 'foo 34)))))

-----

2 points by akkartik 3491 days ago | link

All done:

  atom:  	10 tests,  	0 nested suites.
  memtable:  	5 tests,  	0 nested suites.
  do:  	2 tests,  	0 nested suites.
  for:  	3 tests,  	0 nested suites.
  ssyntax:  	13 tests,  	0 nested suites.
  ...
  strings:  	0 tests,  	15 nested suites.
      trim:  	4 tests,  	0 nested suites.
      tokens:  	2 tests,  	0 nested suites.
      endmatch:  	4 tests,  	0 nested suites.
      subst:  	3 tests,  	0 nested suites.
  ...
  types:  	0 tests,  	3 nested suites.
      coerce:  	2 tests,  	1 nested suite.
          strings:  	9 tests,  	5 nested suites.
              numbers:  	6 tests,  	3 nested suites.
                  rational-rounds-with-unused-base-arg:  	6 tests,  	0 nested suites.
                  rational-rounds-to-even:  	6 tests,  	0 nested suites.
                  float-rounds-to-even:  	6 tests,  	0 nested suites.
              characters:  	4 tests,  	0 nested suites.
              coercions-to-same-type:  	3 tests,  	0 nested suites.
              string->num:  	18 tests,  	0 nested suites.
              string->int:  	13 tests,  	0 nested suites.
      type:  	15 tests,  	0 nested suites.
      annotation:  	4 tests,  	0 nested suites.
  Suite module: all 3 tests passed!
  Suite special-syntax: all 4 tests passed!
  Suite html: the single test passed!
  There are no tests directly in suite special-forms.
      Suite special-forms.function-definition: all 22 tests passed!
      Suite special-forms.if: all 5 tests passed!
      Suite special-forms.quasiquote: all 15 tests passed!
      Suite special-forms.quote: all 3 tests passed!
      Suite special-forms.assign: all 3 tests passed!
  There are no tests directly in suite types.
      Suite types.coerce: all 2 tests passed!
          Suite types.coerce.strings: all 9 tests passed!
              Suite types.coerce.strings.numbers: all 6 tests passed!
                  Suite types.coerce.strings.numbers.rational-rounds-with-unused-base-arg: all 6 tests passed!
                  Suite types.coerce.strings.numbers.rational-rounds-to-even: all 6 tests passed!
                  Suite types.coerce.strings.numbers.float-rounds-to-even: all 6 tests passed!
              Suite types.coerce.strings.characters: all 4 tests passed!
              Suite types.coerce.strings.coercions-to-same-type: all 3 tests passed!
              Suite types.coerce.strings.string->num: all 18 tests passed!
              Suite types.coerce.strings.string->int: all 13 tests passed!
      Suite types.type: all 15 tests passed!
      Suite types.annotation: all 4 tests passed!
  Suite len: all 3 tests passed!
  Suite bracket-fn: all 3 tests passed!
  ...

  Yay! All 606 tests passed!

-----

2 points by zck 3546 days ago | link | parent | on: ASK: Best way to learn Lisp?

What are your goals? Although the people here are pretty helpful, there isn't much out there, resource-wise, for Arc. This is both in terms of documentation and libraries.

Are you interested in hacking a Lisp itself? Then Arc is a good choice. Are you interested in learning a Lisp you can find companies using? Arc is suboptimal.

-----

3 points by kinnard 3546 days ago | link

I suppose I'm learning lisp for more idealistic/philosophical rather than professional reasons. Though it seems there are compelling professional outcomes nonetheless.

-----

2 points by zck 3545 days ago | link

If you're interested in Arc, sure, go for it. It's a lot of fun, and the things it does are very well designed.

If you want suggestions as to which Lisp might fit your philosophical ideals, it would help to talk about what the ideals are.

-----

1 point by kinnard 3544 days ago | link

I'd describe myself as a bottom-up thinker. [But I'm unopposed to the description "top-down" because . . . "which way is up?"] I like to work from axioms to outcomes. I'm frustrated under other conditions.

-----

2 points by hjek 3539 days ago | link

MIT have some good freely available videos on Lisp, where they go through a lot of philosophical stuff: https://archive.org/details/mit_ocw_sicp

-----

2 points by zck 3565 days ago | link | parent | on: ASK: Is arc better than clojure?

Clojure also has a pretty cool way to not have to call (uniq) by hand. If, inside a backquote, you append a # to a symbol, clojure will replace that variable with a gensym. And it'll use the same gensym every time you use that variable in the backquoted form.

Here's the source for `and` (https://github.com/clojure/clojure/blob/clojure-1.7.0/src/cl...):

    (defmacro and
      "Evaluates exprs one at a time, from left to right. If a form
      returns logical false (nil or false), and returns that value and
      doesn't evaluate any of the other expressions, otherwise it returns
      the value of the last expr. (and) returns true."
      {:added "1.0"}
      ([] true)
      ([x] x)
      ([x & next]
       `(let [and# ~x]
          (if and# (and ~@next) and#))))
See how it uses and#, but it doesn't capture the variable and?

I'm not entirely sure how you would capture a variable (e.g., Arc's "aand"); if you try to, clojure errors by default. There's probably some way, but I don't know offhand.

-----

3 points by rocketnia 3562 days ago | link

This StackOverflow answer ends with "I'd recommend a real anaphoric macro" and gives an example: http://stackoverflow.com/questions/9764377/how-to-avoid-anap...

Based on that, I found this way to write aand, which seems to work at http://www.tutorialspoint.com/execute_clojure_online.php:

  (defmacro aand
    ([] true)
    ([x] x)
    ([x & next]
     `(let [~'it ~x]
        (if ~'it (aand ~@next) ~'it))))
  
  (prn (aand "woo" (list it it) (list it it it)))
It looks like Clojure macros can capture variables in the other direction too, like Arc:

  (defmacro capture-it
    ([] 'it))
  
  (prn (let [it "woo"] (capture-it)))

-----

2 points by zck 3566 days ago | link | parent | on: ASK: Is arc better than clojure?

It would be nice, but I have a hard time recommending it to anyone with no releases since 2009.

Perhaps Anarki would be something to recommend. But that's not really being driven forwards either. Any changes are the result of design by committee, which doesn't tend to lead to great design.

-----

2 points by akkartik 3566 days ago | link

It doesn't seem fair to call Anarki design by committee. It's closer to a small number of scatterbrained people who periodically have a shiny new idea and add it in in anarchist fashion. Maybe design by Dory? http://www.imdb.com/character/ch0003708 :)

-----

1 point by zck 3565 days ago | link

You're right. Perhaps I'd be better off saying "no single vision motivating changes".

-----

1 point by kinnard 3566 days ago | link

I wonder why PG decided to go hands off.

-----

More