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

as a lisp noob i'm curious what specific sorts of things you could do with first-class macros. perhaps swapping out macros for a given macro call? say in one pass of a program (function) a particular macro call is expanded by macro1, and in the second pass the macro call is expanded by macro2

-----

6 points by kens1 6404 days ago | link

The problem I ran into today was:

  arc> (apply or '(nil t nil))
  Error: "Function call on inappropriate object #3(tagged mac #<procedure>) (nil t nil)"
I assume that first-class macros would let me do this.

-----

4 points by nex3 6404 days ago | link

There are folks here who know more about this than I do, but I think first-class macros would be very useful for creating a pure-Arc module system.

-----

2 points by eds 6404 days ago | link

I'm not exactly an expert on this, but I think it would allow you to put a macro literal in functional position. Right now:

  arc> and
  #3(tagged mac #<procedure>)
  arc> (eval (list and 1 nil 2))
  Error: "Bad object in expression #3(tagged mac #<procedure>)"
So if you had theoretical first-class macros, you could do stuff like use backquote to protect a macro you use from being overridden. (This wouldn't be necessary if we had a module system, but that might require first-class macros itself.) So in the (contrived) example below, foo works fine because prs is a function, but bar fails because foo is a macro.

EDIT: Actually, function literals in functional position only works on Anarki. It might be nice to have that fix in the official version.

  arc> (mac foo args `(,prs ,@args))
  #3(tagged mac #<procedure>)
  arc> (mac bar args `(,foo ,@(keep [isa _ 'sym] args)))
  #3(tagged mac #<procedure>)
I think first-class macros might be useful in making infix math expansion occur at compile time rather than run time... but I'm not completely sure on that one.

-----

4 points by Jesin 6402 days ago | link

Yes, please. First class macros and the ability to use macros and functions (rather than just their names or definitions) in functional position would be great, and macro names would not have to shadow variable names gobally anymore. In my opinion that is one of the biggest problems with Arc.

-----

2 points by sacado 6402 days ago | link

Oh, yes. That one drove me crazy a few times.

-----

1 point by nex3 6404 days ago | link

fns in functional position work fine for me in arc2... can you give an example where they die?

-----

3 points by eds 6404 days ago | link

  arc> (eval (list + 3 4))
  Error: "Bad object in expression #<procedure:...mming\\Arc\\ac.scm:602:9>"

  arc> (mac foo args `(,+ ,@args))
  #3(tagged mac #<procedure>)
  arc> (foo 3 4)
  Error: "Bad object in expression #<procedure:...mming\\Arc\\ac.scm:602:9>"

-----

1 point by nex3 6404 days ago | link

Oh, I thought you meant function literals as in calls to fn. But calling functions from lists... yeah, that would be great to have.

-----


i love Lua's tables. after using them, other languages feel abstruse in that department, with all these alternatives that are in my mind conceptually and functionally the same thing: (key,value) pairs

[edit]it should be noted that Lua is fast, like the fastest scripting language fast

-----

1 point by tokipin 6404 days ago | link | parent | on: Arc with vim

welcome

i tried to make vim switch to a copied lisp syntax when it boots up an arc file but i wasn't able to get even that working

as far as details for the syntax, i would say don't give the [... _ ...] notation any special color or anything

once you have something, anything really, i think it would be fine if you uploaded it to the anarki arc git wiki http://git.nex-3.com/arc-wiki.git into the 'extras' folder

i look forward to a prompt upload

-----


personally i don't see why the insistence on a remainder-style curry. i like what i proposed in the other thread http://arclanguage.org/item?id=3962 which is that if a function is given _ as an argument, even in multiple places, then the function will be curried for those argument slots

  (= my-prn (print _ 0 _ 0))

  (my-prn "test" 1) => (print "test" 0 1 0)
the benefit is you don't require what i think is a somewhat arbitrary arrangement of placing the most important arguments at the end, and you don't need to use argument-swapping functions just to line things up correctly. you just put the _ into the argument spots you want to postpone and you're done

for variadics:

  ((+ a b _) c d e) => (+ a b c d e)

-----

4 points by cchooper 6405 days ago | link

That also looks useful to me, but to be pedantic, I wouldn't call it currying.

-----

4 points by cchooper 6405 days ago | link

Do you mean something like this?

  (mac fix rest
    (withs (rest-parm (if (is '_ (last rest)) (uniq))
            parms rest-parm
            body nil
            rev-rest (if rest-parm (cdr (rev rest)) (rev rest)))
           (trav rev-rest 
                 (fn (x) (if (is '_ (car x))
                             (w/uniq u (push u parms) (push u body))
                             (push (car x) body)))
                 [self (cdr _)])
           `(fn ,parms ,(if rest-parm 
                            (join (list 'apply) body (list rest-parm))
                            body))))
If so I'm going to push it to the wiki.

-----

1 point by tokipin 6405 days ago | link

actually i don't understand any of that ^_^;; i'm a lisp noob. in other languages there aren't macros so i implement it as a function which stores the function-to-be-curried and its initial arguments in a closure

however i tested your macro with some arithmetic and it all seems to work fine. the only thing i found is that something like this will cause an error:

  ((fix + _ 2) 3 4)
because there isn't an underscore at the end. i don't understand lisp enough to see if that was your intention. i think for the sake of variadic functions it should adapt regardless of where the underscore is (or whether or not it's present, eg: (fix +)), either by detecting if a function is variadic (which i'm guessing isn't reasonably possible at the moment) or by always returning a variadic function [edit: actually i think i can decipher the meaning of (if (is '_ (last rest))]

if the generated expression is always variadic, it would seem to mess with the fact that the underlying system cares how many arguments there are. is that a big deal? i don't think so. a language i use this function in is Lua, whose functions are all variadic (in that the interpreter doesn't complain if you supply too few (unsupplied are niled) or too many (excess are discarded) arguments) and it simply is never a problem. to me the fixed-argument thing seems similar in spirit to static typing in that it tries to solve a problem that really isn't significant

-----

2 points by cchooper 6405 days ago | link

Yes, I implemented it so it would only be variadic if there was an underscore at the end. It would actually be a simpler macro if they were always variadic, but that's such a radical change to the language that I'm a bit wary about it.

But maybe it's a good idea. I see your point about the 'spirit of static typing'. I'll have to check out Lua and see how it works out.

Edit: I mean it would be radical if fix were implicit, of course.

-----

2 points by tokipin 6406 days ago | link | parent | on: could currying be introduced in Arc?

in other languages i write a function that i call fix which does the same as the _ notation except that the _ represents a general "hole to be filled later" and can be present any number of times

take for example a function named 'print' which accepts string, r, g, and b arguments

  (= my-prn (fix print "message" _ _ _))
so that

  (my-prn 0 0 1)
would print "message" in blue

  (= my-prn (fix print _ 0 _ 0))
  (my-prn "test" 1)
would print "test" in green. if built into the language it could be done something like:

  (= my-prn1 (print "message" _ _ _))
  (= my-prn2 (print _ 0 _ 0))

-----


could it be related to the license he's using?

-----

4 points by nex3 6407 days ago | link

I'm no lawyer and I haven't read the artistic license very closely, but Anarki's under the same license as the original codebase, so I'm pretty sure there shouldn't be a problem...

-----

3 points by antiismist 6406 days ago | link

IAAL--Arc is under the Perl Artistic License, see http://www.opensource.org/licenses/artistic-license-2.0.php

PG can roll in changes per part 4.a

-----

4 points by nex3 6406 days ago | link

I don't think I've ever seen the term "IAAL" used before.

-----

2 points by tokipin 6415 days ago | link | parent | on: Top 10 differences between Scheme and Arc

my guess is it avoids it because it's ugly. i may be in the minority for thinking that's a good reason

-----

5 points by byronsalty 6414 days ago | link

Well I don't think it's ugly, but ugliness aside it's very descriptive in one char. I'd personally like to see this convention carried over. Ruby uses the same convention so it's not just Scheme.

If this was intentionally left out my guess would be that PG was trying to save those chars for something meaningful to the compiler (syntax) not for aesthetics.

-----

1 point by are 6414 days ago | link

It should be possible to detect, at define-time, whether a function/macro has side-effects (see the ideas for a conservative purity analyzer in http://arclanguage.org/item?id=558).

So if the function/macro has side-effects, def/mac could e.g. also assign it to a second symbol with "!" appended.

'?' could also be done similarly, but would be more difficult. Here is a start:

def/mac should also assign its function/macro to a second symbol with "?" appended if:

1) The function/macro has no side-effects (no "!")

2) The function/macro has a least one argument

3) The function/macro could return the empty list

-----

1 point by Jekyll 6411 days ago | link

join? ?

list? ?

sort? ?

first? ?

It's not doing it for me.

Leaving aside the issues of detecting a query, I think it's a really bad idea to have the compiler force (badly guessed) semantic knowledge on me.

It's my code, I wrote it, and I don't want any compiler telling me that a query that caches previous results must be imperative! and not end in a ? .

I also thing needlessly polluting a namespace with addition symbols is a bad idea. You only get one namespace in arc, try to preserve it for the future.

-----

1 point by tokipin 6414 days ago | link

that makes sense. '!' is already being used (though the convention doesn't interfere with the syntax at the moment)

bear with me here, but '!' means the function isn't pure, right? if so, who cares? it seems like an ivory tower thing. ? is fine, though maybe prefix notation can be considered

  isPair
  isNumber
  dangerSet
  dangerSet-car

-----

5 points by absz 6414 days ago | link

Just because something is academic doesn't mean it's not worthwhile. For instance, map, keep, reduce, etc. are different if passed a function with side-effects. What happens if you give them a function which modifies the list as it's being traversed? A pathological example:

  arc> (= x (range 1 5))
  (1 2 3 4 5)
  arc> (map [do (= (cdr x) (cddr x)) _] x)
  (1 3 4 5)
  arc> x
  (1)
However, if map is passed a pure function, you can e.g. run one copy of the function on each core and run it in parallel.

And "dangerSet" is both non-Lispy and non-Arcy. It's non-Arcy because it's long. And it's non-Lispy because of that capital letter: danger-set would be marginally better. But nevertheless, pair? is shorter than is-pair, and (in my opinion) reads much more nicely.

-----

9 points by im 6415 days ago | link

You may be in the minority for thinking it's ugly.

-----


it seemed like arc on top of javascript didn't take long to write. i wonder if someone would be up to writing a C/C++ or D or JVM or CLR version

-----

5 points by partdavid 6421 days ago | link

I think the OP's point was, if it's so much slower than Mzscheme, something is "wrong" with Arc itself, not the runtime.

-----

3 points by tokipin 6423 days ago | link | parent | on: New version

i was thinking that too, but how would you do it dynamically (eg with variables) ?

  (cut "abcde" begin end)
what would i need to put in end to get the full string? nil?

-----

3 points by sjs 6422 days ago | link

Both nil and (len str) work. I see both sides of the argument as counting from -1 eliminates the 0 corner case.

I like indices that are intuitive with literal numbers. Counting from 0 at one end and from 1 at the other is jarring. When -1 points to the end of string rather than before the last char (cut str 0 (- (len str))) returns the first char instead of the empty string.

With -1 -> before last char:

  (def chop ((o str "abcdef"))
    (pr "Chop how many chars off the end of \"" str "\"? ")
    (= n (coerce (cut (readline) 1) 'int)) ; bug in readline prepends #\newline
    (prn "Chopped: \"" (if (is n 0) str (cut str 0 (- n))) "\"")) ; handle corner case
With -1 -> end of string:

  (def chop ((o str "abcdef"))
    (pr "Chop how many chars off the end of \"" str "\"? ")
    (= n (coerce (cut (readline) 1) 'int)) ; bug in readline prepends #\newline
    (prn "Chopped: \"" (cut str 0 (- -1 n)) "\"")) ; no corner case, but there's this -1 there
I probably made a stronger argument for -1 pointing to the end of string as it leads to shorter code.

-----

2 points by nex3 6422 days ago | link

If you absolutely need to do that, you can just use (len str).

-----


programmer dvorak: http://www.kaufmann.no/roland/dvorak/

been using it for about a year and dvorak in general for three or four. the difference in comfort vs qwerty is huge

-----

More