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

I think I am going to say here that from the little I have seen of Factor (http://factorcode.org/) I really like its object system. Method calls look like normal words, but they work for anything that implements a method for that word. I'm going to use sequences as an example. Arrays, quotations (code blocks) and integers all implement the sequence protocol, so for example:

  { 2 7 1 } 3 add { 6 5 } append
makes the array { 2 7 1 3 6 5 }

  [ foo bar ] \ baz add [ foobaz barbaz ] append
makes the quotation [ foo bar baz foobaz barbaz ]

  4 7 add { "bar" "baz" } append 3 append
makes the array { 0 1 2 3 7 "bar" "baz" 0 1 2 }.

I think any object system we put in the language should include the ability to create types that define their own versions of functions like join, and the ability to inherit from other types.

This seems to fit well with the following design philosophy:

Can I? Yes.

Do I have to? No.

That is, it allows you to think about type definitions and OOP, but if you don't want to, you can still use types that you or other people have defined as if they were built in, without having to think about the OOP.

-----

3 points by Jesin 6612 days ago | link | parent | on: Does Arc need the character type?

Yes, the choice to have a separate character type surprised me. Just do it the way Python does it (or the way Python 3 is going to do it).

-----

1 point by Jesin 6614 days ago | link | parent | on: Map et al arguments are backwards

Several issues with this. First, this becomes impossible:

  (def dotprod (xs ys)
    (apply + (map * xs ys)))
How would you propose doing that? By messing with the fundamental semantics of Lisp lists?

Then there's the problem of thinking about it. Which is easier, thinking of

  (map a b)
as "map a onto b", or as "map b onto a" (or "map a under b")?

Prettiness of indentation in a few special cases of map, ability to map onto multiple lists, and consistency of language semantics. Pick two.

-----

1 point by absz 6614 days ago | link

That's not quite true, though. As I pointed out below (http://arclanguage.org/item?id=4704), you can set up map so that you could write

  (def dotprod (xs ys)
    (apply + (map xs ys *)))
Now, I'd rather have map stay as it is, as I've said. One should have fmap for "flipped map" which does this, and it may or may not belong in the core. After all, (map f xs) does read better than (map xs f). But even so, it is doable.

EDIT: The more I look at this, the more wrong it looks. I'm even more inclined against this; even if we have it, it shouldn't be called something so similar to map.

-----

1 point by tokipin 6614 days ago | link

for multiple lists, the lists would all go first and the function last. i don't see why this is a problem

as for what makes sense, that gets into SVO vs VOS etc and i don't think it is significant in programming. i know i don't read programs as if they were english. the most important portion of the expression is the word "map." once i see that word, i want to know what the function is and what the list(s) are because that's all that is relevant. conceptually, it doesn't matter what order they're in, and neither order makes more "sense." not for me at least

[edit]i've used map in both orders (in functional languages that don't have map, i make my own,) and again, i haven't noticed a difference besides one of readability

-----

1 point by absz 6614 days ago | link

Since most languages are SOV and SVO, Lisp already does not read like most human languages. Lisp is either VSO or VOS (depending on how it is written); the verb (function) comes first. However, the English or math-speak phrase here is "map f onto x". It is not "map x through f" or "map x by f;" neither of these is ever used. Set-builder notation writes { x/2 : x \in Z }; this is, in many ways, what map is based on, and it puts the function before the list. I find (map xs -) to be far less readable than (map - xs), not to mention (map xs ys +) vs. (map + xs ys). Furthermore, this way of writing it mimics function application: (car x) becomes (map car xs), and so on.

There is a slight gain in indentation-based readability with your version, but I'm not convinced it's substantial enough to warrant the less-readable, less-regular, less-common inversion to be the standard; at most, a provided variant, but probably something that one should define oneself.

And for what it's worth, if the function is particularly long, I usually write

  (map
    [foo (bar _)
         (frob nitz)
         (xyzzy (quux _ _)
                alpha)]
    betas
    gammas)
which preserves the visibility of all the arguments.

-----

1 point by tokipin 6614 days ago | link

i see your point about it mimicking function application, and that seems to me the reason if there was any for why that order was chosen

> I find (map xs -) to be far less readable than (map - xs), not to mention (map xs ys +) vs. (map + xs ys)

