Interesting problem for me

Notices and updates
ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

DrDave wrote:To pass the time while awaiting my turn at the medical center
O_O

No comment... :-)

(I have my best idea into the bathroom! Everyone has its own place to think, to ponder :-)

Great!
--

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

you could make it even shorter putting the 'pop' inside the 'if'

Code: Select all

(while lst
     (if (setq myeven? (not myeven?))
         (push (upper-case (pop lst)) newList -1)
         (push (pop lst) newList -1)
     )

DrDave
Posts: 126
Joined: Wed May 21, 2008 2:47 pm

Post by DrDave »

Lutz wrote:you could make it even shorter putting the 'pop' inside the 'if'

Code: Select all

(while lst
     (if (setq myeven? (not myeven?))
         (push (upper-case (pop lst)) newList -1)
         (push (pop lst) newList -1)
     )
Right, I considered that. But because no matter what happens in the 'if' block, there will be a 'pop', I decided to factor it out and write it just once.

Do you think it will make a speed difference?

Nevermind... I tested it. It DOES make it a bit faster to in-line the 'pop'. From a bit over half a second runtime to a bit under.
...it is better to first strive for clarity and correctness and to make programs efficient only if really needed.
"Getting Started with Erlang" version 5.6.2

Kazimir Majorinc
Posts: 388
Joined: Thu May 08, 2008 1:24 am
Location: Croatia
Contact:

Post by Kazimir Majorinc »

ale870 wrote:Lutz, is there any way (generally speaking) to make a function that return a reference to an element of a list (like in the example before) instead returning a copy? Can I do that using contexts?
Symbols can be used as references.

(set 'L (list 'L.0 'L.1 'L.2))

(set 'return-by-reference (lambda(lst i)(nth i lst)))
(set (return-by-reference L 0) "i!")
(set (return-by-reference L 1) "o!")
(set (return-by-reference L 2) "let's go!")

(set 'dereference-list (lambda(lst)(map eval lst)))
(println (dereference-list L))
;("i!" "o!" "let's go!")

It has its price, but I think it is The Way.

ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

@Kazimir can you help me to understand what's happening here?!

Code: Select all

(set 'L (list 'L.0 'L.1 'L.2)) 
What's happening in newLisp with that syntax?

And, generally, speaking, can you help me to understand your example? It seems really interesting and using advanced tricks, but I'm lost after the first row!!

What's happening there?

Thank you!
--

DrDave
Posts: 126
Joined: Wed May 21, 2008 2:47 pm

Post by DrDave »

@Alesandro, you've been too long without alcohol in your system resulting in cloudy thinking LOL

It's all straight-forward, if you take it bit-by-bit.

Code: Select all

(set 'L (list 'L.0 'L.1 'L.2)) 
This creates the list (L.0 L.1 L.2) and binds it to L.

Code: Select all

(set 'return-by-reference (lambda(lst i)(nth i lst))) 
This just defines a function. It is identical to writing this:

Code: Select all

(define (return-by-reference lst i) (nth i lst))
This function has two paramters, a list and an integer used as an index. The function body finds the ith member in the list and returns it.

Code: Select all

(set (return-by-reference L 0) "i!") 
(set (return-by-reference L 1) "o!") 
(set (return-by-reference L 2) "let's go!") 
These three lines work the same. They simply set values to each member of the list L. It's a generic way to do this on a list

Code: Select all

(set 'L.0 "i!" 'L.1 "o!" 'L.2 "let's go!")

Code: Select all

(set 'dereference-list (lambda(lst)(map eval lst))) 
This is the same as

Code: Select all

(define (dereference-list lst) (map eval lst))
You can see that it take s a list as a paramter, then evaluates each member of the list.

Code: Select all

(println (dereference-list L))
This is doing

Code: Select all

(eval L.0 )
(eval L.1)
(eval L.2)
...it is better to first strive for clarity and correctness and to make programs efficient only if really needed.
"Getting Started with Erlang" version 5.6.2

ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

Thank you, functional languages are still "a new thing" for me, even after many months and several bottles of alchol :-) !
--

DrDave
Posts: 126
Joined: Wed May 21, 2008 2:47 pm

Post by DrDave »

ale870 wrote:Thank you, functional languages are still "a new thing" for me, even after many months and several bottles of alchol :-) !
It will make more sense the more you use it. I'm just a casual programmer, not a hard-core computer scientist like Kaz or Lutz or some of the others.

I'm not sure, but I think Kaz used 'return-by-reference' for his function name to emphasize that a pointer is being used rather than returning a copy of the actual value. Someone will verify or correct this, I'm sure.
...it is better to first strive for clarity and correctness and to make programs efficient only if really needed.
"Getting Started with Erlang" version 5.6.2

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

There is an easier, straight forward and safe way to pass and return data by reference to and from user-defined functions, when using default functors:

Code: Select all

(set 'data:data '(a b c d e f))

(define (foo lst x)
	(push x lst)
	lst)

(foo data 99) => data

data:data => (99 a b c d e f)

; push one more than use the return value

(reverse (foo data 98)) => (f e d c b a 99 98)

data:data => (f e d c b a 99 98)
so basically when you call the function you pass the namespace handle only, which will pass it by reference and return it again. All list/array/string functions in newLISP now if they see a context they have to look for the list/array/string inside the default functor of the context which is <context>:<context>

newdep
Posts: 2038
Joined: Mon Feb 23, 2004 7:40 pm
Location: Netherlands

Post by newdep »

It will make more sense the more you use it.
Personaly i have this problem ->
.. If you start studying it, its getting even more difficult ..
not because of its complexity but because of it flexibility.. ;-)
-- (define? (Cornflakes))

ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

@Lutz, I think functors are the best way to manage references. They are easy to be used, fast and readable.

@newdep, that is normal. In fact, while you are studying a programming language, you want to face more and more complex problems, and every problem open a door with many possible solutions inside. But in order to apply a solution, you need to acquire more knowledge. Furthermore, more a language is "flexible", more solutions you can find, and more things you need to learn to apply them. I love this!
I really like progrmaming languages, I study some of them only to get the "phylosofy" that is behind them. Instead I learnt other languages to use them for specific jobs or for every-day-usage. I know more than 15 languages but, of course, I know very well only some of them.
newLisp is one of those languages I started to study just for curiosity, and to learn some basics of functional languages. But in the time, I discovered that it's a powerful tool, and that Lutz made a great job with it.
So I decided to "promote" it to "everyday-language".
But in the time I even discovered that it was a good language not only for scripting, but even for something more complex. So... I'm here to discuss with you, in order to learn every day something more, and to help other guys (this is the reason I opened one italian blog site).
--

xytroxon
Posts: 296
Joined: Tue Nov 06, 2007 3:59 pm
Contact:

Post by xytroxon »

Hi all!

This past weekend I was trying to automate the word list, but had a problem on Windows 98se (48 megabytes of memory)...

This code slows down to a dead crawl, unless I add (inc ctr) after (push (string ...and then everything works fine...

Code: Select all

; Create all 456976 English four letter words...
; ( Warning:  May be offensive to some sensitive programmers ;)
(for (z 97 122)
  (for (y 97 122)
(print (time ; begin timing debug
    (for (x 97 122)
      (for (w 97 122)
        (push (string (char z) (char y) (char x) (char w)) word-list -1)
        ; (inc ctr) ;<<< uncommenting this statement makes time linear
      )
    )
) ",") ; end timing debug
  )
)
(println ctr " - " (length word-list) " words.")

(setq source-list (copy word-list)) ; copy list before each pass
; trust newLISP, but verify... ;)
(println (slice source-list 0 32))
(println (slice source-list -32))
(exit)
Does this work for you on other systems? Or have I found a strange problem with newLISP? May need to add another (for or two for larger memory systems...

-- xytroxon
"Many computers can print only capital letters, so we shall not use lowercase letters."
-- Let's Talk Lisp (c) 1976

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

I think that must be a bug. It doesn't appear to matter what you insert - a number or string, just anything other than the push result. Older versions of newLISP don't show this behaviour...

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Its the returning of the growing word-list getting longer and longer from the 'for' statement.

Instead of inserting (inc cnt) you can put any thing else i.e. true or nil, which changes the return to a smaller piece of data.

added later:

In older versions 'push' returned the pushed element, so the return value as last fucntion in a 'for' loop was always small.
Last edited by Lutz on Thu Dec 18, 2008 2:17 am, edited 1 time in total.

DrDave
Posts: 126
Joined: Wed May 21, 2008 2:47 pm

Post by DrDave »

I didn't try to figure out your code, but just ran it. As you said, incrementing your counter and it zips through. Comment it out and it crawls, getting slower as it progresses.

newLISP 10.0.0 WIN32 XP pro
...it is better to first strive for clarity and correctness and to make programs efficient only if really needed.
"Getting Started with Erlang" version 5.6.2

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

But Lutz I thought it returned a reference rather than a copy?

- ah wait, it's the return of for not push... ?

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

There is a list of all of them here:

http://www.newlisp.org/downloads/newLIS ... lease.html

Its basically everything except user-defined functions and macros and 'for' and all other iterators with a local looping variable, like 'dotimes', 'dolist', 'doargs' and 'dotree'.
Last edited by Lutz on Thu Dec 18, 2008 1:20 pm, edited 1 time in total.

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

... so the following is possible:

Code: Select all

> (set 'l '(1 2 3))
(1 2 3)
> (reverse (begin (push 99 l)))
(3 2 1 99)
> l
(3 2 1 99)
> 
the reference passes through the 'begin' without a problem.

Note that 'push' in older versions always returned the pushed element, now it returns a reference to the list.

starting version 10.0.1 the 'for' loop will return the reference, so there will be no slowdown.
Last edited by Lutz on Fri Feb 06, 2009 6:43 pm, edited 2 times in total.

Kazimir Majorinc
Posts: 388
Joined: Thu May 08, 2008 1:24 am
Location: Croatia
Contact:

Post by Kazimir Majorinc »

Yes, DrDave, that was everything right. Henx.

ale870
Posts: 297
Joined: Mon Nov 26, 2007 8:01 pm
Location: Italy

Post by ale870 »

Using references is a big improvement even to speed up the code.
Lutz, it means now the functors can be substituted in some way in the program, isn't it? In fact, in the past, we used functors to pass values by reference, but now they could be useful only for user-defined functions.

Ones question: Is there any reason (e.g. performance) to still use functors instead native reference-passing?

If I find a situation where I can use either functors or function reference, is there any tip to decide what's the best way to follow?
--

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

All built-in functions automatically pass references in and out for lists, strings and arrays. Only with user-defined functions and macros you need default-functors for reference passing in and out.

If the majority of lists and strings in a program are small, then don't worry about the whole thing. When lists or strings get bigger than a hundred elements then you might consider reference passing, but only if some operation on them occurs frequently.

In older versions everything in newLISP was value passing by default and newLISP was still considered one of the fastest scripting languages (see http://www.newlisp.org/benchmarks/ )

But the reference passing issue is not just about speed. Reference passing also allows you to write destructive user-defined functions without recurring to macros or passing quoted symbols (1).

From a programming style point of view, I would say that value passing and non-destrcuctive user-defined functions are the cleaner, safer and more intuitive way to write bug-free functional programs. But from a practical point of view, you need reference passing to efficiently deal with large data objects, when you want to avoid frequent copying. Then default-functors are the most straight forward method in newLISP.

(1) Traditionally reference passing can also be achieved using either macros or passing quoted symbols to user-defined functions. This method is not recommended because it brings a whole basket of other problems, i.e. variable capture. There are ways around it, but they lead to complex code. Some of Kazimir's blog posts investigate these problems in greater detail.

Locked