Recursive TCL proc without explicit return - recursion

I am writting a simple "proc" to calculate the factorial. I would like to understand why my function does not work without the return statement.
According to TCL docs, functions that are defined without explicit "return",
return the value of the last executed command in its body.
proc fac { n } {
if { $n == 1 } {
return 1
}
puts $n
set n [expr {$n - 1}]
return [expr {[fac $n ] * $n}]
}
puts [fac 5] # ans 24
When the "return" is removed, I get the following error message:
invalid command name "1"
while executing
"[expr {[fac $n ] * $n}] "
(procedure "fac" line 7)
invoked from within
I expected that without the explicit "return", the function should return 24 as well.

Your expectation is correct. But you have square brackets around expr procedure in the last line. It is:
[expr {[fac $n] * $n}]
This means for the interpreter: 1) execute expr procedure with given argument; 2) execute the result of expr procedure. Because of this, the interpreter tries to execute procedure 1 that doesn't exist and you receive an error.
To fix this error - just remove square brackets from the last line:
proc fac { n } {
if { $n == 1 } {
return 1
}
puts $n
set n [expr {$n - 1}]
expr {[fac $n ] * $n}
}

Related

sum function in Julia is giving error if the array is empty

I am trying to create a code which identifies if the elements in an array are monotonic or not.
I wrote the below code and got the error -
function isMonotonic(array)
if length(array) <= 2
return true
end
check_up = []
check_down = []
for i in range(2, length(array))
if array[i] <= array[i-1]
append!(check_up, 1)
end
if array[i] >= array[i - 1]
append!(check_down, 1)
end
end
if sum(check_up) == length(array) - 1 || sum(check_down) == length(array) - 1
return true
else
return false
end
end
isMonotonic([1, 2, 3, 4, 5, 6 , 7])
I am getting the below error
Error: Methoderror: no method matching zero(::Type{Any})
I think it is because I am trying to sum up the empth array, I want to understand how to overcome this problem in general, I have a solution for the above code, but in genral I want to know the reason and how to use it. I do not want to first check if the array is empty or not and then do the sum.
If you wanted to save yourself lots of effort, the simplest solution would just be:
my_ismonotonic(x) = issorted(x) || issorted(x ; rev=true)
This will return true if x is sorted either forwards, or in reverse, and false otherwise.
We could maybe make it a little more efficient using a check so we only need a single call to issorted.
function my_ismonotonic(x)
length(x) <= 2 && return true
for n = 2:length(x)
if x[n] > x[1]
return issorted(x)
elseif x[n] < x[1]
return issorted(x ; rev=true)
end
end
return true
end
# Alternatively, a neater version using findfirst
function my_ismonotonic(x)
length(x) <= 2 && return true
ii = findfirst(a -> a != x[1], x)
isnothing(ii) && return true # All elements in x are equal
if x[ii] > x[1]
return issorted(x)
else
return issorted(x ; rev=true)
end
end
The loop detects the first occurrence of an element greater than or less than the first element and then calls the appropriate issorted as soon as this occurs. If all elements in the array are equal then the loop runs over the whole array and returns true.
There are a few problems of efficiency in your approach, but the reason you are getting an actual error message is because given the input, either this expression sum(check_up) or this expression sum(check_down) will effectively result in the following call:
sum(Any[])
There is no obvious return value for this since the array could have any type, so instead you get an error. If you had used the following earlier in your function:
check_up = Int[]
check_down = Int[]
then you shouldn't have the same problem, because:
julia> sum(Int[])
0
Note also that append! is usually for appending a vector to a vector. If you just want to add a single element to a vector use push!.

Expressing the double summation sequence in Raku