well, if the function is named, the order isn't as significant. i personally don't see a difference in either of those pairs, but compare (map + xs ys) to a version where + is a lambda, and likewise with (map xs ys +)

i wonder which usage is more common: map with a named function, or map with a lambda. i'm sure it is the lambda usage, but i haven't programmed much in lisp. it would be interesting to analyze some code and see some numbers

  (map betas gammas
      [foo (bar _)
           (frob nitz)
           (xyzzy (quux _ _)
                  alpha)])

  (map betas gammas (fn (a b)
      (foo (bar a)
           (frob nitz)
           (xyzzy (quux b a)
                  alpha))))
also, it could be made to accept any order. though i don't see a reason for that besides serving as a model for other functions w/ respect to the implied underscore notation

-----

1 point by absz 6614 days ago | link

Clearly, readability is largely personal preference. As I said, I like the syntax of your version for lengthy anonymous functions. But I don't see it as a huge net win. It might, on the other hand, be nice to have a mapover macro which turned

  (mapover as bs ... ys zs (a b ... y z)
    (do-stuff a b ... y z))
into

  (map (fn (a b ... y z) (do-stuff a b ... y z))
       as bs ... ys zs)
which might be clearer in the really-lengthy-function case. Here it is (lightly tested):

  (mac mapover (arg1 arg2 arg3 . arg4+)
    " The last two arguments to mapover are treated as the parameter list and body
      of a function `f', which is then applied to each element of the given
      sequences (the other, previous arguments) in turn; a list consisting of the
      results of this function is returned.  In short, this is equivalent to
      (map f arg1 arg2 ... argN), where `f' is the aforementioned constructed
      function.
      Note that there is *not* an implicit `do' around the body of the function;
      if there were, it would be impossible to tell where the lists ended and the
      function began.
      See also [[map]] [[each]]. "
    (withs (args  (apply   list arg1 arg2 arg3 arg4+)
            body  (last    args)
            parms (car:cut args -2 -1) ; 2nd to last
            lists (cut     args  0 -2))
      `(map (fn ,parms ,body) ,@lists)))
Note that it's limited in that there is no implicit do around the body of the function; since it can take any number of lists, there would be no way to tell where they stopped and the function began. Also note that this may well rely on the Anarki, but I'm not 100% sure if it does.

(And I'm sure someone will tell me that CL's loop can do this in 3... 2... 1...)

Overall, I do think that (map f xs) is cleaner in the named-, short-, and moderately-long-function cases, but it's always possible to write an inversion if you think differently. But what do you think of mapover as another approach?

-----

1 point by tokipin 6614 days ago | link

i wouldn't mind that, though it would probably be considered repetitive with map, and the first thing i would do would be (= map mapover) [edit]oops, macros aren't first class... yet

ya'll confuse me wit dem macros @_@. i made my own function called nap (the other option was pam, which rolls off the tongue with an undesirable cooking-spray sort of feel)

  (def nap args
       (apply map (car (rem acons args)) (keep acons args)))
i'm not exactly sure if it works as it should but it seems ok. i noticed a nifty application of this any-order form:

  arc> (nap '(1 2 3) < '(3 2 1))
  (t nil nil)

-----

2 points by absz 6613 days ago | link

Note that mapover is less general than map. It's explicitly designed for the "long anonymous function" case, so you cannot do

  (mapover '(1 2 3) '(4 5 6) +)
; instead, you must do

  (mapover '(1 2 3) '(4 5 6) (x y)
    (+ x y))
. This is why it is a macro: it needs to treat its last two arguments as part of a function body, so it cannot evaluate them. As a macro, it can package them up and put them in a function, which can be passed to map along with the lists.

nap is a clever function, but will oddly allow you to write (map '(1 2 3) < > '(4 5 6)), which is meaningless. Nevertheless, It's not a terrible idea.

-----

1 point by almkglor 6614 days ago | link

  (mac mapeach (var . rest)
    (if (acons var)
        (with (vals (firstn (len var) rest)
               body (nthcdr (len var) rest))
          `(map (fn ,var ,@body) ,@vals))
        (let (val . body) rest
          `(map (fn (,var) ,@body)) ,val))))

-----

5 points by Jesin 6615 days ago | link | parent | on: Password trouble

