Arc Forumnew | comments | leaders | submitlogin
1 point by evanrmurphy 2 hours ago | link | parent | on: Trivial arc webapp

Is this served online somewhere or only accessible via download?
1 point by prestonbriggs 13 hours ago | link | parent | on: The use of + for non-numbers

I wouldn't do anything for a speed boost at this stage. Premature optimization and all that.

Preston

1 point by d0m 14 hours ago | link | parent | on: ([_] 1) vs ((fn (x) x) 1)

Oh my ... thank you. That explains a lot of things :p
1 point by garply 15 hours ago | link | parent | on: The use of + for non-numbers

Regarding your second suggestion, we could also use . instead of &, as that's what Perl and PHP do - feels a little more natural to me. But . might cause me a little mental friction in differentiating between the different uses of . in (. "a" "b") and (do (= a '(1 2)) a.0).

To be honest, I'm still not crazy about the idea simply because I don't need the speed boost and + doesn't seem to cause me to use extra mental cycles when reading my code. I'd be open to it though if the community really wanted it that way.

We could vote and also ask PG what he thinks and then make a decision.

1 point by waterhouse 16 hours ago | link | parent | on: ([_] 1) vs ((fn (x) x) 1)

[_] = (fn (x) (x)), not (fn (x) x).

  [idfn _] = (fn (x) x).
  ([idfn _] 1) -> 1.
1 point by waterhouse 16 hours ago | link | parent | on: The use of + for non-numbers