How to express the double variable double summation sequence in Perl 6?
For an example of double variable double summation sequence see this
It must be expressed as is, i.e. without mathematically reducing the double summation into a single summation. Thank you.
The X (cross operator) and the [+] (reduction metaoperator [ ] with additive operator +) make this surprisingly easy:
To represent1 the double summation ∑³x = 1 ∑⁵y = 1 2x + y , you can do the following:
[+] do for 1..3 X 1..5 -> ($x, $y) { 2 * $x + $y }
# for 1..3 X 1..5 # loop cross values
# -> ($x, $y) # plug into x/y
# { 2 * $x + $y } # calculate each iteration
# do # collect loop return vals
# [+] # sum them all
If you wanted to create a sub for this, you could write it as the following2
sub ΣΣ (
Int $aₒ, Int $aₙ, # to / from for the outer
Int $bₒ, Int $bₙ, # to / from for the inner
&f where .arity = 2  # 'where' clause guarantees only two params
) {
[+] do for $aₒ..$aₙ X $bₒ..$bₙ -> ($a, $b) { &f(a,b) }
}
say ΣΣ 1,3, 1,5, { 2 * $^x + $^y }
Or even simplify things more to
sub ΣΣ (
Iterable \a, # outer values
Iterable \b, # inner values
&f where .arity = 2) { # ensure only two parameters
[+] do f(|$_) for a X b
}
# All of the following are equivalent
say ΣΣ 1..3, 1..5, -> $x, $y { 2 * $x + $y }; # Anonymous block
say ΣΣ 1..3, 1..5, { 2 * $^x + $^y }; # Alphabetic args
say ΣΣ 1..3, 1..5, 2 * * + * ; # Overkill, but Whatever ;-)
Note that by typing it, we can ensure ranges are passed, but by typing it as Iterable rather than Range we can allow more interesting summation sequences, like, say, ΣΣ (1..∞).grep(*.is-prime)[^99], 1..10, { … } that would let us use sequence of the first 100 primes.
In fact, if we really wanted to, we could go overboard, and allow for an arbitrary depth summation operator, which is made easiest by moving the function to the left:
sub ΣΣ (
&function,
**#ranges where # slurp in the ranges
.all ~~ Iterable && # make sure they're Iterables
.elems == &function.arity # one per argument in the function
) {
[+] do function(|$_) for [X] #ranges;
};
Just like [+] sums up all the values of our f() function, [X] calculates the cross iteratively, e.g., [X] 0..1, 3..4, 5..6 first does 0..1 X 3..4 or (0,3),(0,4),(1,3),(1,4), and then does (0,3),(0,4),(1,3),(1,4) X 5..6, or (0,3,5),(0,4,5),(1,3,5),(1,4,5),(0,3,6),(0,4,6),(1,3,6),(1,4,6).
1. Sorry, SO doesn't let me do LaTeX, but you should get the idea. 2. Yes, I know that's a subscript letter O not a zero, subscript numbers aren't valid identifiers normally, but you can use Slang::Subscripts to enable them.

TCL recursively call procedure

