Contexts as Objects

Started by kinghajj, September 09, 2007, 12:25:16 AM

Previous topic - Next topic

m35

#30
Quote from: "m i c h a e l"As you can see, these little critters are close to being objects (instance variables and methods), but without things like inheritance or constructors. Every time I try to implement the more complex aspects of OO using newLISP, I give up, wondering if all the object-oriented overhead and complexity is really worth it.


This OOP in newLISP interests me. When I was trying to duplicate some Python libraries in newLISP, I used a context approach similar to kinghajj's to create objects. It provided a simple but mostly effective way to do http://www.alh.net/newlisp/phpbb/viewtopic.php?p=8593">inheritance and constructors.

Jeff

#31
You can simulate nested contexts by using a few functions in main to maintain a list of incrementally named symbols that point to contexts:



http://artfulcode.nfshost.com/files/nested-contexts-in-newlisp.php">http://artfulcode.nfshost.com/files/nes ... ewlisp.php">http://artfulcode.nfshost.com/files/nested-contexts-in-newlisp.php
Jeff

=====

Old programmers don\'t die. They just parse on...



http://artfulcode.net\">Artful code

rickyboy

#32
Quote from: "Lutz"In one of his posts Kinghajj suggested a 'def-struct' macro. Inspired by this here is a 'def-class' macro which uses the context packaging mechanism only for the object maker, initialization, data setter and getter methods, but leaves the object data itself in a simple Lisp list.

Excellent Lutz!  This is the best idea I've seen so far for data abstraction in newlisp.  It's simple and clean.



