Jump to content
IGNORED

Converting a string or list version of a number to a number in LOGO II for calculations


Recommended Posts

If I use a READLINE to input data, it is returned as a list. Suppose I wish to input a number (integer). Is there a simple way to convert a list like [45 ] to the number 45, or do I have to invent a BASIC VAL type routine to interpret and convert the list value to a number? I suppose I could use READCHAR and interpret each character as it it entered. But then I would potentially have to consider any reediting of the entered value and displaying it as well.

Link to comment
Share on other sites

Reading this is in manual is not a good sign. 

 

Warning: Words and Numbers In Tl Logo, you can form words whose characters are all digits.

But these are not treated as numbers, even though they look like numbers.

For example, the arithmetic operations will not accept something like "25 as an input.

Conversely, the word-manipulating operations do not work on numbers.

This distinction between words and numbers can be confusing, because error messages

that result from inappropriate inputs do not distinguish between numbers and words.

 

I can't find reference to a conversion function either. 

 

Page 145 in the manual has something to start with that converts numbers to a base 8.

That gives you a skeleton I think. 

 

TO BASES :N 
IF :N < 8 OUTPUT DIGIT :N 
OUTPUT WORD BASE8 (:NI 8) 
DIGIT REMAINDER :N 8 
END 

TO DIGIT :N 
OUTPUT PICK :N + 1 :DIGITLIST 
END 

(Note the 1 added to N: the first digit in the list, for example, is the digit 0.) 
Of course , there is nothing special about base 8. You can convert to any 
base less than 10 in the same way: 

TO BASE :N :B 
IF :N < :8 OUTPUT DIGIT :N 
OUTPUT WORD BASE (:N/:B) :B 
DIGIT REMAINDER :N :8 
END 

 

  • Like 1
Link to comment
Share on other sites

it turns out, that it can be done fairly easily. This morning I realised that it is possible to build a list of valid commands with the SENTENCE command, that can define a number from an element in a list. This list can the be executed using the RUN command and produce a numeric variable and that value can be OUTPUT from the procedure as a number.

 

 TO TEST2                       
 MAKE "A READLINE               
 MAKE "X SENTENCE [MAKE "Y ] :A 
 RUN :X                         
 OUTPUT :Y                      
 END 

 

This example assumes that we enter 123 as input for READLINE.

First we MAKE "A as a list from READLINE [123 ]. Then we SENTENCE a list with the elements [MAKE "Y ] and the single element list in :A and MAKE "X from it. This produces a valid command string like this  [MAKE "Y 123 ]. Then we just RUN the command string. It produces a variable :Y with the numeric content 123. We OUTPUT it, and everyone is happy.

 

Try PRINT 2 + TEST2

Enter...

>123

 

and it prints 125.

  • Like 3
Link to comment
Share on other sites

Ok, but never tell me that Forth is weird, ever again. :) 

That's a few convolutions to get there but good on you for finding the magic words. 

 

Note: This is interesting because the EVALUATE command in Forth, which is like RUN in LOGO I think, can be used the same way to convert a string to number.

ie: Just give it to the interpreter. 

  • Like 1
Link to comment
Share on other sites

After further reading i noticed that there is a section in the LOGO II manual, which has some examples of using the ability to RUN the content of a list to implement a WHILE command and other stuff. From another millennium I can remember, that the APL language also had an EXECUTE command, that could do something similar. I have always had a soft spot for APL, primarily because of its strong handling of vectors, matrices etc.. Perhaps Forth can be used to create an APL like language on the Ti99. LOGO II has the basics with its lists and ability to traverse a list, but it would be very slow as an interpreted language. As for home computers in the eighties there was a version of APL for the Amiga - It was very expensive and unfortunately very buggy.

  • Like 1
Link to comment
Share on other sites

On 10/14/2024 at 5:07 AM, jschultzpedersen said:

Perhaps Forth can be used to create an APL like language on the Ti99. 

That is possible.  There is this a guy named Bob Armstrong who wrote a system for himself that is based on APL concepts. 

But he performs the same kind of magic that you see done with APL. 

CoSy uses "words" rather than symbols in true Forth form. For example the iota operator is written as ...   iota   :) 

 

In my opinion Bob's mind struggles with creating a linear way to present his language. It seems like he is thinking of everything simultaneously,  to me anyway.

Maybe his mind is running APL, or maybe I'm just not smart enough not follow it. 

 

You can try to figure it out here. :) 

 

/CoSy/CoSy

 

 

 

Link to comment
Share on other sites

It seems that CoSy is rarely downloaded. At least my antivirus software (Norton) does not like it and kills it off. Probably because it is suspect by being rarely used. I can bypass Norton, but, anyway, I think I will postpone further investigations for now.

 