With regard to (2), to destructively append the list '(1 2 3) to xs, you can:

  (zap join xs '(1 2 3))
"zap join" is several characters longer than ++, but zap has general utility.

I use the string function to concatenate strings. It seems to work identically to +, as long as the first argument is a string. I do give heterogeneous arguments to string usually, and I like seeing that they will clearly be coerced into a string.

I have a couple of ideas.

1. It would be little problem for me if Arc provided + as is and provided a "plus" function that worked only on numbers and allowed me to simply go (= + plus) and proceed normally. Unfortunately, that would break all the functions in arc.arc and so forth that use + to concatenate lists (which includes, among other things, the setforms function, which is used in expand=). It would be really nice if one could "freeze" the variable references in those functions, so that changing the global value of + wouldn't change what "+" in the bodies of those functions referred to.

2. If you use concatenation so much, perhaps we could allocate an ssyntax character for concatenation. & is currently used for andf (experiment with ssexpand to see). We could boot out that usage, or perhaps have "&&" become andf. Good/bad idea? (Precedent: my memory tells me the TI-89 uses & for string concatenation.)

2 points by waterhouse 17 hours ago | link | parent | on: Ask: PG and Anti-OO

Given the way I defined a Bank-Account, you could implement this rather simply:

  (def deposit (x . args)
    (apply x 'deposit args))
Or, with akkartik's implementation, which I agree is nicer and better:

  (def deposit (x . args)
    (apply x!deposit args))
And you could make another "object" and give it a distinct 'deposit "method" and it would work fine.

So... it seems that one can easily implement these things in Arc. If you have some project in mind for which you want OO stuff, you can just do the things posted in this thread, and tell everyone how it goes if you like.

If you think OO should be put into the core of the language, well, there's a certain resistance to adding features just because someone suggests it. The core would become large, disorganized, and difficult to maintain if we did that. So, you would have to give a convincing argument as to why it's worth putting in there, and a demonstration of how useful it is in some real project of yours is probably the best argument you could give.

2 points by akkartik 1 day ago | link | parent | on: Ask: PG and Anti-OO

Yes that's implementable; I find this even more expressive:

  (x!deposit 50 "meh")
The implementation is simpler than waterhouse's version - just return the obj:

  (def Bank-Account (password)
    (let money 0
      (let check-pass [unless (is _ password)
                        (err "Wrong password!")]
         (obj deposit (fn (x pw)
                        (check-pass pw)
                        (++ money x))
              withdraw (fn (x pw)
                         (check-pass pw)
                         (if (< money x)
                             (err "Not enough money.")
                             (-- money x)))
              check (fn (pw)
                      (check-pass pw)
                      money)
              change-pw (fn (new-pw pw)
                          (check-pass pw)
                          (= password new-pw))))))
1 point by akkartik 1 day ago | link | parent | on: (map [string ".*" _] "test")

When you phrase it as map-as, it becomes easier to fit into my defgeneric/defmethod framework (http://www.arclanguage.org/item?id=11865). Thanks!

I've spent some time thinking about how to extend it for multiple-dispatch, and I didn't want to also think about setting the arg index to dispatch on.

1 point by zck 1 day ago | link | parent | on: Html test

No html, but here's the doc on formatting: http://arclanguage.org/formatdoc
2 points by rocketnia 2 days ago | link | parent | on: Atpos bug?

What do you expect it to do?

In case you didn't know, the point of 'atpos is to implement atstrings, an optional string interpolation feature that lets "@qty @(plural qty \"taco\") @@ $@price" compile so that it evaluates to things like "2 tacos @ $11". This option isn't enabled by default, so any Arc program that uses atstrings, such as news.arc, has to (declare 'atstrings t) first.

IMO, an @ at the end of an atstring is a syntax error, since it isn't escaping anything. It might be convenient to give "...@" a meaning like (sym "..."), (err "..."), or even just "...@@", but that's adding functionality rather than fixing bugs.

1 point by waterhouse 2 days ago | link | parent | on: The use of + for non-numbers

Aha! That works. Thank you!
1 point by garply 2 days ago | link | parent | on: The use of + for non-numbers

What other goodies does your arc.vim plugin have? Is your editor at all integrated with the arc repl? Lack of a repl that I could easily send arc code to was the reason I switched to emacs after years of using vim. These days, using emacs with viper (vim emulation mode), I don't miss vim at all.
1 point by aw 2 days ago | link | parent | on: Macros without 'mac'?

http://arcfn.com/doc/index.html and http://arcfn.com/2009/06/whats-new-in-arc3.html
1 point by ulix 2 days ago | link | parent | on: Macros without 'mac'?

Very interesting, thanks!

Do you know where I can find an Arc language reference?

2 points by fallintothis 3 days ago | link | parent | on: The use of + for non-numbers

String concatenation is particularly convenient after the + change for arc3.tar: http://arclanguage.org/item?id=9937. That's probably what I use + for most of the time.

I find thinking about whether or not I have to escape the "@" character is distracting

I find this is easier with proper syntax highlighting. My arc.vim ftplugin can detect if you have (declare 'atstrings t) and, if so, highlights the escaped parts of strings. That way, you know if @ is escaped just by glancing. But I don't mean to shamelessly plug, haha. I don't use atstrings either, but my reason is far lazier: in the middle of writing code, it's less effort to just use + than it is to declare then go back and start using @s.

3 points by fallintothis 3 days ago | link | parent | on: The use of + for non-numbers

if someone feels like showing me how to use a diff program to display the nice patch changes, please feel free

You mean like

  diff -u old-arc.arc new-arc.arc
or are you on Windows or something?
1 point by prestonbriggs 3 days ago | link | parent | on: Yeah, but is it Arc?

I guess I've got Arc on the brain these days.
3 points by garply 3 days ago | link | parent | on: The use of + for non-numbers

I make heavy use of + for concatenation throughout my code. I prefer it for a few reasons:

1. I find myself concatenating lists frequently and I prefer that frequently used functions be short. join has 4 chars to +'s 1

2. I also find ++ convenient for modifying a list variable. What would you use for the equivalent for join? In Racket's style, it would be join!, but I don't see a good analogue in arc for your proposal.

3. I'm constantly doing string concatenation. + is good for that because it's a short function name and also because I expect it to work because it works like that in many popular high-level languages (python, ruby, javascript). I also don't like to use arc's "@" for string-escaping because I find thinking about whether or not I have to escape the "@" character is distracting.

1 point by d0m 3 days ago | link | parent | on: Ask: PG and Anti-OO

Exactly, Arc already have OO with closures. However, what I suggest is this:

  (x 'deposit 400 "achtung")
could be instead written as:

  (deposit x 400 "achtung")
So basically, we get rid of the quote in front of deposit and we reverse the first and second parameter.

I find that:

  (let x (Bank-Account "meh")
    (deposit x 50)
    (check x))
Is cleaner then:

  (let x (Bank-Account "meh")
    (x 'deposit 50)
    (x 'check))
3 points by rocketnia 3 days ago | link | parent | on: The use of + for non-numbers

For what it's worth, I practically never add numbers. I actually use subtraction much more than addition! So I don't mind whatever these operations are named--and I mind the speed even less, actually--but I can testify that this change would sorta hinder my own code at this point. :-p

You've almost certainly encountered this comment above the definition of 'join, but I'll paste it here just in case it elucidates anything:

  ; Rtm prefers to overload + to do this
1 point by waterhouse 3 days ago | link | parent | on: Ask: PG and Anti-OO

What you describe is doable with closures, at least as far as your example goes. Your example can be implemented almost word-for-word in Arc as it stands:

  (def Socket (url port)
    (let o (obj on-receive (fn (..) ..)
                send (fn (..) ..))
      (fn (method-name . args)
        (apply (o method-name) args))))
obj is a macro that creates a hash table (you don't need to quote the keys, by the way). So, (Socket url port) will return a function that accepts 1 or more arguments, assumes the first is a method name, looks it up in the hash-table o, finds the corresponding function, and applies it to the rest of the arguments.

If you want to give your object thing internal state that you'll want to modify, use a let.

Here is an example that probably demonstrates most of what you're looking for. It is pretty much cribbed from SICP[0].

  (def Bank-Account (password)
    (let money 0
      (let check-pass [unless (is _ password)
                        (err "Wrong password!")]
        (let o (obj deposit (fn (x pw)
                              (check-pass pw)
                              (++ money x))
                    withdraw (fn (x pw)
                               (check-pass pw)
                               (if (< money x)
                                   (err "Not enough money.")
                                   (-- money x)))
                    check (fn (pw)
                            (check-pass pw)
                            money)
                    change-pw (fn (new-pw pw)
                                (check-pass pw)
                                (= password new-pw)))
          (fn (method-name . args)
            (apply (o method-name) args))))))

  ; In action
  arc> (= x (Bank-Account "meh"))
  #<procedure: Bank-Account>
  arc> (x 'deposit 50 "meh")
  50
  arc> (x 'check "meh")
  50
  arc> (x 'deposit 200 "meh")
  250
  arc> (x 'withdraw 300 "meh")
  Error: "Not enough money."
  arc> (x 'check "meh")
  250
  arc> (x 'deposit 20 "achtung")
  Error: "Wrong password!"
  arc> (x 'check "meh")
  250
  arc> (x 'change-pw "achtung" "meh")
  "achtung"
  arc> (x 'deposit 400 "achtung")
  650
[0]http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html...
2 points by rocketnia 3 days ago | link | parent | on: Macros without 'mac'?

Am i wrong if I think that, in the end, the main difference between 'def'+'eval' and 'mac' is that 'mac' allows its code to be evaluated and expanded once, whereas 'def' needs to expand its code every time it is called ?

It's 'eval that expands its code once every time it's called. If you don't use 'eval at all, then all your arc code will be expanded exactly once, at the time you enter it at the REPL or load it from a file (since those are the points where 'eval is called internally).

When you enter the expression (def foo (x) (obj key x)) is at the REPL, it's evaluated as a two-step process: First it's compiled (which expands the (def ...) and (obj ...) macro forms), and then the compiled code is run. When it's run, the body of the function isn't run yet; instead, it's packed up into a procedure and stored as foo. When you call foo later, no expansion takes place, only running of already compiled code.

A better (but not perfect) way to use 'eval equivalently to 'mac is something like this:

  (def mywhen (test . body)
    `(if ,test (do ,@ body))
  
  (eval `(time:for i 1 1000 ,(mywhen '(is i 666) '(prn "Oh no!"))))
If we wanted to make 'do a non-macro, we could do that too:

  (def mydo body
    `((fn () ,@body)))
  
  (def mywhen (test . body)
    `(if ,test ,(apply mydo body)))
  
  (eval `(time:for i 1 1000 ,(mywhen '(is i 666) '(prn "Oh no!"))))
Finally, if we wanted to avoid the use of macros altogether, the example would turn into something like this:

  ; The procedure corresponding to an Arc macro can already be obtained
  ; using 'rep.
  (assign mywhen rep.when)
  (assign mytime rep.time)
  (assign myfor rep.for)
  
  (eval:mytime:myfor 'i '1 '1000 (mywhen '(is i 666) '(prn "Oh no!")))
I could make a few guesses as to why this kind of programming isn't popular in lisps, but my personal reason is that I tend to consider all operators to provide their own syntax, with procedure call syntax just being the default choice. For me, it's inconsistent to have the '(prn ...) syntax be quoted when the (mywhen ...) syntax isn't.
1 point by ulix 3 days ago | link | parent | on: Macros without 'mac'?

You can get around the problem also in the following "weird" way:

(let x ''(+ 1 2) (xrepeat 3 `(pr ,x)))

but the way you proposed is more "natural" since it respects the "rule" of quoting functions and variables passed at calling time.

Am i wrong if I think that, in the end, the main difference between 'def'+'eval' and 'mac' is that 'mac' allows its code to be evaluated and expanded once, whereas 'def' needs to expand its code every time it is called ?

1 point by ulix 3 days ago | link | parent | on: Macros without 'mac'?

Thank you for the answer, very interesting. Here's some more things I found:

1) actually the "reference to undefined identifier" error can be avoided un-quoting the variables at calling time, as in: (let i 2 (eval­ `(+ ,i 1))) (time:for i 1 1000 (mywh­en `(is ,i 666) '(prn­ "Oh no!")))

2) the last expression is computed in 176 msec, whereas the regular macro 'when' is computed in 2 msec (much faster as you forecasted).

3) these examples don't work in online interpreter Arc Web REPL (http://dabuttonfactory.com:8080/), but they work in TryArc (http://tryarc.org/)

Thanks

1 point by fallintothis 3 days ago | link | parent | on: (map [string ".*" _] "test")

Yet another option:

  (def map-as (type f seq)
    (coerce (map1 f (coerce seq 'cons)) type))

  arc> (map-as 'cons [+ ".*" _] "test")
  (".*t" ".*e" ".*s" ".*t")
  arc> (map-as 'string [+ ".*" _] "test")
  ".*t.*e.*s.*t"
  arc> (map-as 'cons [+ _ 1] '(1 2 3))
  (2 3 4)
  arc> (map-as 'string [+ _ 1] '(1 2 3))
  "234"
This works because of how coerce works.

  arc> (coerce '("a" "b" "c") 'string)
  "abc"
It deals with lists and strings well, which is decent: Arc's only other sequence-like type is the table (I don't think you'd ever want to treat symbols as a sequence of 1-character symbols; you'd just use a string). Tables would work better if they were properly coerced, cf. the comment above tablist and listtab in arc.arc.

The more I think about it, the more I like this model. Conceptually, it seems that map should behave like

  (def map (f seq)
    (map-as (type seq) f seq))
even if it's not implemented like that -- all the coercions would surely be slow. (Tangential: map would also need to handle multiple sequences.) But it makes more sense for map and coerce to at least have compatible behavior. Plus, map's current behavior is a degenerate case of the coerce-compatible map:

  arc> (map inc "abc")
  "bcd"
  arc> (map-as 'string inc "abc")
  "bcd"
so it's not like you lose functionality, and then this post's example would've worked to begin with.
2 points by d0m 4 days ago | link | parent | on: (map [string ".*" _] "test")

This macro hide fallintothis' suggestion to my string-are-not-list problem. So basically it does:

  (def ->s (var . body) 
   `(let ,var (coerce ,var 'cons)
      (string ,@body)))
And now I can use:

  (let s "hello"
    (->s s
      (intersperse ", " s)))
  
  > "h, e, l, l, o"
1 point by akkartik 4 days ago | link | parent | on: (map [string ".*" _] "test")

Can you elaborate?
1 point by d0m 4 days ago | link | parent | on: (map [string ".*" _] "test")

Finally, I've chosen to make a little macro:

  (let s "hello"
    (->s s 
      (map [+ ".*" _] s)))
2 points by aw 4 days ago | link | parent | on: Macros without 'mac'?

Btw, you need an additional quote to get values like your "x" into the eval in all cases... "blub " works because a literal string evaluates to itself, but consider a list like (+ 1 2)

  arc> (let x '(+ 1 2) (repeat 3 (pr x)))
  (+ 1 2)(+ 1 2)(+ 1 2)nil
  arc> (def xrepeat (n . body)
         (eval `(for ,(uniq) 1 ,n ,@body))))
  #<procedure: xrepeat>
  arc> (let x '(+ 1 2) (xrepeat 3 `(pr ,x)))
  333nil
This can be fixed by adding another quote...

  arc> (let x '(+ 1 2) (xrepeat 3 `(pr ',x)))
  (+ 1 2)(+ 1 2)(+ 1 2)nil
Also, you got around the limitation that eval doesn't have access to the lexical variables of its caller by passing in the value of "x", but if you wanted to have your eval/macro to set the value of a variable, that would be harder.

As waterhouse mentioned, two differences between macros and eval are that macros are expanded once when your program is loaded, but eval has to expand and compile its argument every time its called. And like any function eval doesn't have access to the lexical variables of its caller unless you pass in values yourself.

Aside from that, macros and eval are quite similar in the sense that they both treat code as data, and so you have the opportunity to manipulate the code before it gets evaluated.

More