I am trying to create a program that simplifies radicals in TI-BASIC. However, one FOR loop seems to be only completing one iteration while the rest work fine. Here is the code:
Input "Root=",A
Input "Radical=",B
B→Z
ClrList L₃
prgmPRMNTOL1
prgmGETPRIME
The FOR loop in question starts here...
For(Y,1,10)
0→Z
For(X,1,dim(L₂))
If L₁(Y)=L₂(X)
Then
Z+1→Z
End:Disp Z
End
If Z≥A
Then
int(Z/A)*A→C
int(Z/A)→D
For(T,1,D)
L₁(Y)→L₃(1+dim(L₃))
End
For(R,1,C)
ClrList L₄
For(S,1,dim(L₂))
If L₂(S)=L₁(Y) and C>0
Then
–1→L₂(S)
C-1→C
End
End
For(Q,1,dim(L₂))
If L₂(Q)≠–1
Then
L₂(Q)→L₄(1+dim(L₄))
End
End
ClrList L₂
For(Q,1,dim(L₄))
L₄(Q)→L₂(Q)
End
End
End
...and ends here.
1→E
For(M,1,dim(L₃))
E*L₃(M)→E
End
1→F
For(N,1,dim(L₂))
F*L₂(N)→F
End
Disp "OUTSIDE",E,"ROOT",A,"INSIDE",F
The program works perfectly besides the fact that this one loop only runs once. I will post prgmPRMNTOL1 and prgmGETPRIME as well if necessary, though they probably do not have any impact as they modify only L₁ and L₂.
EDIT: Added a indented version.
Input "Root=",A
Input "Radical=",B
B→Z
ClrList L₃
prgmPRMNTOL1
prgmGETPRIME
For(Y,1,10)
0→Z
For(X,1,dim(L₂))
If L₁(Y)=L₂(X)
Then
Z+1→Z
End
End
If Z≥A
Then
int(Z/A)*A→C
int(Z/A)→D
For(T,1,D)
L₁(Y)→L₃(1+dim(L₃))
End
For(R,1,C)
ClrList L₄
For(S,1,dim(L₂))
If L₂(S)=L₁(Y)
Then
–1→L₂(S)
End
End
For(Q,1,dim(L₂))
If L₂(Q)≠–1
Then
L₂(Q)→L₄(1+dim(L₄))
End
End
ClrList L₂
For(Q,1,dim(L₄))
L₄(Q)→L₂(Q)
End
End
End
1→E
For(M,1,dim(L₃))
E*L₃(M)→E
End
1→F
For(N,1,dim(L₂))
F*L₂(N)→F
End
Disp "OUTSIDE",E,"ROOT",A,"INSIDE",F
Close Your Loops
Your issue seems to stem from incorrectly matching your If statements, loops and their End statements.
What's Happening
The behavior of TI-Basic when end of file is reached before all loops and If statements have been closed is to fail silently, terminating the program, rather than alerting the users of an error.
This behavior makes certain odd pieces of code syntactically valid. For instances this snippet would run without error:
For(A,1,10
Disp A
The results being
1
Done
Obviously this is the same as running Disp 1 so, there's no reason to use this an your code. It serves only to make silent and annoying errors appear in code.
The Fix
Assuming the indented version of your code represents how you want your loops to be nested, the code below should fix your problem.
Input "Root=",A
Input "Radical=",B
B→Z
ClrList L₃
prgmPRMNTOL1
prgmGETPRIME
For(Y,1,10)
0→Z
For(X,1,dim(L₂))
If L₁(Y)=L₂(X)
Z+1→Z
End
If Z≥A:Then
int(Z/A)*A→C
int(Z/A)→D
For(T,1,D)
L₁(Y)→L₃(1+dim(L₃))
End
For(R,1,C)
ClrList L₄
For(S,1,dim(L₂))
If L₂(S)=L₁(Y)
–1→L₂(S)
End
End:"Inserted this End
For(Q,1,dim(L₂))
If L₂(Q)≠–1
L₁(Q)→L₄(1+dim(L₄))
End
ClrList L₂
For(Q,1,dim(L₄))
L₄(Q)→L₂(Q)
End
End
End
1→E
For(M,1,dim(L₃))
E*L₃(M)→E
End
1→F
For(N,1,dim(L₂))
F*L₂(N)→F
End
Disp "OUTSIDE",E,"ROOT",A,"INSIDE",F
If that doesn't fix it, the missing End is elsewhere in your code.
Related
How do I execute Ruby files from another Ruby file?
class Launch
def get_program
begin
files = ["sum_of_digits", "compressed_sequence",
"shortest_repetition"]
(0...files.length).each_with_index do |index|
puts "#{index} . #{ files[index]}"
end
begin
puts "Enter program number to execute: "
puts program_number = gets.chomp.to_i
puts "loading program #{files[program_number]}"
begin
load(`ruby #{files[program_number]}.rb
#{files[program_number]}.txt`)
rescue
puts "loading error"
end
puts "do you want to continue Y/N"
answer = gets.chomp
end until answer == 'N'
rescue
puts "the file cannot be loaded ,it may be moved or not exist "
end
end
end
launch = Launch.new
launch.get_program
launch = Launch.new
launch.get_program
While executing, I am getting the output, but for only one program, and the loop is terminating. I want to execute files in a loop until the user enters "N".
In general your code isn't written in the Ruby way. This is untested but it looks about right:
class Launch
FILES = ['sum_of_digits', 'compressed_sequence', 'shortest_repetition']
def get_program
FILES.each_with_index do |fname, i|
puts "#{i} . #{fname}"
end
loop do
puts "Enter program number to execute: "
program_number = gets.to_i
file_to_load = FILES[program_number]
puts "loading program #{file_to_load}"
begin
system("ruby #{file_to_load}.rb #{file_to_load}.txt")
rescue => e
puts "loading error: #{e}"
puts "'#{file_to_load}' cannot be loaded, it may have been moved or not exist."
end
puts 'Do you want to continue Y/N'
break if gets.chomp.strip.upcase == 'N'
end
end
end
launch = Launch.new
launch.get_program
Some things to study:
block and end are used to start exception handling, not to define control loops. Well, they can, but there are better, more idiomatic, ways. loop is recommended by Matz.
You used load but I don't think that's really what you'd want to do. Instead, you should tell the OS to load and run the code in a sub-shell using system, not in the context of your currently running code.
Instead of using a bare rescue, your code should at least capture the exception using rescue => e so you can output what occurred. In "real life", AKA, production, you should be even more discerning and capture only the exceptions you expect, but that's a different discussion.
When using a begin/rescue/end, try to keep them as small as possible, at least until you're more familiar with how they work. rescue is a great way to shoot yourself in the foot, and debugging raised exceptions that could be generated by many lines of code can be a pain.
In general, when you have a list of things that's likely to change, or any variable that's more likely to change than the rest of the code, put that definition at the top of the script, or the top of the class or module definition, then reference it as a constant. That helps avoid magical dust being sprinkled through the code that has to be searched for if you want to add or delete things. Like files. Or magical dust.
I'm trying to review the slides of class. The code is supposed to print "early work" once then followed by "later work" twice(you can set the repeat number of the later work). But I wonder why this code doesn't work, and how can I modify the code? Since now the code will generate infinite loop of "later work" rather than 2(which is supposed to be)
require 'continuation'
def work
p "early work"
here = callcc {|here| here}
p "later work"
return here
end
def rework(k)
entry = work
k.times do |i|
entry.call(entry)
end
end
rework(2)
The code doesn't work because the loop counter in k.times is stuck. Each call to entry.call(entry) rewinds the program to when callcc returns. So callcc returns again, the later work happens again, work returns again, and k.times starts again. When k.times starts, it resets its loop counter to zero. The infinite loop is because the loop counter is always zero.
To fix the program, we must continue the loop, not restart it. The best fix is to use a fiber, but first, I try to use a continuation. Here's the version that works on my machine:
require 'continuation'
def work
p "early work"
here = callcc {|here| here}
p "later work"
return here
end
class Integer
def my_times
i = 0
while i < self
yield i
i += 1
end
end
end
def rework(k)
entry = nil
k.my_times do |i|
if i == 0
entry = work
else
entry.call(entry)
end
end
end
rework(2)
I fix the control flow by calling work inside the loop. When work returns again, I don't reset the loop counter.
I also define my own Integer#my_times and don't use Ruby's Integer#times. If I change the code from k.my_times back to k.times, the loop counter gets stuck again. This exposes a problem with continuation objects in Ruby.
When a continuation rewinds a program, it might rewind or preserve the values of local variables. My program assumes that entry.call preserves the loop counter. Matz's Ruby Implementation preserves the loop counter in Integer#my_times, but rewinds the loop counter in Integer#times. This is the only reason why my program can't use Integer#times.
MRI seems to rewind locals in C code (like Integer#times) but preserve locals in Ruby code (like Integer#my_times). This makes a mess of loop counters and other locals. Ruby does not fix this mess, but warns against callcc. Ruby says, warning: callcc is obsolete; use Fiber instead.
Here's the program using a fiber:
def work
p "early work"
here = Fiber.new do
while true
p "later work"
Fiber.yield
end
end
here.resume
return here
end
def rework(k)
entry = nil
k.times do |i|
if i == 0
entry = work
else
entry.resume
end
end
end
rework(2)
I'm trying to create a rescue that if and when there is an Twitter::Error::NotFound error (such as does not exist) it will just keep going through the loop. Please help, thanks.
Below is the code,
begin
File.open("user_ids.txt") do |file|
file.each do |id|
puts client.user("#{id}").screen_name
rescue Twitter::Error::NotFound => error
next # skip this item
end
end
end
Instead of the retry method is there a a method that can skip and keep moving on to the next item in the loop?
I'm pretty sure the error.rate_limit does not apply (I copied this code from a different rescue call), is there another method to call? like error.notfound.continue_with_loop
I would like to create a rescue that if and when there is an error such as does not exist so it will just keep going through the loop. Please help, thanks.
yes next will continue and retry the next item in a loop.
retry will retry the loop with the same item.
Note: you don't have enough ends for all the do that are in that method. So I'd try:
begin
File.open("user_ids.txt") do |file|
file.each do |id|
puts client.user("#{id}").screen_name
rescue Twitter::Error::NotFound => error
sleep error.rate_limit.reset_in + 1
next # skip this item
end
end
end
Note: see how proper indentation makes it clear when you're missing an end ?
You may need to shift the begin/end block that is currently around the lot - to just be around the code that you want to rescue-from (or it'll default to the outside begin/end rather than your loop)
File.open("user_ids.txt") do |file|
file.each do |id|
begin
puts client.user("#{id}").screen_name
rescue Twitter::Error::NotFound => error
sleep error.rate_limit.reset_in + 1
next # skip this item
end
end
end
I'm finding this a bit odd. I would expect each iteration of parse_line(ARGF.read_line) here to wait for input from STDIN. What actually is happening is the first iteration skips waiting for user input, but subsequent iterations do wait. My temporary workaround is just to iterate an extra time.
def parse_line(line)
line.split(" ").map(&:to_i)
end
def get_number_of_slices
parse_line(ARGF.readline(1)).first
end
def get_all_slice_dimensions(number_of_slices)
number_of_slices += 1 # for some reason the first read doesn't wait for user input...
number_of_slices.times.collect { puts "iter"; parse_line(ARGF.readline) }
end
def main
puts (get_all_slice_dimensions get_number_of_slices)
end
main
Added code so that it is a full working program. I found that when I changed readline(1) to readline in get_number_of_slices, I did not need to add 1 to number_of_slices in get_all_slice_dimensions any longer, but I would still like to know the reason why this affects the behavior. If you pay attention to the output, iter will print twice the first time.
I'm comparing a word against another string, which is changing by looping through the alphabet and inserting each letter at every position of the word.
#position_counter = 0
EDIT: Here is the code that letter_loop is running through.
#array = ["amethod", "variable", "block"]
def word_list_loop
#match_counter = 0
#array.each do |word|
letter_loop(word)
end
puts #match_counter
end
CLOSE EDIT
def letter_loop(word)
("a".."z").each do |letter|
word_plus_letter = #word.dup
word_plus_letter.insert(#position_counter, letter)
#match_counter+=1 if word.match(/\A#{word_plus_letter}\z/)
end
#position_counter+=1
letter_loop(word) unless #position_counter == (#word.length + 1)
end
The word I'm using for the argument is "method". But when I run this, I am getting a index 7 out of string (IndexError). Its looping through the alphabet for each position correctly, but it doesn't seem to get caught with the unless #position_counter == (#word.length + 1) to end.
I've tried a few other ways, with an if statement, etc, but I'm not able to get the method to complete itself.
How many times are you running letter_loop? Are you sure the error happens in the first run? From what I see, if you call it a second time without resetting #position_counter to zero, it will begin with #word.length + 1 producing the exact error you see. Other than that, I couldn't find any problems with your code (ran just fine here on the first run).
Update: since you're using a recursive solution, and position_counter does not represent the state of your program (just the state of your method call), I'd suggest not declaring it as #position_counter but as an optional parameter to your method:
def letter_loop(word, position_counter=0)
("a".."z").each do |letter|
word_plus_letter = #word.dup
word_plus_letter.insert(position_counter, letter)
#match_counter+=1 if word.match(/\A#{word_plus_letter}\z/)
end
position_counter+=1
letter_loop(word, position_counter) unless position_counter == (#word.length + 1)
end
If you can't/don't want to do this, just reset it before/after each use, like I suggested earlier, and it will work fine:
#array.each do |word|
#position_counter = 0
letter_loop(word)
end
(though I wouldn't recommend this second approach, since if you forget to reset it somewhere else your method will fail again)
I think the problem is that you are calling letter_loop from within #array.each, but you don't reset #position_counter to zero on each iteration of the #array.each loop.
If that doesn't fix your problem, add something like this as the first line of letter_loop:
puts "letter_loop word=#{word}, position=#{#position_counter}, matches=#{#match_counter}"
Then run the program and examine the output leading up to the IndexError.