Let me offer some, admittedly pedantic, advice.  I'd change def-class to evaluate to the context (class) name, by adding one more line:
(define-macro (def-class)
  (let (ctx (context (args 0 0)))
    (set (default ctx) (lambda () (args)))
    (dolist (item (rest (args 0)))
      (set (sym item ctx)
           (expand '(lambda-macro (_str _val)
                      (if (set '_val (eval _val))
                          (nth-set ((eval _str) $idx) _val)  
                          ((eval _str) $idx))) '$idx)))
    ctx))

That makes the REPL response easier on the eyes (and doesn't waste value output lines):
> (def-class (point x y))
point

Also I'd change point:difference to point:distance, and in the body of this function I'd also change the point coordinate references from such as (p1 0) to such as (point:x p1); so that you all in all have the definition:
(define (point:distance p1 p2)
  (sqrt (add (pow (sub (point:x p2) (point:x p1)) 2)
             (pow (sub (point:y p2) (point:y p1)) 2))))


Thanks Lutz -- I will use your code in my projects.  --Rick
(λx. x x) (λx. x x)

rickyboy

#33
Quote from: "Jeff"You can simulate nested contexts by using a few functions in main to maintain a list of incrementally named symbols that point to contexts:



http://artfulcode.nfshost.com/files/nested-contexts-in-newlisp.php">http://artfulcode.nfshost.com/files/nes ... ewlisp.php">http://artfulcode.nfshost.com/files/nested-contexts-in-newlisp.php


Good article, Jeff.   I noticed that your definition of function @, namely
(define (@ tree)
  (cond
    ((null? tree) nil)
    ((>= (length tree) 2)
      (if (> (length tree) 2)
          (@ (cons (context (tree 0) (name (tree 1))) (2 tree)))
          (context (tree 0) (name (tree 1)))))))

is, in essence, doing a left fold over the list (which you call tree) with the function
Quote(λ (acc x) (context acc (name x)))

So I'd rewrite @ to use apply (a left fold operator, by definition):
(define (@ lst)
  (if (and (list? lst) (> (length lst) 1))
      (apply (fn (acc x) (context acc (name x))) lst 2)))
(λx. x x) (λx. x x)

Jeff

#34
Yeah.  It was while I was exploring contexts, which was before I explored apply and letex.  I had a hard time getting apply- I thought it was funcall, not a folding operation.  At any rate, I offered up the article for the topic; I don't use that in my code.  I only use contexts sparingly now.
Jeff

=====

Old programmers don\'t die. They just parse on...



http://artfulcode.net\">Artful code

Lutz

#35
Thanks for the good suggestions Rick (return value for def-class and point:distance). There was also a suggestion by Michael to change the name from 'def-class' to something else, but I couldn't think of anything else and I have seen 'def-class' used in a similar way by other people and in other Lisps. In any case I am open to suggestions for a different name.


Quote from: "Jeff"I only use contexts sparingly now.


... and so do most, including my self, using contexts mainly for organizing code into modules, and this is what contexts in newLISP where designed for originally. The suggested 'def-class' function falls in that same category: it creates a module of specialized functions for a certain data type.



As an additional benefit 'def-class' helps in data abstraction and gives a bit of an OO look and feel when reading/writing the code. That "class" module created supplies a minimal set of data constructor and access functions.



For me contexts have one other mayor application area, which is using them as containers for dictionaries and hashes when dealing with huge amounts of data (thousands to millions) in natural language processing and often together with the 'bayes-train' and 'bayes-query' functions.



Perhaps the current 'newLISP Users Manual' is pushing the OO aspect of contexts too much and should more emphasize usage of contexts for organizing functions in modules and for data abstraction?



Lutz



ps: edited the original post from 10/4 with the context as return value.

m i c h a e l

#36
Quote from: "m35"When I was trying to duplicate some Python libraries in newLISP, I used a context approach similar to kinghajj's to create objects.


Quote from: "m35 elsewhere"I have been porting some code from Python to newlisp during the last few weeks


This brings up a good point. The porting over of one's code seems a common enough task when first trying a new language. And if your code is object-oriented and the new language is functional, you're faced with having to convert your code into a completely different way of programming. Do we yank out an object's methods into functions containing long case statements? How do we go from thinking of our code as a collection of interacting objects to thinking in terms of functions applied to data? I have yet to read, hear, or see anyone give a clear explanation of just how to do this. I'm afraid the functional/object-oriented paradigms reflect a deep difference in the way people think about problems. Afraid because I may be doomed to endlessly trying to create a decent object system within newLISP! ;-)



m i c h a e l

m i c h a e l

#37
Quote from: "Lutz"The suggested 'def-class' function falls in that same category: it creates a module of specialized functions for a certain data type.


Since you used the term 'data type' to describe what the functions in the module are for, what about using 'data-type'?


> (data-type (person last first))
person
> (data-type (book title author isbn))
book
> (set 'catch-22 (book "Catch-22" (person "Heller" "Joseph") "0-684-83339-5"))
("Catch-22" ("Heller" "Joseph") "0-684-83339-5")
> (person:first (book:author catch-22))
Joseph
> _


It's the same number of characters as 'def-class' and doesn't look at all like Common Lisp! (I began to loathe CL after reading all the unfair and condescending comments the CLers were making about newLISP.)



m i c h a e l

rickyboy

#38
Very nice suggestion, m i c h a e l.  ML-like languages use the data keyword to introduce http://en.wikipedia.org/wiki/Algebraic_data_type">algebraic data types, so you and Lutz are thinking along those lines.  For that reason, data-type (or data) makes sense to me too, and I'd vote for either of them as constructor names.



BTW, I wouldn't hate CL because of it's vocal adherents -- it's a really nice language and has its place in some settings.  The pompous a-holes though, oh my ...  I agree with you there.  :-)
(λx. x x) (λx. x x)

m i c h a e l

#39
Quote from: "Rick"Very nice suggestion, m i c h a e l.


Thank you! :-)


Quote from: "Rick"BTW, I wouldn't hate CL because of it's vocal adherents -- it's a really nice language and has its place in some settings.


Yes, that's true. Don't worry, I know it's not CL's fault ;-) I just wonder how a language affects the people who use it, or if the language is affected by them. Probably both. It's clear to me that programming languages attract certain types of people. Ruby and newLISP draw fun-loving and easygoing types, while something like C++ or Common Lisp attracts the "serious" and "superior" programmers. Yes, these are gross oversimplifications, but there may be a grain of truth to them.



m i c h a e l

frontera000

#40
I really like data-type.



One thing I noticed is how it maps to SXML. This way it can be used for defining data-type which can be turned into XML on the fly, which can give new capabilities to newLISP applications.



I really hope this becomes part of the language.

rickyboy

#41
Welcome back Bob!



BTW, m i c h a e l started another thread which continues our thoughts and experiments with data-type.  We discovered some limitations with it, in particular.  If you are interested and have some time, we sure could use your brain power.  Check out the continuation thread at http://www.alh.net/newlisp/phpbb/viewtopic.php?t=1933">//http://www.alh.net/newlisp/phpbb/viewtopic.php?t=1933.



--Ricky
(λx. x x) (λx. x x)

itistoday

#42
Hi, I'm a newLISP newBIE and while trying to understand Lutz's awesome macro I went through and formatted it nicely in C-style and added comments.  If there are any other newbies out there that are confused by it perhaps this may help:


(define-macro (data-type)
(let (ctx (context (args 0 0)))
; sets the constructor
    (set (default ctx) (lambda () (args)))
; create getters and setters
    (dolist (item (rest (args 0)))

(set (sym item ctx) ; creates something like point:x

; the reason expand is used is because we want the
; point:x method to print stuff based on a number,
; not the value of a variable $idx when it's called.
; In other words it's the difference between:
; (print (my-list $idx))
; and
; (print (my-list 5))

(expand '(lambda-macro (_str _val)
(if (set '_val (eval _val))
; if value is specified act as a setter
          (nth-set ((eval _str) $idx) _val)
; otherwise act as a getter
          ((eval _str) $idx)
)
)
; internal var representing current index
; for dolist expression
'$idx
)
)
)
ctx
)
)
Get your Objective newLISP groove on.