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

Stalin is actually the name of "an aggressive optimizing batch whole-program Scheme compiler," to quote Wikipedia (http://en.wikipedia.org/wiki/Stalin_(Scheme_implementation)). It can be found at http://cobweb.ecn.purdue.edu/~qobi/software.html . Now, it's certainly an unfortunate name for the compiler, but that's hardly sacado's fault.

-----

2 points by absz 6467 days ago | link | parent | on: Yet another attempt at an Arc logo

I don't really see the lambda, but I like the rest. Very dynamic and energetic, and it doesn't feel "forced" into a concept the way some of the other logos have.

-----

3 points by absz 6467 days ago | link | parent | on: Simpler definition of aand?

Unfortunately, your definition is broken. You just defined and, not aand. What you miss in aand is that it is bound to the previously-evaluated clause, so we have

  arc> (aand 3 (prn it) 10 (prn it) t)
  3
  10
  t
Yours, on the other hand (band), results in

  arc> (band 3 (prn it) 10 (prn it) t)
  Error: "reference to undefined identifier: __it"
. However, and is defined as

  (mac and args
    " Evaluates arguments till false is found else returns the last one.
      See also [[or]] [[aand]] [[andf]] [[andmap]] "
    (if args
        (if (cdr args)
            `(if ,(car args) (and ,@(cdr args)))
            (car args))
        't))
, which is roughly equivalent to your aand.

Also, a formatting tip: surround code by two blank lines and indent it to get it to format properly.

-----

1 point by jeff303 6467 days ago | link

Ack, OK somehow I didn't even think to read the definition of and before. Now I can see how my definition is basically equivalent.

I noticed it being bound in aand before but wasn't sure why. Your example of applying prn seems useful but are there any other common similar idioms? Thanks for the reply.

-----

1 point by absz 6467 days ago | link

Well, you can write (aand (complex-expression 'that (might return) "nil") (frobnicate it)), but I can't think of any specific examples off the top of my head. There's also aif and awhen, which do similar things, and which are probably slightly more useful.

-----


That seems like a very interesting idea, and I haven't had time to fully digest it yet, but here are some of my first thoughts.

(1) I don't really like having to write (call car x); that adds a layer of complexity, and I'm just going to want to write (car x), thus losing benefits down the line. It might be nicer to by default do things polymorphically, and then only specify "I want this car" when we need it.

(2) If you just define a way to say "I implement this function" in the core, and leave out interfaces, then they can be added on later. If you just define interfaces in the core, going the other way requires lots of extra one-function interfaces. Don't do it! Provide interface functionality, but put that on top of the core.

(3) Using a polymorph to store methods (and everything else) is a wonderfully clever bit of metahackery, and really does seem to allow pretty much anything you want: it's all in the getmethod. Uniformity is very powerful: look at Smalltalk and Lisp. Now look at Java. Quick, look at Lisp again! :)

(4) With the way you make things explicit, it feels like you're pretty much implementing an ugly OOP system on top of Arc. Again, make more things implicit--that way it won't feel like classic OOP, and thus (hopefully) won't be used like classic OOP. call feels like a long-winded way to do a message send (à la Smalltalk); if that's explicit, it feels like we're Greenspunning Smalltalk. Instead, let's integrate the feature. (I don't know if that was clear at all... it's related to point 1.)

I can't wait to see what people do with this--the more I think about it, the more I like this idea.

-----

3 points by almkglor 6468 days ago | link

(1) Agree

(2) Could be done, and have interfaces simply act as a shortcut way of saying "I have (for objects) or need (for functions) the following: a, b, c, and d"

(4) LOL. We're making an informally-specified, ad-hoc, bug-ridden implementation of half of CLOS. ^^

-----

2 points by sacado 6468 days ago | link

"We're making an informally-specified, ad-hoc, bug-ridden implementation of half of CLOS"

That's what I thought when I was thinking about solutions for these problems :)

I think (1) could be solved simply by using redef on each polymorphic function : if car becomes polymorphic, just encapsulate the desired behavior in a new definition of car that will do the dynamic dispatch for you. If you want a specific version of car (e.g. the array implementation), just call it explicitly : (array-car x) .

-----

2 points by cchooper 6468 days ago | link

(1) Yep, I agree. You'd want to put the polymorphisn all the way down, so you nearly never have to actually use call in your code.

(2) Again, agreed. Implement features on top of the system, rather than within it, just like Arc!

(4) Might be tough to make everything completely implicit. Ideally, the whole thing should be invisible, like it didn't even exist, but works anyway. All suggestions for doing that are welcome.

-----

3 points by absz 6468 days ago | link

(4) Actually, I think we're in agreement there, I just didn't say what I meant too well :) In fact, one of the reasons your post may look so explicit is that you're discussing how to implement the system, and thus have to deal with a lot of "low-level" code, the way the first few lines of arc.arc look nothing like most Arc you'll actually use (safeset, etc.). For instance, call certainly appears to be such a feature—used to get the system working (and possibly sometimes used the way Ruby uses its #send method), but not in every case. Similarly, since you're discussing implementing the system, of course implementation details will show through. At any rate, if the goal for the "end-user" is invisibility/integration/implicit behaviour (which I think all mean roughly the same thing in this context), then we're in agreement.

-----

2 points by cchooper 6468 days ago | link

Yes, I wasn't disagreeing with you, just pointing out that it might not be easy. As you say, some of this will just disappear because it's low level and will be buried right at the bottom where you implement the basic type operations. Hopefully it'll all turn out like that, but I'm not counting my chickens yet.

-----

2 points by absz 6468 days ago | link | parent | on: Defining Setable Forms

Try removing the comma in front of olddef; it should work then.

-----

4 points by Darmani 6468 days ago | link

Unfortunately, that won't work because the form is being returned to a place outside the closure where olddef was defined; when eval is given the form containing olddef, it will not recognize it.

Here's a better definition:

  (let olddef def
    (mac def (name args . body)
      (if (acons name)
        `(def= ,(cadr name) ,args ,@body)
        (apply (rep olddef) (cons name (cons args body))))))

-----

2 points by absz 6468 days ago | link

Shouldn't that be (mac def ...)?

Anyway, nice work, but damn do we need 1st-class macros.

-----

3 points by Darmani 6468 days ago | link

Oops -- thank you. Fixed.

-----


But if you think about it as an abstract base class/mixin/interface, then the standard terminology is "is-a". For instance, in Ruby:

  module MyMixin # Like an interface
    ...
  end
  
  class MyClass
    includes MyMixin # Like "implements MyMixin"
    ...
  end
  
  foo = MyClass.new
  if foo.is_a? MyMixin
    puts "is-a"
  else
    puts "has-a"
  end
  # Output: "is-a"
I'd rather see the "basic types" not as a collection of basic components, but as a collection of basic interfaces one can implement, or basic type classes one can be a member of, or what-have-you; what I'd really rather do is duck most of it, like Ruby does. If I can define car and cdr for my type, map should work seamlessly.

Regardless, it sounds like a lot of the voices here are in agreement over some common set of the features this plan proposes, which is a good thing. Perhaps we should set the naming quibbles aside for now and try to flesh that out. Or perhaps we should settle on a name for what we are about to flesh out. Either way, it looks like something good could well emerge from this thread.

-----

2 points by almkglor 6468 days ago | link

I vote we settle on a name first, because we need it to refer to stuff when we talk about it ^^

-----

5 points by absz 6470 days ago | link | parent | on: Hash element as lvalue

Yes, it is possible. But first, a formatting tip: surround your code with blank lines and indent each line of code with two spaces to get it to look like a real code block.

What you want is defset, defined in "arc.arc". The idea with defset is that you define what will happen when = sees something of the form (name ...) as its first argument (called a "place"). The best tutorial for defset is http://arcfn.com/doc/setforms.html -- it should answer your questions. Good luck!

-----

2 points by zhtw 6469 days ago | link

Thanks for the tip. That way my first post, I didn't know how would it look.

Anyway looks like defset is exactly what I need. Thanks a lot!

-----

2 points by absz 6469 days ago | link

It occurs to me that there's another problem with this code: your use of t as a variable name. This is outright forbidden globally:

  arc> (= t (table))
  Error: "Can't rebind t"
. Though it does work locally, it is nevertheless inadvisable: t is the global "true" value (equivalent to 't). It's probably better to use tb as the name for your table.

Glad to be of assistance.

-----

2 points by sacado 6469 days ago | link

And don't ever use tab, particularily for a table : it is a macro's name so it will get you in trouble.

-----

1 point by absz 6469 days ago | link

Or we could fix that part of the language ;)

Seriously, that's one of my biggest standing irritations. If I have some time, I might look at fixing that in the Anarki, actually.

-----

2 points by zhtw 6468 days ago | link

I also had a problem with tab and also think that it should be fixed.

Btw what do I need to load to get the base language without any web stuff. Are there an official "base" part? As.scm loads all the libraries for me. Do I need to load arc.arc only to get the base language.

-----

1 point by absz 6468 days ago | link

Yes, that would be the way to do it, but I don't know a simple way to load only arc.arc.

-----

2 points by absz 6471 days ago | link | parent | on: Moved Anarki to GitHub

If anyone has a spare, I'd appreciate an invite: my email's local-part is emailguy888, and its domain part is gmail.com. (Try to harvest that, spam-bots!)

-----

2 points by kostas 6471 days ago | link

Sent.

-----

1 point by absz 6471 days ago | link

Thank you!

EDIT: Now I have 3 invites too. Yay exponential growth!

-----

2 points by absz 6472 days ago | link | parent | on: Predicates: `is...' versus `...?'

As another new-ish Lisper, comfortable with only Scheme and Arc, I have to disagree. I find appending a character which might anyway occur at the end of a predicate to be a confusing way of expressing predicates. What about a type called, say, tem (a template, perhaps): what's temp? Is it tem predicate or temporary? I actually prefer the "a..." style to the "...p" style, but I think "...?" is still better.

-----

1 point by Jesin 6472 days ago | link

Who would ever use 'tem for anything? A template type would more likely be called temp, and the predicate would be tempp. Usually when p is the next letter, it's included in the variable name, and when a p at the end of a name is part of a word, it is not usually read as predicate. This sort of collision is very rare, and when it does happen, it usually takes no more than a second to figrue out.

On the other hand, asomething in Arc sometimes means anaphoric-something and sometimes means isa-something. This inconsistency is much more common, and a- collisions are no better than -p collisions.

Then there is the foo? of Scheme. Every time I see foo? it interrupts my reading. I don't know about you, but I think of ? followed by a space as a terminator, and putting it between a function name and its arguments throws me off. The ? character also has a lot of potential for ssyntax, and in that position any break it would cause would most likely coincide with a conceptual break. I have no problem with punctuation separating symbols, but when it's punctuation followed by a space, that looks like a pause and throws me off.

-----

2 points by absz 6472 days ago | link

I used tem because I couldn't think of another word quickly, and everyone has seen temp used as a variable name. Your point about anaphoric- versus isa-, though, is a good one; I'd forgotten that, and that's just another reason I like ...? as the terminology. Using single characters can lead to collisions.

When I see (even? n), I read the "even?" as "even" with an upwards tone, not as "even" followed by a separator. Thus, the predicate call reads as a question in my head, which is what it's supposed to be. On the other hand, I find that #'foop reads like the word "foop," which doesn't mean anything. It's less severe with something like #'numberp, but nevertheless, I find ...p to be where the semantic collision lies.

And though you're worried about the removal of ...? as ssyntax, as nex3 pointed out (http://arclanguage.org/item?id=4849), one could explicitly allow a ? at the end, while still allowing it as ssyntax.

-----

1 point by Jesin 6469 days ago | link

And where does most ssyntax go? At the end of identifiers.

Also, consider that

  (foo? 'baz)
can be written as

  foo?!baz
Mixing punctuation like this gets weird.

-----

3 points by absz 6468 days ago | link

Actually, we right now have no ssyntax that goes at the end of identifiers. Arc has ten pieces of syntax. () and [] are circumfix. ' ` , ,@ and ~ are prefix. : . and ! are infix. The two syntax requests I recall off the top of my head were (1) being able to write $(...) for some reason, which is prefix; and (2) being able to write ($f ...) for (map f ...), which is also prefix. So from a preliminary study (admittedly, with very few data points, but that's all there are), it appears that prefix syntax is the most common.

And as for the foo?!baz observation? Don't do that then :) Seriously, I don't think that's a problem. Just because we can write something like ~+:/.3.1@-2.5!-1 doesn't mean we should. (If you're curious, that is currently legal and expands to (compose (complement +) (/ 3 1@-2 5 '-1)) [r@q is notation for the complex number with magnitude r and angle q, just in case you haven't seen it before.]).

EDIT: Used to say "that's actually probably a bug, since I was expecting it to expand to (compose (complement +) (/ 3.1@-2.5 '-1)), but how often will we be putting complex numbers inside ssyntax?," but that was wrong (see http://arclanguage.org/item?id=5090).

-----

2 points by eds 6468 days ago | link

That expansion isn't a bug. You just can't put floating point numbers into ssyntax.

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

-----

1 point by absz 6468 days ago | link

D'oh. How'd I miss that? Thanks.

-----


To be pedantic, it was proven that any program can be expressed in one line of APL (two if you need I/O).

In any case, I agree wholeheartedly: classes, if used properly, are an incredibly good way to streamline code. (Don't use them for everything, though. Then you get Java.) Ruby's mixins are actually very, very convenient, and seem to me to mesh well with Arc's approach: anything that can be cared and cdred can be mapped, too, and Arc doesn't care. But I feel like referring to this style as has-a is slightly weird, and it threw me off for quite a while. An object doesn't have-an Enumerable, it is-an Enumerable. On the other hand, an object does have-an #each method, so it does make some sort of sense.

Another advantage of combining mixins/has-a and Arc is that we get implicit mixins. In Ruby, you need to define #each and you need to include Enumerable to get all the Enumerable methods. But in Arc, since there are only functions, defining each would allow you to pass your object to all Enumerable functions (or their equivalent) without having to (include-mixin 'Enumerable 'MyType).

-----

3 points by almkglor 6472 days ago | link

My main objection is the current state of arc.arc : Every iteration construct works with lists or strings, but it won't work well with something that has 'car and 'cdr (they check by using 'acons and 'alist, which use (is (type foo) 'cons) - meaning I had to hack into 'acons and 'alist. For that matter I had to hack into 'isa too)

Generally is-a means "object is this and only this", meaning single inheritance, which was really my meaning. But a scanner isn't a cons (it's a subset of cons; it will fail on scar and scdr). It does has-a 'car and has-a 'cdr.

-----

2 points by Jesin 6463 days ago | link

I think the reason you keep saying has-a is that you're using conses as an example. A cons does has-a car and has-a cdr, but this is too restrictive. For example, say you wanted to make a type that acts like a list, that is, it supports map, each, reduce, all, rev, some, len, nthcdr, and so on.

  arc> (= a (my-listtype 'foo nil t 'bar))
  (foo nil t bar)
  arc> (car a)  ; has-a car
  foo
  arc> (cdr a)  ; has-a cdr
  (nil t bar)
  arc> (map no a)  ; has-a map (?!)
  (nil t nil nil)
  arc> (rev a)  ; has-a rev (?!)
  (bar t nil foo)
  arc> (some no a)  ; has-a some (?!)
  t
  arc> (all no a)  ; has-a all (?!)
  nil
See what I mean? (Note: I fully agree that it would be really cool if the above actually worked, I'm just arguing that the name has-a makes no sense here.)

-----

1 point by almkglor 6462 days ago | link

has-a scanner interface just means that: it has-a car and has-a cdr. 'map et al. now require an object which has-a scanner interface, and will simply use basic 'car and 'cdr operations to work. This supports genericity: just write 'map et al once, then any new type you create just needs to give 'car and 'cdr, and say it has-a scanner interface, and the existing map will work.

Now suppose we have another type, which has-a 'collide function, which handles the events where it is collided with in the game space. A ship has-a collide function, and the basic collission detection code is something like this:

  (thread
    (while t
      ((afn (game-elements)
         (iflet (first . rest) game-elements
           (each e rest
             (when (overlapping first e)
               (collide first) (collide e))))
       game-elements)))
The above now works on ships. Now suppose we add a new type of game element: a missile. We simply define its 'collide function, and declare it as having that function; now it magically works without changing the collision-detecting code.

-----

1 point by nlavine 6470 days ago | link

Agreed. This is exactly the problem that should be fixed. Your way would do it, although there are also some others.

Ironically, one great way is just to do no safety checks at all - the opposite of typing. I agree that we need something else, though.

-----

1 point by absz 6472 days ago | link

Right. I concur--it's just the name that I felt was slightly odd. The approach is a good one.

-----

More