I made my first attempt at creating a command that will take a scalar value and for instance multiply (or add or subtract etc.) that value with all elements of an array of values of any length (actually a list) and return another list with the updated values. This can be solved with a recursive process in LOGO II and works for me. The next step will be to add another level so I can handle lists of lists (effectively multidimensional matrices of any size). Again I expect this can be done with recursion. If I can get this to work I can support a number of APL like capabilities. It will probably be dead slow in LOGO II, but fun.....

  • Like 3
Link to comment
Share on other sites

Very interesting work you are doing. 

The hardest part of doing this stuff in Forth IMHO is dynamic memory management. LOGO has that solved for you so with your skill level you are off to the races. 

 

On tiny systems like TI-99 Forth typically does static allocations. 

I have a library from the Standard website that gives the ALLOCATE FREE  ANS/ISO wordset.  

If I were to combine that with the SAMS card I might be able to make something work. 

 

I have implemented experimental versions of MAP REDUCE and FILTER that uses the dictionary memory in a crude way.

Simple linear allocation like the Forth dictionary uses. 

 

The syntax ended up being pretty fun. I have however never done a project with it.

: REDUCE ( inital addr size xt-- n)
    ['] REDUCER IS ACTION  FOREACH ;

\ Use REDUCE to do something real
: ..  ( 0 addr size -- )  ['] .  REDUCE ; \ print array signed
: U.. ( 0 addr size -- )  ['] U. REDUCE ; \ print array un-signed
: SUM     ( addr len ) 0 -ROT  ['] + REDUCE ;
: AVERAGE ( addr len ) DUP 2/ >R  SUM  R> / ;

 

The [[   marks the start of memory  and  ]]  updates the size in the header and returns the address. 

SIZE returns the start of data address ( past the header info) and the number of items on the data stack. 

 

\ MAP returns a new array as output 
: MAP ( initial addr size xt-- addr' size')
  [[ >R  ['] MAPPER IS ACTION  FOREACH  R> ]] SIZE ;

\ filter creates a temp counted array that might be a different size
: FILTER ( initial addr size xt-- addr' size')
 [[  >R  ['] FILTRATION IS ACTION  FOREACH  DROP R> DUP ]] DROP SIZE ;

 

Then you can do:

\ allocate some arrays
[[  20 CELLS ALLOT  ]] DATA: B[] ( un-initialzed data example)
[[  1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , ]] DATA: A[]

\  test code
A[] ..   \ prints A[]

\ using REDUCE
A[] SUM .
A[] AVERAGE .

\ MAP
\ map requires operators that have this stack action ( n -- n') 
A[] ' 8* MAP ..
A[] ' 1- MAP ..

\ FILTER
\ filter functions must have a stack diagram ( n n -- ?)
\ This conforms to Forth comparison operators
\ The flag determines if the data will be added to the output or not.
7 A[] ' < FILTER ..
4 A[] ' > FILTER ..
9 A[] ' = FILTER ..

\ using the initial value 1, we can test for ODD/EVEN
: EVEN ( initial n -- n ?)  AND 0= ;
: ODD  ( initial n -- n ?)  AND 0> ;
1 A[] ' EVEN FILTER ..
1 A[] ' ODD  FILTER ..

\ filter based on array element 
A[] 3 ]@  A[] ' > FILTER ..

\ SEQUENTIAL actions 
1 A[] ' ODD FILTER  ' 8* MAP  SUM . 

 

It's not APL, but it gets nearer to that kind of thinking. 

 

Link to comment
Share on other sites

I think that if I were to try my hand at using Forth for this, I would start by creating a data structure with information on my object (dimensions, type of content etc.) this would be like a header for each object. With this data available I could then reserve the right amount of memory for an updated version of the object and also decide whether one object was compatible to another object. As an example a vector of 5 elements could multiply with the row of a matrix if the matrix also had 5 elements per row. A scalar could multiply with an object of any dimension and so on. Strings would be handled as a vector of characters and thus have similar behaviour.

 

With LOGO II it is a bit different. With a scalar, because I use recursion, I don't have to know the number of elements in a list because I just cut out an element at a time and process it, then creates an altered version of the list minus the first element and repeats - until I have an empty list. Similarly I build the new list one element at a time from the processed item isolated from the old list.

 

I still have a full STSC APL language package. It is DOS based and made for the original IBM PC. I did some work with it in the early eighties, but it has been mothballed ever since, and, to be frank, I can hardly understand my own code from back then. That is the downside of this highly 'concentrated' language. You have to analyse old code in detail to make sense of it.

 

For now I am 'factoring' the problem and writing small procedures to solve each step. Just like Forth, actually...

  • Like 2
Link to comment
Share on other sites

1 hour ago, jschultzpedersen said:

I think that if I were to try my hand at using Forth for this, I would start by creating a data structure with information on my object (dimensions, type of content etc.) this would be like a header for each object. With this data available I could then reserve the right amount of memory for an updated version of the object and also decide whether one object was compatible to another object. As an example a vector of 5 elements could multiply with the row of a matrix if the matrix also had 5 elements per row. A scalar could multiply with an object of any dimension and so on. Strings would be handled as a vector of characters and thus have similar behaviour.

 

With LOGO II it is a bit different. With a scalar, because I use recursion, I don't have to know the number of elements in a list because I just cut out an element at a time and process it, then creates an altered version of the list minus the first element and repeats - until I have an empty list. Similarly I build the new list one element at a time from the processed item isolated from the old list.

 

I still have a full STSC APL language package. It is DOS based and made for the original IBM PC. I did some work with it in the early eighties, but it has been mothballed ever since, and, to be frank, I can hardly understand my own code from back then. That is the downside of this highly 'concentrated' language. You have to analyse old code in detail to make sense of it.

 

For now I am 'factoring' the problem and writing small procedures to solve each step. Just like Forth, actually...

From what I can gather your data structure header is the way CoSy works.  My crude challenge was to get something working with just an integer array. The header in my case is just the number of elements. 

If I added a few more fields to my header with a type field and the size of each element, it could do a lot more, but I am just playing with learning the concepts at this stage. 

 

I toyed with LISP like CONS in Forth and it can be done but on a retro machine it's pretty memory hungry and I never did get a garbage collector working so that dies pretty fast. :)

It is a very powerful concept however.

 

I have tried grok APL code on occasion without doing the real legwork and I am happy to hear that even a seasoned user has to relearn what they wrote.

Forth can do that to it you don't work hard to prevent it and even then ... ;)

 

Yes LOGO and Forth share that aspect of making you build much of your own stuff in small understandable pieces.

Hat's off to you for putting the effort in on the TI LOGO system. 

 

Link to comment
Share on other sites

Wisdom comes with age... or something like that. I just discovered that if I have a list with items where the first item is a valid numeric character, that item can be converted to a number by using the FIRST command. I don't think this is mentioned in the manual, but it works never the less. So I can do it like this...

 

MAKE "LST [42 Doodle] 

PRINT 1 + FIRST :LST

and the answer is 43

 

MAKE "LST [42 [43 44]] works too

MAKE "LST [[42 43] 44] does not work since the first element is in itself a list.

 

To test if the first item is a number, I can use...

TEST NUMBER? FIRST :LST

IFT PRINT [This is true]

 

In this way I can test whether the first item is a list or a valid number.

  • Like 2
Link to comment
Share on other sites

A routine for multiplying all numeric elements in a list with a specific value is trivial in LOGO II. See code below, which multiplies a list of numbers with 5. As an alternative to using a recursive routine, you can use the combination of TELL and EACH to make a sort of WHILE-WEND loop that stops when there are no more elements in the list.

 

 TO MULTIPLY :LIST :M           
 TELL :LIST                     
 MAKE "ARRAY [ ]                
 EACH [MAKE "ARRAY LPUT YOURNUMBER * :M :ARRAY ]              
 OUTPUT :ARRAY                  
 END

 

 PRINT MULTIPLY [1 2 3] 5      
 5 10 15  

 

It gets more hairy, when you have a list where some of the members of the list are lists of numbers themselves. I haven't solved that one yet. Some sort of multilevel recursion I suppose. Work in progress...

  • Like 2
Link to comment
Share on other sites

I think this subject is about done now. So I will just publish a somewhat enhanced version of a MULTIPLY function. This version will multiply a number with all members of an array or it can multiply two equal-sized lists of numbers with each others. Results are returned as a list. Just make sure the last argument is a list.

 

 TO MULT :M :LST                
 MAKE "L LENGTH :LST            
 MAKE "ANSW [ ]                 
 TEST NUMBER? :M                
 IFF IF NOT :L = LENGTH :M THEN OUTPUT [DIMENSION MISMATCH ] STOP                           
 IFT REPEAT :L [MAKE "ANSW LPUT FIRST :LST * :M :ANSW MAKE "LST BUTFIRST :LST ]             
 IFF REPEAT :L [MAKE "ANSW LPUT FIRST :LST * FIRST :M :ANSW MAKE "M BUTFIRST :M MAKE "LST BUTFIRST :LST ]                 
 OUTPUT :ANSW                   
 END                            
                                
 PRINT MULT [1 2 3] [4 5 6]    
 4 10 18                        
 
PRINT MULT 5 [4 5 6]          
 20 25 30        

              

 PRINT MULT [2 3] [4 5 6]      
 DIMENSION MISMATCH   

 

Edited by jschultzpedersen
attachment wrongly included
  • Like 3
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...