Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

On list! inconsistency [was Re: WYSIWYG programming]

 [1/17] from: joel:neely:fedex at: 30-Oct-2000 8:26


[rebol-bounce--rebol--com] wrote:
> > ... Most of the series references have > > unaltered positions, but for the list! case, the
<<quoted lines omitted: 4>>
> namely doubly linked lists, and how they are implemented in > REBOL.
EXACTLY my point. The user's life is made more awkward (having to remember exceptions) to make the implementor's life easer. THAT'S BACKWARDS and out of character with e.g., the lovely way that net protocols are presented through an elegant, consistent interface that PROTECTS the user from the underlying details of implementation.
> It's a question of docs.
No. It's a matter of design. Someone CHOSE to put the burden on the user instead of the implementor. Implementing list mutations as a "black sheep" was a design/implemention decision. Yes, all such decisions should be clearly stated, but clearly stating the choice is different from addressing whether the choice benefits or costs the user. -jn-

 [2/17] from: jeff:rebol at: 30-Oct-2000 5:54


Howdy, Joel: [...lists are the black sheep of series...]
> > It's a question of docs. > No. It's a matter of design. Someone CHOSE to put the
<<quoted lines omitted: 4>>
> clearly stating the choice is different from addressing > whether the choice benefits or costs the user.
Okay, we're sorry that the design decisions concerning lists have not been clearly stated (documented). :) We're not purposefully trying to burden the user by the implementation of lists in REBOL, though you make a case that we are. Lists are put in for a specific type of application that expects to work with a large set of data upon which it does many insertions and removals, but relatively few searches. Lists were included because it was felt this would be a necessary tool for some people. Also, there may be a deeper reason for lists having absolute indexing (beyond their implementaion), but I don't know it. I'll ask around when I get the chance. Cheers-- -jeff

 [3/17] from: joel:neely:fedex at: 30-Oct-2000 11:06


Hi, again, Jeff, [rebol-bounce--rebol--com] wrote:
> Howdy, Joel: > [...lists are the black sheep of series...]
<<quoted lines omitted: 3>>
> implementation of lists in REBOL, though you make a case > that we are.
Not my intent. That's what I get for trying to be too brief! ;-)
> Lists were included because it was felt this would be a necessary > tool for some people.
Absolutely! I've always understood blocks, lists, and hashes as types that provide the same concept (storage of arbitrary values in an orderly container) but performance-optimized for different uses. But that means that it would be really nice if their interface was consistent. Lists are a valuable addition to the REBOL armory. I was only asking for the trigger to be in the same place as the other guns, unless there's a real reason why it needs to be
> Also, there may be a deeper reason for lists having absolute > indexing (beyond their implementaion), but I don't know it. > I'll ask around when I get the chance.
That was the key issue. Thanks for checking (when you have time! -- I certainly understand that you have plenty to do!). -jn- -- ; Joel Neely [joel--neely--fedex--com] 901-263-4460 38017/HKA/9677 REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] { | e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]

 [4/17] from: lmecir:geocities at: 30-Oct-2000 19:12


Hi Joel, I would like to make a few points: 1) my hat's off to RT for their implementation of lists 2) there's a spec lists *must* comply to to be called lists: insert and remove *must* be elementary operations for lists 3) your requirements are in contradiction with the spec Regards Ladislav

 [5/17] from: lmecir:geocities at: 2-Nov-2000 19:56


