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.
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.
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
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
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
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?
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)
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.
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.
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.
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.
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.
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.
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.
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))