Arc Forumnew | comments | leaders | submit | bogomipz's commentslogin
1 point by bogomipz 6486 days ago | link | parent | on: Small pattern matching macro

What happens to arg in (defp sum^mul (arg) ... ) ?

Wouldn't it be better if the function was to be called like this?

  (sum^mul '(126 9) 90) => 1224
  (sum^mul 7 134) => 141
  (sum^mul 13) => 169

-----

1 point by araujo 6485 days ago | link

I really had thought of getting something apparently cleaner , like the syntax you are proposing. At the end I decided it'd be better to preserve an 'argument' field to clearly indicate that it is a function-like definition and we need to pass an argument to it , something more like a spec:

   (sig 'sum^mul) => (arg)
Besides being a good visual indicator, it also plays a role inside the macro definition , this is the variable containing the value to be matched against the different patterns internally, so in this case, such a variable is actually needed too.

Pattern-matching operates over 'data structures' , that is why we need to pass lists (or another structure) to the function. I think there is no need to increase complexity on this, or probably creates confusion about it.

-----

4 points by bogomipz 6486 days ago | link | parent | on: Local variables

Wasn't part of the problem that they made the innermost do the scope of the variable? What if they had used the outermost do instead? That would normally mean a def, which would be quite intuitive for the user.

The compiler should then be smart enough to figure out which closures actually make use of the variable and optimize away the overhead of holding onto a variable that is not needed.

-----

3 points by bogomipz 6486 days ago | link | parent | on: Lambda with a name

There's also afn which implicitly binds 'self.

-----

2 points by bogomipz 6487 days ago | link | parent | on: Infix Math

Most of the values in math expressions are in the form of variables. How do you handle that? Stick a dummy number in front like this?

  (0 + x * y * scale)
The compiler will optimize that away, right?

-----

4 points by cadaver 6487 days ago | link

The variables/sub-expressions are first evaluated completely, only then infix analysis will happen. It's exactly like with lists:

  (= somelist '(1 2))
  ...
  (somelist 1)
works just like

  ('(1 2) 1)
does.

As to your second argument, the +-*/ operators are passed as first-class functions, so, there shouldn't be any optimization happening. Worst thing that can happen is that the compiler doesn't understand literal numbers in functional position, or arithmetic operators applied to first-class functions, and signals an error.

-----

4 points by eds 6487 days ago | link

Assuming x, y and scale are numbers, just

  (x * y * scale)
should do the trick. As cadaver said, the arguments are evaluated completely before infix evaluation. So you can also do

  (x * y * (sqrt z))
or

  (x * Y * (sqrt (t * u + v)))

-----

2 points by bogomipz 6486 days ago | link

Ah ok, in that case this is no less than brilliant! :)

-----

1 point by bogomipz 6487 days ago | link | parent | on: A proposal for a module system...

Doesn't that mean you have to do an assignment in the normal case as well?

  (= foo (use 'foo))

-----

3 points by bramsundar 6487 days ago | link

I don't think so. Couldn't you just have use's macroexpansion add a global variable named foo?

-----

2 points by bogomipz 6486 days ago | link

Yes, I thought of that after I wrote the comment. Avoiding repetitions like this is exactly what macros are for. I guess I'm not used to thinking in lisp yet.

pau wants 'use to be a function, though, so there would have to be a separate macro, or the other way around, or something.

-----

2 points by almkglor 6486 days ago | link

  (def function-that-assigns-one-to-a-global-symbol-of-your-choice (s)
    (eval `(= ,s 1)))

-----

1 point by bogomipz 6487 days ago | link | parent | on: Value of iteration expressions

Returning the last value is probably no harder than a hardcoded t. Most of the time you don't care for more specific than a boolean, but one of those days it might come in handy.

-----

4 points by absz 6487 days ago | link

On the other hand, that operates differently if the last value is nil; in other words, it's a tradeoff and has different semantics. I'm personally inclined to think that a boolean might be more useful.

-----

2 points by ecmanaut 6486 days ago | link

I agree to a point; to be a useful idiom, the semantics of the return value should primarily make code easier to read for humans -- while allowing for the useful flow construct which cuts corners on code length.

I don't find t / nil necessarily be the best range, though; the number of iterations that was looped, if non-zero, nil otherwise, conveys useful information that is often wanted and would presently require explicit code for defining and updating a counter variable that, could instead ideally just be there for you to capture, should you want it.

In languages where zero has boolean falsity, the unmodified iteration count would of course work even better and be more cleanly, but I think nil-or-positive-integer works better in Arc.

If getting the count was presumed to be the more common case (vs just figuring out if a loop ran through its body at all) I would argue for the count, zero or otherwise, but personal experience says you mostly want the "whether", not the "how many?", and that the latter is the occasional useful fringe case that mainly adds extra convenience.

-----

1 point by absz 6486 days ago | link

Given that the number of iterations adds strictly more information, I can't see why that would be a bad idea. I agree that it's not normally what you would want, so the asymmetry between numbers and nil is probably worth it.

-----

3 points by bogomipz 6487 days ago | link

Ah, of course, I take back the suggestion :)

-----

1 point by eds 6487 days ago | link

Don't CL's and Scheme's do allow the user to specify the return value? Maybe this wouldn't necessarily be the case with each, but I think it is correct in spirit to allow the user to control the return value.

-----

1 point by bogomipz 6487 days ago | link | parent | on: A proposal for a module system...

When you do (use 'foo), is the module globally known as 'foo and in the current file accessible without prefix? This seems the most straight forward since the file is named "foo.arc" and you don't want to load it multiple times when used by different modules. But then I wonder what happens when you (useas 'foo 'fu), and why is this even useful if (use 'foo) makes sure you don't need to do foo@bar. Actually, why even have the foo@bar syntax at all?

Is each source file treated as a separate module?

How about this even simpler suggestion?

  (use foo)
Loads "foo.arc" into a symbol table named 'foo, unless this is already done, and makes all of its symbols available in the current module (the current source file, or a general module 'user or whatever if done in the repl).

  (use foo bar baz (barbeque bq))
Loads module 'foo, but only imports symbols 'bar, 'baz and 'bq locally, where the latter is originally named 'barbeque. In case you just want to rename one function to avoid a name clash, and want everything else imported straight up, this should be possible as well;

  (use foo (barbeque bq) *)

-----

2 points by pau 6487 days ago | link

In Python, if you do

  import string
you still have to access symbols within string using the prefix, and I imagined Arc's (use ...) doing the same.

Arc should register in some way that the module was loaded, since if two other modules do (use 'x), then they have to reference the same table. This is, afaik, what Python does. So 'locally' (within the current module), you access the symbol table of another package with the name you want (if you don't supply one, then it's the same as in the file), but the system remembers who is who globally.

Each source file is a module, yes.

To be able to load a list of modules, like

  (map use '(string regex parser))
I think that it is important that the first parameter to the use function be a symbol, e.g. (use 'string) instead of (use string).

I like your suggestion (specially changing the names to avoid clashes)... Yes, it could be a nice way to avoid the prefix... ;)

-----


I think the most interesting aspect of this discussion is that it shows a problem with destructuring a list you want to recurse over.

Traditionally, your function would be written like this;

  (def print-list (lst)
     (when lst 
        (prn (car lst)) 
        (print-list (cdr lst))))
This works as expected and is what lispers have done for half a century. The root of your problem is that the original cons is lost when the function destructures it to a and b, so you cannot do the above test.

Existing languages that support argument destructuring, AFAIK do so through pattern matching. In this case the problem does not exist because the matching is the branch.

Imagining Arc with pattern matching, your function would look something like this;

  (def print-list (nil)
     | print-list ((a . b))
       (prn a)
       (print-list b))
EDIT:

This can already be done with almkglor's pattern matching library;

  (require "lib/defpat.arc")

  (defpat print-list (nil) nil
                     ((a . b)) (do
          (prn a)
          (print-list b)))

-----


Here's the other thread;

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

It started with the idea of using ? rather than o, then someone suggested using only one ? for all optional arguments.

-----


Does the suggestion really close that door? For instance, if you wanted to add keyword arguments, they could go like this:

  (fn (a b ? (c 3) (d 4) ! (e 5) (f 6) . rest) ...)
Combining all four argument flavors in the same function is of course not a good idea.

-----

1 point by kennytilton 6488 days ago | link

Looks like how common lisp works. And agreed: mixing optional with keyword args would be a nasty thing to do to users. Probably they saw that it was /possible/ and said sure, why not?

-----

More