Hi, I would like to say thank you to Rishi for his reply, because otherwise I would have no chance to see Joel's reply. As my thanks take this: insert-item: :insert insert: func[list [series!] item [any-type!]] [insert-item list item] Now to Joel's reply: not being a native speaker I am not sure I understood everything. My point was, that the differences between the behaviour of lists and blocks in Rebol are enforced by the conflicting requirements stating which operations shall be elementary for lists (Insert and Remove) and which operations shall be elementary for blocks (Pick and Change). Does that differ from your point of view? Regards Ladislav ----- Original Message ----- From: Rishi Oswal <[rishi--picostar--com]> To: <[rebol-list--rebol--com]> Sent: Wednesday, November 01, 2000 11:30 AM Subject: [REBOL] Re: On list! inconsistency [was Re: WYSIWYG programming]
> Speaking of lists, I was wondering why it is even considered a series
datatype. About half of the series functions (such as 'reverse, etc..) either don't work, or work differently than other series datatypes. I would think since lists are different from other series datatypes, it makes more sense for it to be it's own datatype with it's own special functions such as:

 [6/17] from: bo:rebol at: 2-Nov-2000 8:48


Joel and others, If you find REBOL functions that don't work on LIST! datatypes correctly or functions that return an error instead of doing what you think they should with a LIST!, please send an email to [feedback--rebol--com] explaining the situation. It may be a known bug, oversight or unimplemented feature. The same goes for HASH!. The problem with REVERSE not working on a LIST! is already in our bug database. Thanks! -Bo On 2-Nov-2000/7:44:08-6:00, [joel--neely--fedex--com] wrote:
>Hi, Rishi, >[rebol-bounce--rebol--com] wrote:
<<quoted lines omitted: 83>>
>[rebol-request--rebol--com] with "unsubscribe" in the >subject, without the quotes.
-- Bohdan "Bo" Lechnowsky REBOL Adventure Guide REBOL Technologies 707-467-8000 (http://www.rebol.com) The Official Source for REBOL Books (http://www.REBOLpress.com)

 [7/17] from: joel:neely:fedex at: 2-Nov-2000 7:44


Hi, Rishi, [rebol-bounce--rebol--com] wrote:
> Speaking of lists, I was wondering why it is even considered a > series datatype.
Because it fulfills the defining concepts of a series: 1) a definite position in 2) an ordered collection of values There's a reason for having block!, hash!, and list! all in the language -- performance. [Disclaimer: I don't work at RT, nor do I play one on TV! Speculation, educated guesses, and unindicted co-rumors ahead.] There are many ways to implement a "collection" structure; three that are widely used are: 1) an array -- a consecutive set of memory "cells" that contain the values of interest (or references to them -- we don't need to worry about that distinction here) in the proper order. 2) a linked list -- a bunch of individual "nodes", each of which contains a single datum and references to its predecessor (except the first) and successor (except the last) in the collection. 3) a hash table -- some combination of the two previous physical strategies, along with an index (in the back-of-the-book sense) that is calculated from the content data and tells where the values are located. Keeping to the "economic model" of software, each of these has some costs, and each has some benefits: Costs: Array - Insertions and deletions require copying/moving chunks of content around. If insufficient space is reserved, insertion may require allocation of new memory areas, garbage collection, mass copying, handle managment, etc. Searching (in general) requires a linear algorithm whose time is proportional to the length of the array. Linked - Extra memory is required for the forward/backward List references. Searching requires traversing the links via a linear algorithm. Random access (i.e., to a specific position of the list) requires stepping through the links as well, with a time proportional to the "distance" between the prior position and the new position. Hash - More storage is required for the index, and computation Table time is required to keep it current with each insertion or deletion. Other issues vary, depending on the way the content data (and index) are physically structured. Benefits: Array - Simplicity. Random access is constant time. If the space can be pre-allocated, and the array is "grown" only by appending, the shuffling of data can be minimized. Linked - Insertion and deletion (at the current position!) can List be done in constant time. If the primary usage is scanning sequentially, the time overhead of accessing consecutive positions is be minimized. Hash - Searching can be done in nearly constant time. If Table the physical storage strategy is "tuned" for it, consecutive and random access may not be too costly. So... it's A Good Thing that REBOL gives us the ability to choose the "flavor" of container that is appropriate for each task. As for the rest of your comments...
> About half of the series functions (such as 'reverse, etc..) > either don't work, or work differently than other series datatypes. > I would think since lists are different from other series datatypes, > it makes more sense for it to be it's own datatype with it's own > special functions such as...
If the differences create costs with no apparent benefit (which is exactly the question I have been raising), then I suggest that the Right Thing To Do is not further fragmentation of concepts, but rather the rationalization of existing concepts into a consistent interface. Believe me, I know what a linked list is and how to build one (and have done so many times...), and there's no reason why a linked list can't be reversed. But...
>> boo: [3 1 1 2 6 5 3 5] == [3 1 1 2 6 5 3 5] >> loo: to-list boo == make list! [3 1 1 2 6 5 3 5]
<<quoted lines omitted: 4>>
>> head reverse copy boo == [5 3 5 6 2 1 4 1 3] >> head reverse copy loo == make list! [3 1 4 1 2 6 5 3 5]
Hence my question of why REBOL can't simply give us a consistent interface to specialized collections that still have their own special strengths. (It's called polymorphism...) -jn-

 [8/17] from: rishi:picostar at: 1-Nov-2000 10:30


Speaking of lists, I was wondering why it is even considered a series datatype. About half of the series functions (such as 'reverse, etc..) either don't work, or work differently than other series datatypes. I would think since lists are different from other series datatypes, it makes more sense for it to be it's own datatype with it's own special functions such as: list-insert (instead of insert) list-remove etc.. While I'm on the subject of series functions - anyone know how to over-ride the default behaivor of 'insert function as follows: insert: func [item][insert list item] also tried: insert-item: :insert insert: func[item] [insert-item list item] and some other stuff with no success. Rishi Previously, you (Joel Neely) wrote:

 [9/17] from: joel:neely:fedex at: 1-Nov-2000 12:46


Hi, Ladislav, Ladislav Mecir wrote:
> I would like to make a few points: > > 1) my hat's off to RT for their implementation of lists
I wholeheartedly concur -- in the sense that I'm glad that list! hash! and block! types give use containers that are optimized for different purposes.
> 2) there's a spec lists *must* comply to to be called lists: > insert and remove *must* be elementary operations for lists
Again, total agreement.
> 3) your requirements are in contradiction with the spec
I don't think I'm laying down "requirements". Remember the history of this thread. (Skip indented text if you aren't interested in the history part...) I made the comment that there are inconsistencies in the design of REBOL, and that comment was challenged. I tried to give examples of such inconsistencies. I also tried to make it clear that I do not regard all inconsistencies as necessarily "evil", and used the result values of Append and Change (applied to blocks) to illustrate that point. The difference in their returned values (original position or adjusted position) has a benefit for the most common uses, and the benefit is related to the *concept* of container, and *not* to the implementation details of the differently-optimized containers. Therefore, IMHO the mild inconsistency is reasonable. That isn't always the case, however. The spec (RCUG) states the differences between result values for some operations applied to list! values vs. block! and hash! values, but there's no explanation of *why* those differences are of any benefit to the programmer. A REBOL programmer who writes a function with an any-block! argument will very possibly have to write/debug/maintain extra code to deal with the variances in behavior of list! vs. block! and hash!. You're right that those differences are documented, but I think it is reasonable to ask whether there's any benefit to the programmer to offset the cost of the exceptions If there is no benefit, then I think it's fair to call the design decision into question as being less than perfect. -jn- PS: Ladislav is due credit for inspiring the latest sig block! -- ; Joel Neely [joel--neely--fedex--com] 901-263-4460 38017/HKA/9677 REBOL [] foreach [order string] sort/skip reduce [ true "!" false head reverse "rekcah" none "REBOL " prin "Just " "another " ] 2 [prin string] print ""

 [10/17] from: al:bri:xtra at: 3-Nov-2000 19:41


Rishi wrote:
> Hi Ladislav. I have tried to use insert the way you mentioned, but for
some reason, this does not work. I get the following error:
> Script: "Queue" (17-Oct-2000) > ** Script Error: insert has no value. > ** Where: insert-it: :insert > insert: func [item [any-type!]] > > The interesting thing is that the method above works for any other
function I have tried (such as remove)...but not insert. It seems that you cannot over-ride insert. I am have included my queue file with the modified insert function the way you have described.
> Anyone know why this is? Is it a bug in rebol or am I doing something
wrong?
> q: make object! [ > list: make block! [] > insert-it: :insert > insert: func[item [any-type!]] [insert-it list item]
What you probably didn't know, is that Rebol has seen the set-word! here: insert: and already assigned the value of 'insert in the make object! context to no value . You can get the same effect at the Rebol prompt, like this:
>> type? a_random_word_I_haven't_used_before
** Script Error: a_random_word_I_haven't_used_before has no value. ** Where: type? a_random_word_I_haven't_used_before See how your error message is exactly like the above error?
> ** Script Error: insert has no value. > ** Where: insert-it: :insert
Rebol, in making the object to assign to 'q, makes a context that contains these words: list insert-it insert It does this by scanning for set-word! data-types in the block after: make object! so the result of evaluting this line: insert-it: :insert is that Rebol finds a match for 'insert in the current object's context, and uses that for the value of: :insert Of course, that's an uninitialised value or "no value", so Rebol gives the error message. It would be nice to be able to specify a "parent" or "super" context, much like a parent directory does, so you could write: insert: :../insert or perhaps better would be: insert: :parent/insert so as to refer to the word in the enclosing or outer context. Much like 'self is kind of a "special" value in objects. But that's a subject for a REP, perhaps. So to cure your problem, what you really need is, is the value of 'insert, which can be found at: system/words/insert Making your q/insert function like this: insert: func[item [any-type!]] [system/words/insert list item] and saving the cost of: insert-it: :insert for each queue object. And, BTW, wouldn't it be better to 'append rather than 'insert? I hope that helps! Andrew Martin ICQ: 26227169 http://members.nbci.com/AndrewMartin/

 [11/17] from: joel:neely:fedex at: 3-Nov-2000 7:02


[bo--rebol--com] wrote:
> If you find REBOL functions that don't work on LIST! datatypes > correctly or functions that return an error instead of doing > what you think they should with a LIST!, please send an email > to [feedback--rebol--com] explaining the situation. It may be a > known bug, oversight or unimplemented feature.
Gladly. I posted my comments here first hoping to get some discussion -- including the possibility that someone could tell me a use for the differences before I simply reported them as a problem (for example, Jeff's patient response on the behavior of Forall vs. e.g., For). I have often learned useful things in such discussions, and assumed that it would be A Good Thing for those discussions to be a matter of public record. If RT would prefer a different approach, please let me know and I'll be glad to follow the standard process. Having had no rationale offered for the list! vs. block!/hash! exceptions, I'll be glad to submit a writeup RSN.
> The problem with REVERSE not working on a LIST! is already in > our bug database.
Thanks, that's good to know! FWIW, I was totally unaware of that particular issue (having never had to Reverse a list!) until Rishi's question inspired me to try it. -jn-

 [12/17] from: g:santilli:tiscalinet:it at: 3-Nov-2000 11:45


Rishi Oswal wrote:
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; code in here does not work > insert-it: :insert > insert: func[item [any-type!]] [insert-it list item] > ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Right word, wrong context. You're inside an object definition, so 'insert refers to the object's 'insert, which is unset! at that time. Try with: insert-it: get in system/words 'insert or simply avoid using the word 'insert in your object. HTH, Gabriele. -- Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/

 [13/17] from: al:bri:xtra at: 3-Nov-2000 22:20


> Hi Andrew!
Hi, Sharriff!
> "probe system" freezes REBOL and Im just as curious as Rishi to know how
exactly the whole heirarchal system of REBOL is built. Try something like the following: map next first system func [word] [write join %system- word mold in system word] You may need to add: next next next next next after the freeze. (Make sure there's about six (or was it seven?))
> I wonder why its undocumented?
Rebol-crew haven't got the time to do it, is the most likely story. Mind you, I haven't really looked that hard yet. I hope that helps! Andrew Martin ICQ: 26227169 http://members.nbci.com/AndrewMartin/

 [14/17] from: sharriff:aina:med-iq at: 3-Nov-2000 8:44


Hi Andrew! probe system freezes REBOL and Im just as curious as Rishi to know how exactly the whole heirarchal system of REBOL is built. I wonder why its undocumented? Best regards Sharriff Aina med.iq information & quality in healthcare AG "Andrew Martin" An: <[rebol-list--rebol--com]> <[Al--Bri--xtra]. Kopie: co.nz> Thema: [REBOL] Re: On list! inconsistency [was Re: WYSIWYG programming] Gesendet von: rebol-bounce@ rebol.com 03.11.00 21:40 Bitte antworten an rebol-list Rishi wrote:
> Hi Andrew.
Hi, Rishi!
> thanks for this info. I don't remember reading about system/words/... in
the rebol users guide. Can you explain what this represents? Is system an object? 'system is a Rebol object that contains lots of stuff in Rebol. Try: probe system for more.
> Are all rebol mezanine and native functions in system object?
Words pointing to them can be found there.
> Better yet, can someone explain the general heirarchy of rebol. ie: what
is in system object?what is in system/word object? etc.. This would be really helpful! probe system
> I am now assuming that 'insert function is actually just a reference to
'system/words/insert function. Better to say that 'insert is a word that evaluates to the :insert function, kind of.
> BTW, I don't see why 'insert would be more inefficent than 'append in a
queue (implemented as an array) since an item has to be inserted in one end of a queue and removed from the other end. As far as I know, I had 2 options:
> OPTION1 > insert at head of list
<<quoted lines omitted: 4>>
> remove at head of list > I simply chose the option 1. I don't see why any of these would be more
efficient than the other if there are about equal number of insertions and removals (if implemented as array like I have). I was thinking of the analogy of a queue in written form. Here's a queue (list) of jobs to do: Sweep the floor Mow the lawn Paint the house Collect the mail Answer email If I wanted to add the job "fix door handle", where would I put it? On the end, like this: Sweep the floor Mow the lawn Paint the house Collect the mail Answer email fix door handle Or, on the front? Like this: fix door handle Sweep the floor Mow the lawn Paint the house Collect the mail Answer email Of course, a lot would depend on the priority of the jobs (I tend to put a high priority on answering email...). I tend to scan left to right, top to bottom, when looking at things, so the first thing is left and top, while the last thing is right and bottom. A queue would seem to follow the same logic. The first thing in the queue is the leftmost and topmost thing, while the last thing in the queue is the rightmost and bottom-most thing. If you were Chinese or Arabic, different rules could apply. YMMV. Andrew Martin ICQ: 26227169 http://members.nbci.com/AndrewMartin/

 [15/17] from: al:bri:xtra at: 3-Nov-2000 21:40


Rishi wrote:
> Hi Andrew.
Hi, Rishi!
> thanks for this info. I don't remember reading about system/words/... in
the rebol users guide. Can you explain what this represents? Is system an object? 'system is a Rebol object that contains lots of stuff in Rebol. Try: probe system for more.
> Are all rebol mezanine and native functions in system object?
Words pointing to them can be found there.
> Better yet, can someone explain the general heirarchy of rebol. ie: what
is in system object?what is in system/word object? etc.. This would be really helpful! probe system
> I am now assuming that 'insert function is actually just a reference to
'system/words/insert function. Better to say that 'insert is a word that evaluates to the :insert function, kind of.
> BTW, I don't see why 'insert would be more inefficent than 'append in a
queue (implemented as an array) since an item has to be inserted in one end of a queue and removed from the other end. As far as I know, I had 2 options:
> OPTION1 > insert at head of list
<<quoted lines omitted: 4>>
> remove at head of list > I simply chose the option 1. I don't see why any of these would be more
efficient than the other if there are about equal number of insertions and removals (if implemented as array like I have). I was thinking of the analogy of a queue in written form. Here's a queue (list) of jobs to do: Sweep the floor Mow the lawn Paint the house Collect the mail Answer email If I wanted to add the job "fix door handle", where would I put it? On the end, like this: Sweep the floor Mow the lawn Paint the house Collect the mail Answer email fix door handle Or, on the front? Like this: fix door handle Sweep the floor Mow the lawn Paint the house Collect the mail Answer email Of course, a lot would depend on the priority of the jobs (I tend to put a high priority on answering email...). I tend to scan left to right, top to bottom, when looking at things, so the first thing is left and top, while the last thing is right and bottom. A queue would seem to follow the same logic. The first thing in the queue is the leftmost and topmost thing, while the last thing in the queue is the rightmost and bottom-most thing. If you were Chinese or Arabic, different rules could apply. YMMV. Andrew Martin ICQ: 26227169 http://members.nbci.com/AndrewMartin/

 [16/17] from: rishi:picostar at: 2-Nov-2000 23:58


Hi Andrew. thanks for this info. I don't remember reading about system/words/... in the rebol users guide. Can you explain what this represents? Is system an object? Are all rebol mezainne and native functions in system object? Better yet, can someone explain the general heirarchy of rebol. ie: what is in system object? what is in system/word object? etc.. This would be really helpful! I am now assuming that 'insert function is actually just a reference to 'system/words/insert function. BTW, I don't see why 'insert would be more inefficent than 'append in a queue (implemented as an array) since an item has to be inserted in one end of a queue and removed from the other end. As far as I know, I had 2 options: OPTION1 insert at head of list remove at tail of list or OPTION2 insert at tail of list remove at head of list I simply chose the option 1. I don't see why any of these would be more efficient than the other if there are about equal number of insertions and removals (if implemented as array like I have). Rishi

 [17/17] from: rishi:picostar at: 2-Nov-2000 21:30


Previously, you (Ladislav Mecir) wrote:
> Hi, > > I would like to say thank you to Rishi for his reply, because otherwise I > would have no chance to see Joel's reply. As my thanks take this: > > insert-item: :insert > insert: func[list [series!] item [any-type!]] [insert-item list item] >
Hi Ladislav. I have tried to use insert the way you mentioned, but for some reason, this does not work. I get the following error: Script: "Queue" (17-Oct-2000) ** Script Error: insert has no value. ** Where: insert-it: :insert insert: func [item [any-type!]] The interesting thing is that the method above works for any other function I have tried (such as remove)...but not insert. It seems that you cannot over-ride insert. I am have included my queue file with the modified insert function the way you have described. Anyone know why this is? Is it a bug in rebol or am I doing something wrong? REBOL [ Title: "Queue" Author: "Rishi Oswal" Email: [rishio--mail--com] Date: 17-Oct-2000 File: %queue.r ] q: make object! [ list: make block! [] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; code in here does not work insert-it: :insert insert: func[item [any-type!]] [insert-it list item] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; this is my code and worked fine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; must comment out previous insert functions ; insert-item: func [item][insert list item] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; remove-item: func [/local item][ item: last list remove back tail list return item ] peek: does [return last list] size?: does [return length? list] is-empty?: does [return empty? list] reset: does [clear list] print-it: func [ {prints the list. The first item in list is first item entered in list} /local temp-list ][ temp-list: copy list print [head reverse temp-list] ] get: func [ {returns the queue as a list with the first item being the first item inserted} /local temp-list ][ temp-list: copy list return copy head reverse temp-list ] set: func [ {replace current queue with a new one} queue [block!] {block of values with first value being first item insert in list} ][ list: copy head reverse queue ] ] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TEST CODE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if using my code, please change insert to insert-item ;comment { all queue functions print ["begin all queue functions..." newline] print [{q/insert ["1" 2 3 4.0]} newline ] q/insert "1" print type? q/peek q/insert 2 q/insert 3 q/insert 4.0 print type? first q/list q/print-it print ["q/peek" q/peek] print ["q/is-empty?" q/is-empty?] print "q/remove-item 1 2 3" q/remove-item q/remove-item q/remove-item q/print-it print "q/reset" q/reset q/print-it q/insert 20 q/insert 30 q/insert 40 print "current queue: " q/print-it print ["getting list..."] temp: q/get print temp print "setting queue..." q/set temp q/print-it print ["internal representation: " q/list] print [newline "...end all queue functions"] ;}

Notes
  • Quoted lines have been omitted from some messages.
    View the message alone to see the lines that have been omitted