Whoa. I was browsing the forums on the same computer I had posted this topic from, and I looked up in the top right corner, and I noticed I had randomly gotten my account back. I guess it was buried somewhere in my browser's cookies and the recent cleanup I did uncovered it. I now shall change my password to something I will remember. I got lucky. Yay!

The bad news is that I needed to get lucky. I still say a password recovery thing would be helpful.

-----


Java, for a CS class. Meh.

-----

4 points by eds 6621 days ago | link

Yeah, same here. And what really scares me is that no one can see past the prison of Java, not even the professors.

I am trying to convert some of my friends over to the Lisp Way. Making a little progress, but most of my friends don't think they have time to learn Lisp on top of their other classes.

-----

7 points by kennytilton 6621 days ago | link

I have heard that even universities are held hostage by students who view college as merely job training, demanding courses in the languages business cannot see past.

Seems to me the unis should fight that fight, but there are a lot of unis in the US, they have to think about marketing, too.

Perhaps as the IT job market continues to shrink the masses will move on to something else and let the computer science departments go back to teaching algorithms.

-----

3 points by eds 6621 days ago | link

I haven't met many students that are set on learning Java and only Java (or insert other popular language of choice), mostly its just that they don't know anything better is out there. I have, however, met professors who hold very strong, and wildly incorrect views on Lisp (many of which probably haven't been accurate for 20 years or more). But how is a college freshman supposed to tell a guy with a PhD he is completely incorrect?

I've heard claims that they'll let me program in whatever language I want in upper division, but I have to wonder if that is true or not.

-----

3 points by kennytilton 6620 days ago | link

I am just telling you what I heard. From professors. At unis in England, come to think of it. Oh, and Brown, a top US school. Sad, I know. :(

-----

1 point by jcl 6618 days ago | link

IIRC, Brown has two introductory computer science tracks -- one that starts with Scheme and the other with Java, with the Scheme course recommended for majors. They've got one of the PLT Scheme implementors on faculty, too, so some of the advanced courses are Scheme-based, as well.

-----


Seems to me that currying would be an unnecessary hassle. Where would you actually use it?

-----


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 6621 days ago | link

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

-----

1 point by Jesin 6621 days ago | link | parent | on: Handling dotted lists

I haven't tested this and it's not very good anyway, but here's this:

  (def list* args
    (aif (cddr args) (cons (car args) (apply list* it))
         (cdr args) (cons (car args) it)
         (car args)))

-----


I wonder how we would deal with this:

  [(foo _ _) baz _]
Does that mean

  (fn (x) ((foo x x) baz x))
or does it mean

  (fn (x) ((fn (y) (fn (z) (foo y z))) baz x))

-----

1 point by cchooper 6624 days ago | link

It would mean the former. I think that's the only sensible way to do it.

-----

3 points by Jesin 6630 days ago | link | parent | on: The Factor Language

I am new to Factor, but I know enough to explain some of the basics. Factor, like Lisp, can do anything to a code block that it can do to a sequence. Observe:

  : until ( pred body tail -- )
      rot \ not add -rot
      while
  ; inline
Now, a line-by-line explanation (not that end-of-line means any more in Factor than it does in Lisp).

  : until ( pred body tail -- )
This starts the definition of until, and then says that it takes three values from the top of the stack (pred, body, and tail from bottom to top) and leaves none of them on the stack at the end. This particular word assumes that the 3 arguments it takes are quotations (although it does not state that; it's dynamically typed) (quotation is Factor's name for a code block).

  rot \ not add -rot
rot is a "shuffle word" with this stack effect: ( x y z -- y z x ), in this case that means ( pred body tail -- body tail pred ).

\ not pushes the word not rather than executing it, roughly equivalent to 'no in Arc.

add appends the not we just pushed to the sequence immediately underneath it, pred.

-rot has the stack effect ( x y z -- z x y ), in this case ( body tail pred -- pred body tail ).

  while
This is just a call to the built-in word while, which happens to have the same stack effect we use for until.

  ; inline
This ends the declaration, and tags the word as inline for the benefit of any optimizing compilers.

Whew. That was a lot harder to explain in English than it was to think about in Factor. Of course, anyone explaining Lisp code to a non-Lisper will have the same sort of difficulty. The point here is that you can modify blocks of code as instruction sequences and then execute them. Sound familiar?

  (mac my-until (test . body)
      `(while (no ,test) ,@body))

-----

More