Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - m i c h a e l

#1
newLISP newS / Espionage in Macworld
May 15, 2010, 11:25:29 AM
Congratulations to Greg (itistoday) of Tao Effect for a positive review of his Espionage program in the June issue of Macworld (page 18).



Good show!



m i c h a e l
#2
It seems the links in the left-hand frame of the manual aren't working correctly in Chrome. Clicking on a link opens a new window with the non-frame version scrolled  to the end of the document. They work fine in Safari and Firefox, however, so it's probably just a Chrome issue.



m i c h a e l
#3
newLISP newS / What the FOOP?
March 17, 2010, 09:14:33 PM
I'm happy (and relieved) to announce the release of "http://www.neglook.com/movies/what-the-foop-H264.mov">What the FOOP?", a video overview of the current state of FOOP.



m i c h a e l
#4
I noticed while using net-eval that context doesn't actually switch the context:


> (net-eval "localhost" 4711 "(context 'C)" 1000)
C
> (net-eval "localhost" 4711 "(context)" 1000)
MAIN
> _


This is similar to what happens when using eval in the following way:


> (dolist (ea '((context 'C) (constant 'v 8) (context MAIN))) (eval ea))

ERR: symbol not in current context in function constant : MAIN:v
> _


Also, shouldn't constant work like set in the following example?


> (new Class 'Thing)
Thing
> (set 'Thing:attribute 1)
1
> (constant 'Thing:attribute 1)

ERR: symbol not in current context in function constant : Thing:it
> _


If you want to use constants for named indexes (a good idea), then you're forced to define your class within a context. This is a must for large, complex classes, but for simple classes, I like the minimalism of defining within the MAIN context.



m i c h a e l
#5
Anything else we might add? / Counting dup
July 13, 2009, 08:01:52 PM
Lutz,



This isn't really a request so much as sharing an idea: What would you think of adding $idx to dup?



Something like this:


> (dup (format "%c" $idx) 10)
("" "01" "02" "03" "04" "05" "06" "07" "08" "t")
> _


Of course, we can do it this way:


> (map (fn (ea) (format "%c" ea)) (sequence 0 9))
("" "01" "02" "03" "04" "05" "06" "07" "08" "t")


Or even:


> (map (curry format "%c") (sequence 0 9))
("" "01" "02" "03" "04" "05" "06" "07" "08" "t")


But neither of these seems as elegant as the dup solution. What do you think?



m i c h a e l
#6
Whither newLISP? / More Mutable FOOP
July 09, 2009, 08:50:40 PM
In my continued experiments with mutability in FOOP, I've discovered another technique that simplifies and unifies the previous system. It's done without the use of symbols stored in the MAIN context and doesn't require two types of objects (mutable and immutable).



The earlier technique required both kinds of objects because the contained objects needed to be immutable. Only the outside object could be mutable. This outer object controlled all of the little immutable objects within itself. If you wanted your outer object to become a part of another object—thus becoming an inner object—you would need to convert the formerly mutable object into an immutable one.



While not egregious, this complexity does make that technique less attractive. So on I continued into the mutable FOOP unknown.



Then one day, I began to store the object results of all methods (including constructors) in a variable within the appropriate classes. For example, sending :+ to two Points would not only give you the result, but it would store that result in Point:obj, as well. This would also allow multiple objects of different classes to be returned (removing a jar lid would leave the jar in Jar:obj and the lid in Lid:obj).



So how does this new way work? Like this:



First, we extend . . . oh wait. I haven't shown you the extend macro yet.


(set (global 'extend) (lambda-macro (sig)
(eval
(cons 'define (cons sig
(expand (args) (list (list (sig 0) (eval (sig 0)))))
))
)
))


So what does this code allow us to do? Here's an example:


> (new Class 'Point)
Point
> (Point)
(Point)
> (extend (Point:Point (x 0) (y 0)) (Point:Point x y))
(lambda ((x 0) (y 0)) ((lambda () (cons (context) (args))) x y))
> (Point)
(Point 0 0)
> (Point 10)
(Point 10 0)
> (Point 10 20)
(Point 10 20)
> (Point 10 20 30)
(Point 10 20)
> ; or just regular functions (not built-ins)
> (define (f n) (* n n))
(lambda (n) (* n n))
> (f 5 5)
25
> (extend (f n (n2 0)) (+ (f n) n2))
(lambda (n (n2 0)) (+ ((lambda (n) (* n n)) n) n2))
> (f 5 5)
30
> ; you can keep going, but be careful
> (extend (f n (n2 0) (n3 0)) (+ (f n n2) (* n3 2)))
(lambda (n (n2 0) (n3 0)) (+ ((lambda (n (n2 0)) (+ ((lambda (n) (* n n)) n) n2))
   n n2)
  (* n3 2)))
> (f 5 5)
30
> (f 5 5 5)
40
> (f 5)
25
> _


With this piece in our toolbox, we can continue on.



First, we extend . . . just a minute. We need one more function before we can extend Class:Class. A function called obj that gets and sets a class's obj variable:


(set (global 'obj) (fn (class that) (if that (setq class:obj that) class:obj)))


While this function is not strictly necessary, it does combine getting and setting, so it hides a little bit of detail (and as we'll see later, obj can be extended to handle multiple named objects).



With this, we can finally extend Class:Class:


(extend (Class:Class) (obj (context) (apply Class:Class (args))))


Now, we can use objects this way:


> (new Class 'Author)
Author
> (extend (Author:Author (last-name "") (first-name "")) (Author:Author last-name first-name))
(lambda ((last-name "") (first-name "")) ((lambda () (obj (context) (apply (lambda
      ()
      (cons (context) (args)))
     (args)))) last-name first-name))
> (Author)
(Author "" "")
> (Author "Heller" "Joseph")
(Author "Heller" "Joseph")
> (obj Author)
(Author "Heller" "Joseph")


Just one more piece needs to be redefined for the whole thing to work easily, and that's the access method we defined previously for the now-abandoned use of symbols:


(define (Class:access it idx value allow-nil?)
(if (or value allow-nil?)
(begin (setf (it idx) value) (obj (it 0) it))
(it idx)
)
)


There are only subtle changes made to :access to account for the new technique.



With this final piece in place, we can write Author's accessors:


(define (Author:last-name it last-name) (:access it 1 last-name))

(define (Author:first-name it first-name) (:access it 2 first-name))


Now, as long as we use the object stored in the class variable obj (through the matching obj function), we can treat objects as though they are mutable:


> (Author "" "Jerome")
(Author "" "Jerome")
> (:last-name (object Author) "Salinger")
(Author "Salinger" "Jerome")
> (:first-name (obj Author) "J.D.")
(Author "Salinger" "J.D.")
> (define (Author:string it) (string (:first-name it) " " (:last-name it)))
(lambda (it) (string (: first-name it) " " (: last-name it)))
> (:string (obj Author))
"J.D. Salinger"
> _


So far, I have found this to be quite natural in use.



For working with multiple objects, as mentioned earlier, the obj function could be extended to accommodate named multiple objects. In the following scheme, we use a Tree called Obj to store the objects:


(new Tree 'Obj)

(set (global 'obj) (fn (a b)
(if
(string? a) (if (object? b) (Obj a b) (Obj a))
(object? a) (Obj b a)
(string? b) (Obj b a:obj)
(a:? b) (setq a:obj b)
(nil? b) a:obj
)
))


Now we can do the following:


> (Author "Heller" "Joseph")
(Author "Heller" "Joseph")
> (obj Author "jh")
(Author "Heller" "Joseph")
> (obj (Author "Serling" "Rod") "rs")
(Author "Serling" "Rod")
> (obj "rs")
(Author "Serling" "Rod")
> (obj "jh")
(Author "Heller" "Joseph")
> _


There are two ways to work with the named objects: in one step or two.



Two steps:


> (obj (Author "Salinger" "Jerome") "jds")
(Author "Salinger" "Jerome")
> (:first-name (obj "jds") "J. D.")
(Author "Salinger" "J. D.")
> (obj Author "jds")
(Author "Salinger" "J. D.")
> (obj "jds")
(Author "Salinger" "J. D.")
> _


Now, one step:


> (obj (Author "Salinger" "Jerome") "jds")
(Author "Salinger" "Jerome")
> (obj "jds" (:first-name (obj "jds") "J. D."))
(Author "Salinger" "J. D.")
> (obj "jds")
(Author "Salinger" "J. D.")
> _


I've only started using this modified version of obj recently, so we'll see how it turns out.



That's it for this report. Stay tuned for further developments.



m i c h a e l
#7
Whither newLISP? / Mutable FOOP
June 03, 2009, 12:01:46 PM
Dear Club,



My continuing adventures in FOOP have led me to a new discovery: mutable FOOP objects.



By adding a self-reference to its second element, a mutable object can preserve its state without manually resetting the reference each time the object is updated. (Actually, manual resetting still occurs, but it's hidden within the object's methods.)



Preliminary disclaimer: Please remember this code is still experimental and unproven. Proceed with care. You can view (and the brave can download) the code http://www.neglook.com/code/mutable-objects.lsp">here.



First, let me introduce a class method and three object methods that can be included in your "init.lsp" file in case you do a lot of FOOP programming (or you could put it in a file called "foop.lsp" that you load before doing serious FOOP):


;; [class method] generic class predicate
(define (Class:? it) (= (and it (list? it) (it 0)) (context)))

;; making objects displayable
(define (Class:string  it) (MAIN:string it))
(define (Class:print   it) (MAIN:print (:string it)))
(define (Class:println it) (:print it) (MAIN:print "n"))


The class method :? is not essential for this demonstration, but it is included for completeness.



I've had these methods defined in my "init.lsp" for a long time now without any problems, but everyone's setup is different, so beware!



Next is the code for doing mutable objects:


(new Class 'Mutable)

;; note: mutable objects require accessors to update their state
;; an inherited helper method called :access simplifies accessor writing

;; the constructor creates the object's reference
(define (Mutable:Mutable id)
(set id (cons (context) (cons id (args))))
)

;; an accessor for the object's id (currently read-only)
(define (Mutable:id it) (it 1))

;; a helper method for writing accessors
(define (Mutable:access it idx value allow-nil?)
(setq this (eval (:id it)))
(if (or value allow-nil?)
(begin
(setf (this idx) value)
(set (:id it) this)
)
(this idx)
)
)


Next, an example Mutable class:


(new Mutable 'Point)

;; keeping a reference to the inherited constructor so we can overwrite it
(setq Point:^Point Point:Point)

;; overwriting the constructor
(define (Point:Point id (x 0) (y 0))
(Point:^Point id x y)
)

;; Point's x and y accessors using inherited :access method
(define (Point:x it value) (:access it 2 value))
(define (Point:y it value) (:access it 3 value))

;; Point's string representation
(define (Point:string it) (replace "MAIN:" (string it) ""))

;; moving a Point to a specific place (x y)
(define (Point:move it x y) (:x it x) (:y it y))

;; sliding a Point by some amount (x y)
(define (Point:slide it x y)
(:move it (MAIN:+ (:x it) x) (MAIN:+ (:y it) y))
)

;; adding two Points together
(define (Point:+ it other)
(:slide it (:x other) (:y other))
)


Finally, the code to produce a sample run:


;; a helper function that displays an expression and its result
;; as if it had been entered on the command-line
 (define (run e)
(print "> " (string e) "n")
(:println (eval e))
)

(println "Sample Run using Mutable Points")
(run '(Point 'p1 10 20))
(run 'p1)
(run '(:slide p1 5 8))
(run 'p1)
(run '(Point 'p2 88 99))
(run '(:+ p1 p2))
(run 'p1)
(run 'p2)
(println "> _")


Which produces the following output:


Sample Run using Mutable Points
> (Point 'p1 10 20)
(Point p1 10 20)
> p1
(Point p1 10 20)
> (: slide p1 5 8)
(Point p1 15 28)
> p1
(Point p1 15 28)
> (Point 'p2 88 99)
(Point p2 88 99)
> (: + p1 p2)
(Point p1 103 127)
> p1
(Point p1 103 127)
> p2
(Point p2 88 99)
> _


Before settling on symbols in the MAIN context for the references, I used a Tree named obj with string references. While this solution was adequate, it lacked the natural feel the symbols provide.



That's it! Mutable objects. Looking forward to hearing how they work for you!



m i c h a e l
#8
Anything else we might add? / Foil Spar
April 01, 2009, 12:26:06 PM
After much soul-searching (and repeated attempts to get my line/file-commander code working), I've decided I can no longer spare the time needed to promote newLISP. This is in no way a negative judgment against the language, so much as an admission of my not being a very good programmer.



Recently, I've been playing around with REALbasic, making a few GUI programs (one, the long ago promised "Cosmic Wimpout" scorer) and have been impressed with the progress I've been able to make. In fact, there are many things about REALbasic that remind me of newLISP.



I wish to thank everyone here at the club for all of your help and encouragement these past few years, and I hope to stop by for a visit from time to time.



As a parting gesture, here is the last newLISP code I'll probably be writing:



(select "foil spar" 7 -3 -1 2 -6 4 0 -8 1 3 -4)



m i c h a e l
#9
newLISP in the real world / wp in newLISP
December 09, 2008, 07:35:14 AM
Dear Club,



I came across this http://ptrace.fefe.de/wp/">listing of a word count program implemented in various languages (see http://ptrace.fefe.de/wp/README.txt">README.txt for more info). As you can probably guess, there was no newLISP version!



So I wrote the following, which seems to work:


#!/usr/bin/newlisp

(new Tree 'counts)

(while (read-line)
(dolist (word (parse (current-line) " "))
(counts word (inc (counts word)))
)
)

(dolist (each (sort (counts)))
(println (each 0) " " (each 1))
)

(exit)


Does anyone see room for improvement? If not, I'll submit this to Felix in a few days' time.



m i c h a e l
#10
Look what I found while browsing posts at reddit programming:



http://www.lispcast.com/drupal/node/30#comment-136">"Every language tells a story"



Upon scrolling to the end of the post, I discovered to my surprise our paren'ed newLISP dragonfly—along with the author's favorable impression of what he calls newLISP's story.



m i c h a e l
#11
Anything else we might add? / Vacuum-tube Lisp
May 25, 2008, 07:35:59 AM
cormullion,



Loved your last post at unbalanced-parentheses: "http://unbalanced-parentheses.nfshost.com/vacuumtubelisp">Vacuum-tube Lisp." I really appreciated the quote from "Slug" in light of the recent car/cdr thread.



Inspired by a chapter in a now-forgotten book, I once intended to write a song about the cddr/cadadr permutations. Someday, maybe I'll get around to doing it :-)



Also, your joke about giving up writing because of us Hollywood types made me realize something: videos can cover subjects only superficially, while writing can explore those subjects in true depth. It's like the difference between movies and novels. Maybe one day, we'll witness someone writing the following blog entry, "The newLISP Introduction movie was okay, but it really didn't do cormullion's original justice" ;-)



m i c h a e l
#12
newLISP newS / Shell Games
April 17, 2008, 10:39:11 AM
Dear Club,



I'm very happy to announce the first episode of a new video series called "Shell Games." They are short, command-line–centric videos showing newLISP in action. Shell Games, at first, will use examples taken from the newLISP documentation, but it might be fun to start a topic here (or use this one) where everyone could contribute code examples for future Shell Games videos.



But for now, just sit back and enjoy the first offering about number generators.



http://www.neglook.com/movies/shell-games-number-generators.mov">Shell Games - Number Generators



m i c h a e l
#13
Anything else we might add? / FOOP Scoop
February 04, 2008, 04:49:11 PM
FOOP Scoop!



If this is the mother of all constructors:


(define (Class:Class) (cons (context) (args)))


Then this must be the daddy of all predicates:


(define (Class:? obj)
  (and (list? obj) (not (empty? obj)) (= (obj 0) (context)))
)


Of course, for this to have real meaning within the context of your code, you must use the fully qualified method name when applying it:


> (Point:? (Point 23 54))
true
> (Complex:? (Complex 0.68 -1.64))
true
> (Complex:? (Point 0 0))
nil
> _


When using it this way, it's usually referred to as a class method.



The predicate's first two tests, (list? obj) and (not (empty? obj))), can become part of a function to test for objectness:


(constant (global 'object?)
  (fn (obj)
     (and (list? obj) (not (empty? obj)) (context? (obj 0)))
  )
)


With that, you could define the predicate this way:


(define (Class:? obj) (and (object? obj) (= (obj 0) (context))))


Even though these should be used as class methods, you can still apply the ? to an object using polymorphism:


> (:? (Point 23 43))
true
> (:? (Complex 0.33 0.11))
true
> (:? (CornFlakes (CornFlake) (CornFlake) (CornFlake) ...))
true
> _


But in essence, all you're really asking the object is: are you your own type? :-)



m i c h a e l



P.S. Even the ellipsis in the CornFlakes object can become valid newLISP code:


(set '... '...)


;-)
#14
Anything else we might add? / FOOP 3, Slide 118
January 30, 2008, 09:35:07 AM
While we're waiting for FOOP 4, I thought you might like to watch a video of the process of making one of the FOOP 3 slides.  Unfortunately, the animation preview is off-screen, so there are a couple of places toward the end where it seems like nothing is happening, but I'm actually just watching the preview :-)



http://www.neglook.com/movies/OneFOOPSlide.mov">One FOOP Slide



m i c h a e l
#15
I decided to dig up the http://www.angelfire.com/tx4/cus/shapes/index.html">link to a site that contains a number of object-oriented implementations of the classic shape example used in most OOP books. Armed with only Lutz's new macro, I set out to see how far I could get. I used the Ruby implementation as a starting point. Here's shape.lsp (note: I'm using data-type instead of def-class in the following code :-):


(load "/lisp/data-type.lsp")

(data-type (shape x y))

(define (shape:move shp newx newy)
(shape:x shp newx)
(shape:y shp newy)
)

(define (shape:r-move shp newx newy)
(shape:move shp (+ (shape:x shp) newx) (+ (shape:y) newy))
)


If you compare this code with the Ruby version, you'll see it's quite a bit shorter. And if you run it, you'll also see that it doesn't work!



Here is how I had to rewrite shape:move for it to function properly:


(define-macro (shape:move shp newx newy)
(nth-set ((eval shp) 0) (eval newx))
(nth-set ((eval shp) 1) (eval newy))
)


It works, but it also seems too low-level. I'm not even sure how to change shape:r-move to make it work correctly. Am I overlooking something? (Most probable.) Should a companion macro be introduced to create methods for these new data types? Will Lutz begin hating me for my unhealthy fixation on OO?! ;-)



m i c h a e l
#16
newLISP Graphics & Sound / FontComp
July 14, 2007, 12:50:54 PM
Dear Club,



I've been working on a program called FontComp using GUI-server, and because it will be quite some time before it's ready for mass consumption (all that messy platform-specific stuff), I wanted to share a http://neglook.com/movies/fontcomp-demo-2.mov">movie of it in operation in the meantime. This is only about 350 lines of unbummed code.



Out of all the ways I've built interfaces (Delphi, VisualBasic, TKinter (python), REALbasic, Interface Builder), GUI-server is my favorite by far. Thanks, Lutz!



m i c h a e l
#17
After my first few blundering attempts to impose upon newLISP my "baggage" programming tricks, I realized (with Lutz's patient help) the way into newLISP was not by force, but by acceptance. (This is beginning to sound like a self-help group meeting testimonial. How's that for a study: Programming Language Communities and Their Therapeutic Effects ;-)



One thing I'm seeing is that the myriad ways of testing, recording information about, and even classifying functions can be elegantly handled by contexts.



All of my functions for testing are in the testing context. Documentation can be found in the docs context. I put my global functions into the user context. After that, I make the function name a global constant holding the user-function from user. A skeleton of a file following this pattern looks like this:


(context 'user)

(define (f a b)
(+ a b (- b a)))

(context MAIN)

(constant (global 'f) user:f)

(define (docs:f)  ; not making any new symbols
(show {f
syntax: (f int-a int-b)

What the function does.

example:

> (f 1 3)
6
> (f 3 1)
2
> _}))

(context 'testing)  ; making new symbols

(define (testing:f)   ; context is needed (not the global f)
(let (f. MAIN:f)  ; and so is MAIN (not testing's f)
(test=
(f. 1 3) 6
(f. 3 1) 2
(f. 1 1) 2
(f. 3 3) 6)))

(context MAIN)


The functions show and test= are user-defined, and since they aren't vital to the discussion, I will just alert you to their existence. Also, the decision about whether or not to switch contexts before defining the test or doc functions depends on if I'm introducing new symbols. Usually, the testing functions end up needing new symbols, but docs rarely does.



Now, at the command line:


> (docs:f)
|
f
syntax: (f int-a int-b)

What the function does.

example:

        > (f 1 3)
        6
        > (f 3 1)
        2
        > _
|
> (testing:f)
testing:passed
> ;; I also modified Lutz's *help* macro to use the function
> ;; in *docs* (if there is one) for all user-defined functions
> (help f)
|
f
syntax: (f int-a int-b)

What the function does.

example:

        > (f 1 3)
        6
        > (f 3 1)
        2
        > _
|
> _


All of the tests for my functions are now located in just one context. The same goes for the documentation and user-defined functions used globally.



I think contexts are just begging to be explored for ways of structuring and reasoning about our newLISP programs.



This leads me back to somewhere close to where I started. And that is the acceptance of the language as it is. Nothing about a programming language is happenstance. Everything is there for a reason (although that reason may no longer be valid, hence the need for continual development). If I look at a language and see only ways it can be made more like this or that language, can I really say I'm seeing the language for what it is? If you look at your significant other and see only ways that person could be different, are you really accepting them as they are? Once you accept the language (and by this, I really mean its nature), you begin to see new ways of doing things and to feel the excitement of exploration again. With that, we can discover the beauty that is newLISP. If we were so impressed with our old language, why are we looking for another one?



As part of this exploration, I wondered if we could use contexts to classify even the built-in functions (lists, arrays, strings, maths, matrixes, i/o, etc). This way, we could see all the functions of certain types:


> (symbols strings)
(strings:address strings:append strings:char strings:dup
 strings:ends-with strings:encrypt strings:eval-string ...)
> _


We could add our user-defined functions to these classifying contexts, in addition to whatever context(s) they happen to be in.



I've really just started to think about the ways contexts can be used, but already, I'm seeing there is more there than meets the eye.



m i c h a e l
#18
I find I use this pattern quite a bit:


(define (f a b)
(set
'a (or a 1)
'b (or b 3))
(+ a b b a))
   



This is how a newLISPer gives default values to parameters.



Using a pattern becomes easier if it is encoded into the language. Rather than having to explain the steps necessary to implement the idiom (usually to a newbieLISPer), you can just point them to the right function.



Here is an example using an imaginary "idiom-encapsulating function" called default:


(define (f a b)
(default
a 1
b 2)
(+ a b b a))


With the steps required to give default values to parameters packaged up into a function, we can explain to others (or remember for ourselves) how to easily use defaults in function definitions.



In the spirit of implicit indexing, we could further simplify the code to something like this:


(define (f (a 1) (b 3))
(+ a b b a))


As with all my observations, they are not meant to be taken as implementation requests. Just aesthetic stirrings within my soul.



FFtI (Feel Free to Ignore)



m i c h a e l
#19
Anything else we might add? / For the Compleat Fan
July 02, 2006, 01:23:55 AM
Just noticed this section's description contains a spelling mistake. Those of you who can see which word it is, raise your hands. No, that's a stupid idea. I can't see any of your hands! Sorry, you can put 'em down :-)



m i c h a e l
#20
It seems our friends [text] and [/text] aren't feeling well (v.8.8.9 on OSX UTF-8.) Try this in the shell (or not, you must ctrl-c then x to stop it from thinking about whatever it's thinking about so hard):



> [text]
a
b
c
[/text]
^C
user reset -
(c)ontinue, (d)ebug, e(x)it, (r)eset:x
bash> _


Watch your processor(s) go nuts till you calm it/them down with the ctrl-c, x caress.



Is [/text] having an argument with [text]? Please talk to them, Lutz, and show them their differences are only syntax-deep ;-)



m i c h a e l