I'm a beginner at TCL and while trying to build the GCD algorithm I ran into some problems I'd like some help with:
how can I call a proc inside a proc recursively like so
proc Stein_GCD { { u 0 } { v 0 } } {
if { $v == 0 } {
puts "$u\t\t$v\t\t$v"
}
if { [expr { $v % 2 } && { $u % 2 } ] == 0 } {
return [expr 2 * ${Stein_GCD 1 0} ]
}
}
set a [Stein_GCD 2 2 ]
puts $a
as you can see, I made the proc to evaluate GCD(the code does not make any sense because I'm trying to solve an example issue), and I'm trying to recursively call the proc again to continue evaluating(notice that I made an if statement that can understand the Stein_GCD 1 0 call, yet the tcl 8.6.6 online EDA emulator says:
can't read "Stein_GCD 1 0": no such variable
while executing
"expr 2 * ${Stein_GCD 1 0} "
(procedure "Stein_GCD" line 5)
invoked from within
"Stein_GCD 2 2 "
invoked from within
"set a [Stein_GCD 2 2 ]"
(file "main.tcl" line 7)
Can you tell me how to efficiently recursively call a proc, and where was my mistake?
will gladly provide more info in the case I did a bad job at explaining.
The error can't read "Stein_GCD 1 0": indicates that you are treating the data as a single string instead of separate arguments. The problem line:
return [expr 2 * ${Stein_GCD 1 0} ]
is not written correctly. ${Stean_GCD 1 0} is not a variable.
You should have:
return [expr 2 * [Stein_GCD 1 0] ]
You want the result from Stein_GCD 1 0, so the brackets should be used.

Fastest route to last key of dict in Tcl

Let's say that I have a Tcl dictionary. I want the fastest way to get the last entered key of the dict (not the value).
Theoretically, I could use:lindex [ dict keys $dict ] end Does anyone know anything else, which is faster?
This is pretty fast:
% set data {a 1 b 2 c 3}
a 1 b 2 c 3
% proc p1 {} {dict get $::data [lindex [dict keys $::data] end]}
% time {p1} 100000
1.87782 microseconds per iteration
But you can shave off about a microsecond by remembering the last key:
oo::object create mydict
oo::objdefine mydict {
variable data last
method add args {
lappend data {*}$args
set last [lindex [dict keys $data] end]
}
method getLast {} {
dict get $data $last
}
}
% mydict add a 1 b 2 c 3
c
% time {mydict getLast} 100000
0.82731 microseconds per iteration
Documentation:
create (method of oo::class),
dict,
lappend,
lindex,
method (object configuration subcommand),
proc,
oo::objdefine (object definition command),
oo::object (class of objects),
set,
time,
variable (object slot subcommand),
{*} (syntax)
I'm seeing [lindex $data end-1] to be faster.
tclsh last.tcl
time_list : 1.0693949999999999 microseconds per iteration
time_dict : 279.470543 microseconds per iteration
last.tcl
set data [dict create]
for {set i 0} {$i < 10000} {incr i} {
dict set data "key_$i" $i
}
set time_dict [time {
set last_key [lindex [dict keys $data] end]
} 1000]
set time_list [time {
set last_key [lindex $data end-1]
} 1000]
puts "time_list : $time_list"
puts "time_dict : $time_dict"

Write a recursive function that returns a stack of Fibonacci sequence

My teacher just asked this question in the exam and I have no idea where to go on.
More details, the prototype of function is given as:
stack<int> Fibonacci_sequence(int n); //fibonacci numbers count up to n
The point is this function is recursive and it should return a stack data type. In my opinion I don't think this is a possible thing to do, but my teacher asked it!!
P.s: sorry, my language is C++
function stack<int> Fibonacci_sequence(int n) {
if n == 0 {
var a stack<int>;
a.push(0);
return a
} else if n == 1 {
var a stack<int>;
a.push(0);
a.push(1);
return a
} else
var temp int;
var seq int;
seq = Fibonacci_sequence(n-1);
temp = seq.pop;
seq.push(temp);
seq.push(temp);
//above: the top element of the stack must be duplicated because it
//is popped off in the process of calculating the sum.
seq.push(seq.pop()+Fibonacci_sequence(n-2).pop());
return seq
}
}
Above is a function that does just that, written in pseudo code because you did not specify a language. Hopefully this helps, it was fun to come up with! Thanks for the interesting question.
Since you didn't specify a language, and you specified it's an exam, here it is in Ruby. Ruby provides stack operations for arrays, but I'm only using push and pop operations in the following so you should be able to easily translate it to the language of your choice.
def fib(n) # no explicit return type, since everything's an object in Ruby
fail "negative argument not allowed" if n < 0
if n > 1
stack = fib(n - 1)
# grab the last two values...
f_n_1 = stack.pop
f_n_2 = stack.pop
# ...and use them to calculate the next.
# The value of this expression is the resulting stack, return it
return stack.push(f_n_2).push(f_n_1).push(f_n_1 + f_n_2)
elsif n == 1
return fib(0).push(1)
else
return [].push(0)
end
end
p fib(10) # => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
You may have to translate this to the language of your exam, but that's appropriate.
Here is my C++ code based on #Elliot pseudo, and it got errors, I specified these errors in the code. And I just figure out that pop() doesn't return a value, I'm gonna fix this.
stack<int> Fibonacci_sequence(int n)
{
if (n == 0) {
stack<int> a;
a.push(0);
return a;
}
else if (n == 1) {
stack<int> a;
a.push(0);
a.push(1);
return a;
}
else
{
int temp;
temp = Fibonacci_sequence(n - 1).pop(); //error C2440: '=': cannot convert from 'void' to 'int'
Fibonacci_sequence(n - 1).push(temp);
Fibonacci_sequence(n - 1).push(temp);
//above: the top element of the stack must be duplicated because it
//is popped off in the process of calculating the sum.
return Fibonacci_sequence(n - 1).push(Fibonacci_sequence(n - 1).pop() + Fibonacci_sequence(n - 2).pop());//error C2186: '+': illegal operand of type 'void'
}
}

Resources