Hi! After learning newLISP for some times, here is my wish list ;-)
1. block/multi-line (nestable) comment; its syntax might be #{...}#
2. .0 is not removed when printing floats (e.g. 1.0 should be printed 1.0, not 1)
3. regex-option parameters should accept nil to mean not using regular expression (e.g. (find "x" "axbxc" nil 2))
4. inc (and dec, sequence, for) should correctly use either integer or floating-point arithmetic based on the type of current value (or of its additional argument) (e.g. (inc 1.2) should be 2.2, not 2; (inc 1 2) should be 3, not 3.0)
5. parameter names can be prefixed (or suffixed) with a marker (says &), and the corresponding arguments would be passed by reference (e.g. (define (my-pop &l (n 0)) (pop &l n)))
6. always return by reference (see //http://newlispfanclub.alh.net/forum/viewtopic.php?f=16&t=3433)
I'm not sure whether they will have any impact (backward compatibility, performance, integrity, etc.). What's your opinion?
Hi! Yes, I think everyone who uses newLISP wants to modify it... :)
I too have wondered about another multi-line text/comment tag f. Perhaps [comment] [/comment], consistent with [text] and [cmd]. Of course, you can usually use [text] [/text] for comments anyway...
Can't see the need for nil in find...
Personally I'm OK with the existing float/integer conversions in newLISP, although I can see that they might cause problems if you haven't found out about them - and some people find out the hard way that + and - do integer arithmetic... Perhaps inc and dec could be smarter without hardship though...
As for backwards compatibility - I have my own opinions! :) I'm ok with incompatible changes if there are substantial benefits in return, but it's less satisfactory when they're just minor compatibility issues or things that could easily be customized locally with a function or two. And maintaining two parallel bits of code for two or more releases is a bit of a chore. I prefer new powerful functions or extended functionality from existing functions!
I think that some of the goals of newLISP are to be as simple as possible, as small as possible, as powerful as possible, and as fast as possible. If you can argue that a change you're proposing can help move towards all of those goals, Lutz may not be able to resist implementing it!
Thank cormullion for your feedback.
As for block comment, a string cannot be used as an alternative for a comment in all places. For example, to "comment-out" an item (2) in a list, compare:
(list 1 "2" 3) # use string, not valid
(list 1
# 2 # use single-line comment, ok but need to reformat code
3 )
(list 1 #{2}# 3) # if block comment is supported
And for the syntax, frankly, I don't like [text]...[/text], [cmd]...[/cmd], [comment]...[/comment]. I think its too verbose.
As for nil in 'find' function, if I want to find a (non-regex) substring p in a string s starting at an index position i:
(find p (slice s i)) # work, but isn't slice will allocate memory; what if s is a very large string
(find (regex-quote p) s 0 i) # work, if we have defined 'regex-quote' ourselves, it's not built-in
(find p s nil i) # error, nil is not a number!
And for inc/dec:
(inc 1.2) # => 2, is this expected in most cases?
(float? (inc 1 1)) # => true!
I know that some changes can be implemented by defining my own functions (e.g. my-print, my-inc), but I think they are "normal" and should be "built-in".
Hi again! We can chat all day about this... :)
I know what you mean about verbosity in the language. However, I think that one of the characteristic of Lutz' newLISP approach is a preference for avoiding puntuation-heavy syntax, so the more verbose versions of things like [text] seem to win out over more compact and possibly ugly character combos. I like that, but I can see your point - an inline comment could be useful.
Quote
if I want to find a (non-regex) substring p in a string s starting at an index position i
I'm still struggling with this one. I would have this thought this would work:
(find p (i s))
(find p (i s) 0) ; regex
As for inc - well, you could argue that its main purpose is for incrementing symbols or list elements, and if you're relying on it to do your arithmetic you might be better off using + or add... That's not to say that it's not got it's surprises, though. Luckily the Introduction to newLISP has covered this area... :)
While we're talking about wish lists, how about a built-in version of this:
(define-macro (extend)
(setf (eval (args 0)) (append (eval (args 0)) (eval (args 1)))))
which is defined to fill the gap between set ...append and push:
(set 'lst (sequence 0 10))
(push (sequence 11 20) lst -1)
;-> (0 1 2 3 4 5 6 7 8 9 10 (11 12 13 14 15 16 17 18 19 20))
(set 'lst (sequence 0 10))
(set 'lst (list lst (sequence 11 20)))
;-> ((0 1 2 3 4 5 6 7 8 9 10) (11 12 13 14 15 16 17 18 19 20))
(set 'lst (sequence 0 10))
(set 'lst (append lst (sequence 11 20)))
;-> (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)
(set 'lst (sequence 0 10))
(extend lst (sequence 11 20))
;-> (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)
And a duplicates function to go with intersect and difference... But I can define my own versions, for now...
Quote
if I want to find a (non-regex) substring p in a string s starting at an index position
take a slice of s:
> (set 's "abcdefg")
"abcdefg"
> (find "de" (2 s))
1
http://www.newlisp.org/downloads/newlisp_manual.html#slice
For the inc/dec request, I must concur. The int/float conversion rules are confusing.
Could we have ++ and -- for integer operations, and inc/dec for floating operations? This would be consistent with the difference between + and add.
Ted
For the multiline comment, couldn't you just make "comment" macro? For instance,
(comment
blah blah blah
...
)
I would support the addition of the following two Scheme comment forms:
#;(s-expression)
#| block comment |#
Since the newLISP parser already checks for # comments, this would have the least impact when implementing. (And the Schemers have already fought out the "correct and proper" syntax for us, so text editors hopefully will suport it too ;p)
//http://en.wikipedia.org/wiki/Scheme_(programming_language)#Comments
Quote
Comments
Up to the R5RS standard, the standard comment in Scheme was a semicolon, which makes the rest of the line invisible to Scheme. Numerous implementations have supported alternative conventions permitting comments to extend for more than a single line, and the R6RS standard permits two of them: an entire s-expression may be turned into a comment (or "commented out") by preceding it with #; (introduced in SRFI 62 [17]) and a multiline comment or "block comment" may be produced by surrounding text by #| and |#.
-- xytroxon
Lutz,
Yes `slice` works, but in this case it will unnecessary allocate memory, right? It's not good if (find p (i s)) is used in a loop, when s is very large.
TedWalther,
comment macro does not work.
(define-macro (comment))
(list 1 (comment 2) 3) # => (1 nil 3), not (1 3)
xytroxon,
In my opinion, I think #{...}# is better than #|...|#, because it's easier to match the end of comment by using `%` in vim.
Thanks for all the suggestions. Some of them are covered in the next release.
Maybe some more general solution
(modify 'x + y) <=> (set 'x (+ x y))
(modify 'x append y) <=> (set 'x (append x y))
(modifyf x append y z) <=> (setf x (append x y z))
(modifyf x + y) <=> (setf x (+ x y))
This allows for slightly shorter, flatter but also slightly faster code, and weight is only one or two extra symbols.
For inc, I agree with Ted, ++ is constent here.
(I'd repeat my old proposal for +., *. etc for floating point +, * etc.)
Look forward with interest, Lutz - and slight trepidation... :)
Just thinking out loud - is there any use for a function that doesn't return anything at all? This could have various uses - Ted's comment idea - and other people have asked about the silent function. Yes, it would be inconsistent and a bit odd, but possibly useful in a number of different contexts...
Thanks a lot, Lutz! Curious about which wishes will come true ;-)
Kazimir, I like your floating-point operators (+., *., etc), first found it in your library, and hope they will be built-in too, so they will be standard names. Currently I do:
(setq +. add -. sub *. mul /. div %. mod)
As for, `modify`, I think using `$it` with `set` is OK
(setq x (+ $it y))
(setq x (append $it y z))
Well, here comes my two cents ;-)
Block comments would be nice, but I've been getting along without them. I can see where they would save a lot of work without editor support, though.
I like the symmetry of ++/inc and +/and, but I also like Kazimir's Caml-like +., -., etc., for the floating point versions of these operators, which contradicts the first option. ++. and --. perhaps? :-)
cormullion's suggestion sounds like a void function:
> (println "a" "b" "c")
abc
"c"
> ;; simulating a void function:
> (define (void) (silent) (print "> "))
(lambda () (silent) (print "> "))
> (void)
> (begin (println "a" "b" "c") (void))
abc
> _
I do find it distracting sometimes to see the output and the result from the print functions together. Since silent even silences the prompt, I often type (print "> ") at the end of my calls to silent so I'm not confused by the missing prompt.
Thanks for reminding me about the use of $it within the set functions, kks. I had forgotten about that.
Let's see, that looks to add up to about 1-3/4 cents. Close enough!
m i c h a e l
hi m i c h a e l! Nice to see you again. A nice void you've gotten us into, although yours is a cheshire-cat of a function, leaving a grin behind:
(list "a" "b" (void) "d")
-> ("a" "b" nil "d")
- it's whimsical, but I'm not sure it makes for readable inline comments anyway...
Quote from: "kks"
xytroxon,
In my opinion, I think #{...}# is better than #|...|#, because it's easier to match the end of comment by using `%` in vim.
I'ld like to see something like (== for the equality test and (= for (set (setq and (:= for (setf, but precedent tends to limit what you can do now and would be confusing to those coming from other Lisps.
Likewise, #|...|# is the block comment form for Common Lisp, hence is more likely to be recognized/expected by Lispers and Schemers, and be recognized by editors highlighting parser...
The Schemer's in-line comment is useful when experimentally trying out two forms of a function, especially if they have long argument lists.
(s-exp1 #;(s-exp2a ...) (s-exp2b ...) ...)
But editors are less likely to properly terminate the highlighted inline comment...
-- xytroxon
Quote from: "Kazimir Majorinc"
(I'd repeat my old proposal for +., *. etc for floating point +, * etc.)
like ocaml, right?
I like the proposed #; and #| comment forms, because of their compatibility with existing syntax hilighters. #; particularly has me excited.
As for Kazimirs +. ++. forms, those can be done as constants, right? I sort of liked the FORTRAN feel of add, sub, mul, etc.
For the == instead of =, I must disagree. Personally I have started using unicode characters in my code; for setf I use the unicode left-arrow character. For "and" and "or" and "find" I use some of the operators from set logic. UTF8 support is GREAT!
When I am doing trig, it is SOOO nice to be able to name variables "phi" and "theta", and be able to use the actual Greek letter instead of having to spell it out!
Yes, I had to configure vi a tiny bit to make it do auto-substitutions of some key sequences into their UTF8 form, but it leads to beautiful looking code.
Ted
For any who may be interested, here is my init.lsp. It shows the beautiful things you can do now that we have UTF8 support!
; Standard C/Unix filehandles that are open on startup
(constant
(global 'stdin) 0
(global 'stdout) 1
(global 'stderr) 2)
(define (dirname path) (join (chop (parse path "/|\\" 0)) "/"))
(define (basename path) (last (parse path "/|\\" 0)))
; Some arithmetic functions
(constant
(global 'negative?) <
(global 'positive?) >)
(define (divisible? i j) (= (mod i j) 0))
(constant
(global 'pi) (mul 4 (atan 1))
(global 'radians/degree) (div pi 180)
(global 'degrees/radian) (div 180 pi))
(define (radians deg) (mul deg radians/degree))
(define (degrees rad) (mul rad degrees/radian))
(constant (global 'do) begin)
; union 222a intersection 2229
(constant '≠ !=) # 2260 not equal
(constant '≡ =) # 2261 identical to
(constant '∈ find) # 2208 element of
(constant '≤ <=) # 2264 less than or equal
(constant '≥ >=) # 2265 greater than or equal
(constant '∀ dolist) # 2200 for all
(constant '× mul) # 00D7 multiply
(constant '÷ div) # 00F7 divide
(constant '√ sqrt) # 221A square root
(constant '⌈ ceil) # 2308 integer ceiling
(constant '⌊ floor) # 230A integer floor
(constant '⋀ and) # 22C0 n-ary logical and
(constant '⋁ or) # 22C1 n-ary logical or
(constant '⟵ setq) # 27F5 assignment
(constant '¬ not) # FFE2,00AC logical not
(constant '⋂ intersect) # 22C2 set intersection
(constant '⋃ append) # 22C3 set union
(define (∑ lst) # 2211 n-ary summation
(apply add lst))
Hi cormullion!
The operative word in my example is "simulating" ;-) Lutz would have to implement it properly to have the correct effect.
I've been quietly working on exploring FOOP (especially the new mutability!) and putting together another video. Hope to have something to share in the near future.
m i c h a e l
Quote
... and putting together another video
thanks Michael, for taking care of this! I hope the last fixes for 'self' work for all situations one might encounter. The test routines you emailed me have been appended the modified qa-foop file (v10.1.9).
FOOP is ready for primetime now!
... and still functional enough to call it FOOP :)
ps: several suggestions in this thread have been implemented and we will have another development release before 10.2.
Lutz - I'm currently using both FOOP version 0 and FOOP version 1. v0 works for current stable releases, v1 works for curent development releases. Eg //http://unbalanced-parentheses.nfshost.com/dragonfly_twitter is using v0 because NFS is on v0 (ie 10.1).
Is there a way to add compatibility to v1 to work with v0? Or a way to define things so that allow the newLISP installation can be upgraded without me having to write separate versions of the FOOP file?
Quote from: "Lutz"
thanks Michael, for taking care of this!
You're welcome! I'm very happy to help in my small way.
Quote from: "Lutz"
I hope the last fixes for 'self' work for all situations one might encounter.
I've been really exercising self quite a bit lately. It's performing brilliantly. Feels very natural for both newLISP and programming with objects.
Quote from: "Lutz"
and still functional enough to call it FOOP :)
I keep meaning to ask you something, Lutz. When you say:
Quote from: "Lutz"
The fact that each object in FOOP is the functional expression which generates itself - its own constructor expression - still justifies the 'F' in FOOP.
It makes me wonder if having constructors with default arguments breaks with this:
> (new Class 'Point)
Point
> (define (Point:Point (x 0) (y 0)) (list (context) x y))
(lambda ((x 0) (y 0)) (list (context) x y))
> (Point)
(Point 0 0)
> _
Or is the fact that (Point) always gives us (Point 0 0) what makes it functional?
What I do know is that coding in FOOP has been more fun than programming in traditional object-oriented languages. So FOOP may as well stand for Fun Object-Oriented Programming! Or another F-word when I can't get the damn code to work ;-)
m i c h a e l
Yes, when you modify the default constructor functional analogy of object<->construtor is somewhat different, but not broken. Then there is also the new (self) a Function to reference the target object of the message.
Quote
Fun Object-Oriented Programming
We also could invent some sort of tag-line including both the word Fun and Functional and leaving the interpretation open to the public?
Regarding old/new FOOP compatibility. I don't see an easy automated way, but at least it is easy to port from old to new by simply renaming the object parameter in old FOOP code to 'self':
; old FOOP code original
(define (method obj p1 p2)
...
(... (obj 1) ...)
)
; old FOOP code prepared for upgrade
(define (method self p1 p2)
...
(... (self 1) ...)
)
; new FOOP code after taking ode self from the parameter list
(define (method p1 p2)
...
(... (self 1) ...)
)
Of course this doesn't take advantage of object mutability, which enables shorter and faster code for modifying objects. But at least old code can quickly be prepared and made work for the switch-over to a newer newLISP version.
I would probably just code two sections (or even files): one for old, one for new FOOP and then decide by the version number in 'sys-info'.
Quote from: "Lutz"
We also could invent some sort of tag-line including both the word Fun and Functional and leaving the interpretation open to the public?
I think FOOP is as much about fun as it is about fitting gracefully into a functional language. I'm delighted by how well FOOP blends with newLISP. And besides, functional has another meaning that might be the most appropriate yet:
Quote
designed to be practical and useful, rather than attractive.
Of course, I find FOOP attractive, too, but it's definitely practical and useful. The complexity of the object models I've done in newLISP blows away anything I've managed to accomplish in other languages.
Leaving it open to interpretation is fine by me. A rose by any other name . . .
Quote from: "Lutz"
but at least it is easy to port from old to new by simply renaming the object parameter in old FOOP code to 'self'
This is ingenious, Lutz.
Back to FOOPin',
m i c h a e l
Funambulistic* Object Oriented Programming
* A "funambulist" is a tightrope (or slack rope), walker or dancer...

(//%3C/s%3E%3CURL%20url=%22http://www.damiatimoner.com/images/el_funambul_gran.jpg%22%3Ehttp://www.damiatimoner.com/images/el_funambul_gran.jpg%3C/URL%3E%3Ce%3E)
Damià Timoner's "El Funàmbul" (2007) (//http)
Quote
("El Funàmbul") contains 10 instrumental pieces; 5 new Damià composicions and 5 covers from different bands as famous as The Doors, Nirvana, Depeche Mode, adapted to the Spanish guitar sound.
Reminds me of Lutz and newLISP, classical approach, yet so avant-garde ;p>
-- xytroxon
As for new FOOP, is `self` a function or a list? And how can I use association list for fields? In old FOOP, I can do:
(define (C:C x y) (list C (list 'x x) (list 'y y)))
(define (C:p o) (println "x=" (lookup 'x o) "; y=" (lookup 'y o)))
(:p (C 1 2)) # x=1; y=2
By the way, is it a good idea if newLISP extends `nth` to call `lookup` for non-number indices? (Another wish ;-)
(setq L '((a 1) (b 2) (c (d 3))))
(list (L 'a) (L 'c 'd) (L 2 'd)) # => (1 3 3)
And when an index is out-of-bound, why not `nth` just return nil instead of throwing an error? I found that I usually need to check the length of the list first.
(setq L '(a b (c d))
(L 1) # => b
(L 5) # ERR: list index out of bounds
(and (> (length L) 5) (L 5)) # => nil
(and (> (length L) 2) (> (length (L 2)) 1) (L 2 1)) # => d
Currently, I just do:
(define (nth? Idx Seq (Default))
{like nth, but return Default if Idx is out of bound or Seq is not a sequence}
(let (R)
(if (catch (nth Idx Seq) 'R) R
(find "index out of bounds|list expected" R 0) Default
(throw-error R) )))
(nth? 5 L) # => nil
(nth? '(2 1) L) # => d
But as you see, isn't just (L 5) better than (nth? 5 L)?
By the way, could someone please tell me how to have newLISP's readline history across sessions?
Quote
As for new FOOP, is `self` a function or a list?
its a function:
(self 1) is equivalent to ((self) 1)
without any argument it returns the object list, with arguments it indexes the object list.
There is a chapter about objects and associations in the manual:
http://www.newlisp.org/downloads/development/newlisp_manual.html#foop
You also can use predefined indexes and index vectors:
(new Class 'Person)
(context Person)
(constant 'age 1)
(constant 'height '(2 0))
(constant 'weight '(2 1))
(define (set-weight w)
(setf (self weight) w))
(context MAIN)
(set 'joe (Person 35 '(1.75 165)))
;; or because its all constants
(set 'joe '(Person 35 (1.75 165)))
(joe Person:weight) => 165
(:set-weight joe 180)
(joe Person:weight) => 180
Quote
And when an index is out-of-bound, why not `nth` just return nil instead of throwing an error? I found that I usually need to check the length of the list first.
This would create ambiguities with the following case:
(set 'l '(a b nil c d nil))
(l 2) -> nil
(l 5) -> nil
use a negative index to count from the end:
(set 'l '(a b c d e f g))
(l -2) => f
see also here:
http://www.newlisp.org/downloads/development/newlisp_manual.html#indexing
Quote from: "Lutz"
You also can use predefined indexes and index vectors:
This is how I've been defining my objects lately. It not only makes clear which attribute you are referring to, but it also allows you to freely add or reorder an object's attributes without needing to change any of its methods. As the complexity of an object grows, so does the need for named indexes. Together, self and setf act as an object's getters and setters.
m i c h a e l
Quote from: "Lutz"
Quote
And when an index is out-of-bound, why not `nth` just return nil instead of throwing an error? I found that I usually need to check the length of the list first.
This would create ambiguities with the following case:
(set 'l '(a b nil c d nil))
(l 2) -> nil
(l 5) -> nil
That code is somewhat confusing (lowercase "L" looks like the number one "1" on my browser)... And the indexing problem is not shown clearly...
(set 'lst '(a b nil c d nil))
(lst 2) -> nil
(lst 4) -> d
(lst 5) -> nil
; without index bounds checking
(lst 6) -> nil
; with index bounds checking
(lst 6) -> ERR: list index out of bounds
Flagging an invalid index value is not an inconvenience... It is a responsible language practice... And it helps ensure code reliability... Not knowing that an index is sometimes out of range can easily hide a buggy program design that works most of the time...
-- xytroxon
Thanks Lutz for clarifications
I think kks's proposal for (nth L 100000...) = nil is not unreasonable. It is analogous to
(1) Previously undefined variables, if used for first time, have value nil
(2) Some functions, for example, find or exists return nil if they cannot return value caller asked for.
Ambiguity, however, exists. For example, if function call](exists (lambda(x)(not (integer? x))) L)[/b]
returns nil, we cannot be sure whether L actually contains nil, or it contains only integers.
But, what caused the problem? In my opinion, problem is in function exists which returns two information compressed in one value. One information is: is there any non-integer in L? Other information is - if there is non-integer in L, which one is that? In most cases, we can compress these two information, but if that non-integer is the same value we use to inform that all members of L are integers, we're lost.
Why we readily use such compression? Because if it works correctly, and it does in most of the cases, it is handy. Our programs are shorter and simpler. But, once we discovered that it doesn't work correctly in all cases, we shouldn't ignore it. Such imprecisions and ambiguities accumulate, and result in short, but not very understandable programs. What is the correct way out of that? I think that for all such ambiguous, lossy functions need lossless version. For example,
(exists/losless (lambda(x)(not (integer? x))) L)
should return (true nil) if nil is element of L, and (nil) if there is no non-integer elements in L.
Beside that, it is maybe best to keep lossy versions as they are, because these are handy and because of compatibility. Maybe. "Default" version might be either one.
Back to kks's proposal, I think both nth/lossy and nth/lossless have sense.
Or, like `lookup`, adding a parameter to `nth` for a "default value" to return in case an index is out of bounds:
(nth 5 '(1 2 3) 0) # => 0
But Kazimir's suggestion is more general, in case we don't know a value that would never exist in the list.
Thought I would get this thread going again with some more simple things that we might do to jazz things up.
1. I also put my vote in for Kazimir's operators +. and such. They look better and are easier to read.
2. I would like to see some of the math functions overloaded to do common vector operations. For instance, if vec
is a vector (a list of integers or floats):
(+ vec) returns (apply + vec)
(add vec) returns (apply add vec)
(* vec) returns (apply * vec)
(mul vec) returns (apply mul vec)
(pow vec) returns (apply add (map mul vec vec)) ;the sum of squares
(pow vec n) returns (i1^n + i2^n + .... + iN^n) the sum of the nth power of the elements
(sqrt vec) returns (sqrt (pow vec)) ;the vector norm
(div vec) returns the unit vector vec/norm
The cost of adding these is minimal but the gain for vector math is great in that we can use conventional functions
instead of a plethora of new ones. Vector expressions will also be greatly simplified.