I have tried this not working ... Can anyone help please ? Want to know logic mistake or the syntax. Thanks in advance.
#*********************************************
puts "Fibbonocci sequence"
proc fibb {size} {
if { $size == 1 || $size ==0 } {
return $size
} else {
return [expr fibb [expr $size - 1] + fibb [expr $size - 2]]
}
}
puts "Enter the length of the series:"
set n [gets stdin]
puts "Fibbonocci sequence upto $n terms are:"
puts [fibb $n]
#**********************************************
The problem is this line:
return [expr fibb [expr $size - 1] + fibb [expr $size - 2]]
Actually, that's got several problems. The first is that the expressions aren't braced:
return [expr { fibb [expr { $size - 1 }] + fibb [expr { $size - 2 }] }]
The second problem is that you have to call fibb as a Tcl command within that outer expression, so more [brackets] are needed:
return [expr { [fibb [expr { $size - 1 }]] + [fibb [expr { $size - 2 }]] }]
Plug that into the right place and the rest of your code should work…
But we can be more elegant than that by turning fibb into a function. Functions in Tcl are really just commands that live in the right namespace, tcl::mathfunc.
proc tcl::mathfunc::fibb {size} {
if { $size == 1 || $size ==0 } {
return $size
}
return [expr { fibb($size-1) + fibb($size-2) }]
}
Then you invoke it using, say:
puts [expr { fibb($n) }]
The only difference is that we've put the command (i.e., the procedure) in the right namespace so that it behaves as an expression component. And we've still put braces around the expression (please always do that until you at least understand why it matters) and simplified the code very slightly.
Also, you can still invoke it directly:
puts [tcl::mathfunc::fibb $n]
That'll work just the same way.
Related
Im trying to implement base64 coding in a very simple way. In my approach (lets for a second put away whether its appropriate or not) I need to reverse strings and then concate them. After that this concated string is used in substring function. Strings are joined properly but when I use substring basex seems to lose it.
Funny thing is substring works for well for all indexes starting at 8. So substring($string, 1, 8) and higher gives correct output. But everything below that is messed up. Starting with one disappeared number: substring($string, 1, 7 (and below) ) results in 6 length string.
Moreover substring can start only with 1st or 0 index. Anything greater results in empty return.
declare variable $array := [];
declare function bs:encode
( $input as xs:string ) {
bs:integer-to-binary(string-to-codepoints($input), "", $array)
} ;
declare function bs:integer-to-binary
( $input as xs:integer*, $string as xs:string, $array as array(xs:string) ) {
let $strings :=
for $i in $input
return
if ($i != 0)
then if ($i mod 2 = 0)
then bs:integer-to-binary(xs:integer($i div 2), concat($string, 0), $array)
else bs:integer-to-binary(xs:integer($i div 2), concat($string, 1), $array)
else if ($i <= 0)
then array:append($array, $string)
return bs:check-if-eight($strings)
} ;
declare function bs:check-if-eight
( $strings as item()+ ) {
let $fullBinary :=
for $string in $strings
return if (string-length($string) < 8)
then bs:check-if-eight(concat($string, 0))
else $string (: add as private below :)
return bs:concat-strings($fullBinary)
} ;
declare function bs:concat-strings
( $strings as item()+ ) {
let $firstStringToConcat := functx:reverse-string($strings[position() = 1])
let $secondStringToConcat := functx:reverse-string($strings[position() = 2])
let $thirdStringToConcat := functx:reverse-string($strings[position() = 3])
let $concat :=
concat
($firstStringToConcat,
$secondStringToConcat,
$thirdStringToConcat)
(: this returns correct string of binary value for Cat word :)
return bs:divide-into-six($concat)
} ;
declare function bs:divide-into-six
( $binaryString as xs:string) {
let $sixBitString := substring($binaryString, 1, 6)
(: this should return 010000 instead i get 000100 which is not even in $binaryString at all :)
return $sixBitString
} ;
bs:encode("Cat")
I expect first six letters from string (010000) instead I get some random sequence I guess (00100). The whole module is meant to encode strings into base64 format but for now (the part i uploaded) should just throw first six bits for 'C'
Alright so I figured it out I guess.
First of all in function concat-strings I changed concat to fn:string-join. It allowed me to pass as an argument symbol that separates joined strings.
declare function bs:concat-strings ( $strings as item()+ ) {
let $firstStringToConcat := xs:string(functx:reverse-string($strings[position() = 1]))
let $secondStringToConcat := xs:string(functx:reverse-string($strings[position() = 2]))
let $thirdStringToConcat := xs:string(functx:reverse-string($strings[position() = 3]))
let $concat :=
****fn:string-join(****
($firstStringToConcat,
$secondStringToConcat,
$thirdStringToConcat),****'X'****)
return bs:divide-into-six($concat) } ;
I saw that my input looked like this:
XXXXXXXX01000011XXXXXXXXXXXXXXXXX01100001XXXXXXXXXXXXXXXXX01110100XXXXXXXX
Obviously it had to looping somewhere without clear for loop and as I novice to Xquery i must have been missed that. And indeed. I found it in check-if-eight function:
> declare function bs:check-if-eight ( $strings as item()+ ) {
> **let $fullBinary :=**
> for $string in $strings
> return if (string-length($string) < 8)
> then bs:check-if-eight(concat($string, 0))
> else $string (: add as private below :)
> **return bs:concat-strings($fullBinary)** } ;
Despite being above FOR keyword, $fullBinary variable was in a loop and produced empty spaces(?) and it was clearly shown when i used X as a separator.
DISCLAIMER: I thought about this before and used functx:trim but for some reason it doesnt work like I expected. So it might not for you too if having similar issue.
At this point it was clear that let $fullBinary cannot be bided in FLWR statement at least can't trigger concat-strings function. I changed it and now it produces only string and now im trying to figure out new sequence of running whole module but I think the main problem here is solved.
I would like to write a proc which can accept dict as an optional argument or create new if none was given. My attempt, however, fails with
too many fields in argument specifier "dictionary [dict create]"
proc getOpts { {dictionary [dict create]} } {
upvar $dictionary dct
for { set i 0 } { $i < $::argc } { incr i } {
set key [lindex $::argv $i]
if { [string index $key 0] == "-" } {
incr i
dict set dct [string trimleft $key "-"] [lindex $::argv $i]
} else {
dict set dct $key ""
}
}
}
As dictionaries are pure values, I thought this could work. It looks I might have been wrong. Still, I would like to know why it doesn’t work.
The reason it does not work is that the argument variable list is a true list, not a command evaluation context. That means the [dict create] is getting parsed as two separate words, and proc doesn't like that. Fortunately, a dict create with no other arguments is just another way of saying the empty string: use {} or "" instead.
The bigger problem is that you are using that with upvar; you probably don't want to do that. The right approach is likely to be to not do the variable binding, and instead to just return the dictionary from the procedure: the caller can save it in one of its own variables if it cares to.
In the following SASS-code snippet I want to check if a map has a specific key. If not, it returns a default value (in this case #bbb)
#function contains($list, $var) {
#return (false == index($list, $var));
}
$colors: (aaa: #aaa, bbb: #bbb);
$out: if(contains($colors, aaa), map-get($colors, aaa), #bbb);
body {
color: $out;
}
For some reason it always returns #bbb. Any suggestions what I'm doing wrong here ?
The first issue is that the return value is null if the value isn't found:
#function contains($list, $var) {
#return (null == index($list, $var));
}
The second issue relates to the semantics of your contains function. Usually a function called contains should return true if the value was found in the list and false otherwise (at least I would expect that):
#function contains($list, $var) {
#return (null != index($list, $var));
}
Then there is a third issue with calling the index function on a map. You would have to pass a key-value pair not just the key to this function:
$out: if(contains($colors, aaa #aaa), map-get($colors, aaa), #bbb);
Now it works as expected but for the sake of completeness let me tell you that there is already a built-in function which does exactly what you try to achieve with your contains-function; the map_has_key($map, $key):
$out: if(map-has-key($colors, aaa), map-get($colors, aaa), #bbb);
Trying to break a for loop if the variable $DEVP doesn't exist.
nme=(Y6T1 Y6-T1 Y6.T1 Yr6T1 Yr6-T1 Yr6.T1 Yr6Term1)
DEVP=(/dev/disk2 /dev/disk3 /dev/disk4 /dev/disk5 /dev/disk6 /dev/disk7 /dev/disk8)
for ((i = 0; i < 7; i++)) ; do
if [ ${nme[i]} ${DEVP[i]} = 0 ] ; then
diskutil eraseDisk FAT32 ${nme[i]} ${DEVP[i]}
else
echo “Formatted USBs” ; break
fi
done
The break works fine
for ((i = 0; i < 7; i++)) ; do
if [ $i -lt 3 ] ; then
echo $i
else
echo “Formatted USBs” ; break
fi
done
Output is:
0
1
2
“Formatted USBs”
, however I'm not sure regarding your if statement, you should probably use -z.
if [ -z ${DEVP[i]} ] ; then
Have a look here
Your comparison looks like you expect the two strings to contain the single number zero. They never will. If they are empty, they will contain the empty string. (But even then having two string arguments to the left of the comparison operator is a syntax error.)
Anyway, if the actual problem you are trying to solve is that you don't know how many elements these arrays contain, just ask.
for((i=0; i<${#DEVP[#]}; ++i)); do
Of course, if the arrays contain a different number of arguments, you could still end up in a situation where ${nme[i]} is undefined.
${nme[i]+:} break
This is rather obscure -- it will expand to the empty string before break (and thus break out of the loop) if the value is unset; if it's set, this is just a : noop.
First repair the syntax: Put things in quotes in the if statement.
EDIT: I thought you needed to refer to the var i with $i, but #tripleee showed me, that this is optional in bash arrays. I removed the extra $ characters.
nme=(Y6T1 Y6-T1 Y6.T1 Yr6T1 Yr6-T1 Yr6.T1 Yr6Term1)
DEVP=(/dev/disk2 /dev/disk3 /dev/disk4 /dev/disk5 /dev/disk6 /dev/disk7 /dev/disk8)
for ((i = 0; i < 7; i++)) ; do
if [ "${nme[i]} ${DEVP[i]}" = 0 ] ; then
echo "diskutil eraseDisk FAT32 ${nme[i]} ${DEVP[i]}"
else
echo “Formatted USBs” ; break
fi
done
If you want to check the vars being empty, introduce an error by looping until 8.
I have put an echo in front of the diskutil line, so you can test without doing something you do not want.
for ((i = 0; i < 8; i++)) ; do
if [ -z "${nme[i]}" ]; then
echo "loop $i: \${nme[i]} is empty";
break;
fi
if [ -z "${DEVP[i]}" ]; then
echo "loop $i: \${DEVP[i]} is empty";
break;
fi
echo "diskutil eraseDisk FAT32 ${nme[i]} ${DEVP[i]}"
done
I need to write recursive function Repl
takes as input an expression in e in Expr and returns an expression in Expr
wherein each number is replaced by the number 1.
For example, if e is the expression
((((9 + 5) ∗ 2) ∗ (2 + (4 ∗ 6))))
then Repl(e) is the expression
((((1 + 1) ∗ 1) ∗ (1 + (1 ∗ 1))))
Can anybody help me how to go about this?
Iterative one is easy to write but how to write it recursively?
It is not clear why you would want a recursive solution for this problem, but the solution is relatively straightforward. Here is pseudocode:
string replace(string s, bool seenDigit) {
if (s == "") {
// The string is empty : we are done
return "";
}
if (s[0] is digit) {
if (seenDigit) {
// This is a second, third, etc. digit in a multi-digit chain
// It has been replaced with "1" already, so we cut it out
return replace(s.substring(1), true);
} else {
// This is the first digit in a chain of one or more digits
// Replace it with "1", and tell the next level that we've
// done the replacement already
return "1"+replace(s.substring(1), true);
}
} else {
// Non-digits do not get replaced
return s[0] + replace(s.substring(1), false);
}
}
s[0] means the first character; string+string denotes concatenation.
Making #dasblinkenlight's solution tail recursive:
string replace(string sToGo, string sSoFar, bool inNumber) {
if (sToGo == "") {
return sSoFar;
}
if (sToGo[0] is digit) {
if (isNumber) {
return replace(sSoFar, sToGo.substring(1), true);
} else {
return replace(sSoFar+"1", sToGo.substring(1), true);
}
} else {
return replace(sSoFar+s[0], sToGo.substring(1), false);
}
}
Notice that every return is either a direct value (the base case) or directly returns what a recursive call gives back. This means the program doesn't need to keep track of the recursive calls, because there's nothing to do with the value being returned other than returning it up the chain, which means (if the interpreter takes advantage of it) that the primary downside to using recursion (the overhead of the stack) can be eliminated.