I've noticed that REBOL doesn't have a built in if...elsif...else syntax, like this one:
theVar: 60
{This won't work}
if theVar > 60 [
print "Greater than 60!"
]
elsif theVar == 3 [
print "It's 3!"
]
elsif theVar < 3 [
print "It's less than 3!"
]
else [
print "It's something else!"
]
I have found a workaround, but it's extremely verbose:
theVar: 60
either theVar > 60 [
print "Greater than 60!"
][
either theVar == 3 [
print "It's 3!"
][
either theVar < 3 [
print "It's less than 3!"
][
print "It's something else!"
]
]
]
Is there a more concise way to implement an if...else if...else chain in REBOL?
The construct you would be looking for would be CASE. It takes a series of conditions and code blocks to evaluate, evaluating the blocks only if the condition is true and stopping after the first true condition is met.
theVar: 60
case [
theVar > 60 [
print "Greater than 60!"
]
theVar == 3 [
print "It's 3!"
]
theVar < 3 [
print "It's less than 3!"
]
true [
print "It's something else!"
]
]
As you see, getting a default is as simple as tacking on a TRUE condition.
Also: if you wish, you can have all of the cases run and not short circuit with CASE/ALL. That prevents case from stopping at the first true condition; it will run them all in sequence, evaluating any blocks for any true conditions.
And a further option is to use all
all [
expression1
expression2
expression3
]
and as long as each expression returns a true value, they will continue to be evaluated.
so,
if all [ .. ][
... do this if all of the above evaluate to true.
... even if not all true, we got some work done :)
]
and we also have any
if any [
expression1
expression2
expression3
][ this evaluates if any of the expressions is true ]
You can use the case construct for this, or the switch construct.
case [
condition1 [ .. ]
condition2 [ ... ]
true [ catches everything , and is optional ]
]
The case construct is used if you're testing for different conditions. If you're looking at a particular value, you can use switch
switch val [
va1 [ .. ]
val2 [ .. ]
val3 val4 [ either or matching ]
]
Related
While reading and trying signature smartmatching I run into something strange.
Executing the following smartmaching signature pairs:
my #sigs = :($a, $b), :($a, #b), :($a, %b);
my #signatures_to_check = :($, $), :($, #), :($, %);
my $c = 0;
for #sigs -> $sig {
for #signatures_to_check -> $s {
$c++;
if $sig ~~ $s {
say " [ $c ] " ~ $sig.gist ~ ' match ' ~ $s.gist;
next;
}
say " [ $c ] " ~ $sig.gist ~ ' do NOT match ' ~ $s.gist;
}
say "\n" ~ '#' x 40 ~ "\n";
}
I've got the following results:
[ 1 ] ($a, $b) match ($, $)
[ 2 ] ($a, $b) do NOT match ($, #)
[ 3 ] ($a, $b) do NOT match ($, %)
########################################
[ 4 ] ($a, #b) match ($, $)
[ 5 ] ($a, #b) match ($, #)
[ 6 ] ($a, #b) do NOT match ($, %)
########################################
[ 7 ] ($a, %b) match ($, $)
[ 8 ] ($a, %b) do NOT match ($, #)
[ 9 ] ($a, %b) match ($, %)
I've tried explaining myself cases [ 4 ] and [ 7 ] but I've failed!
Can somebody explain it to me?
How many things is a value that does the Positional role? Or one that does the Associative role?
The hint is in "a value that does..." and "one that does...". It's a single thing.
So, yes, an given Array or Hash has zero, one, two, or more elements. But it is, as itself, a single thing.
$ indicates a scalar symbol or value. What is the constraint on a scalar symbol or value? It is that it binds to a single thing at a time (even if that thing itself can contain multiple elements).
is there any specific way to check if the condition true on for loop and return true.
ex -
`
check_all_1_to_8_eq()
{
for i in {1..8}; do
if [ a == $i ];then
return 0
else
return 1
fi
done
}`
i want to check if all 1 to 8 are return true then end of the function return true , if on of the if condition return false , then function return false. Please let me know how to solve these type of script.
Continue looping if the condition succeeds, and return outside the loop. If the condition fails, return at that point:
check_all_1_to_8_eq () {
for i in {1..8}; do
if [ ! a == "$i" ]; then
return 1
fi
done
return 0
}
[ ! a == "$i" ] checks if value of variable i ($i) is not equal to a.
You can leverage short circuit evaluation, || (runs the command following it only if the preceding command fails) too, here we will do the equity check [ a == "$i" ]:
check_all_1_to_8_eq () {
for i in {1..8}; do
[ a == "$i" ] || return 1
done
return 0
}
In Logo Language, cascade is a procedure to to compose a function with itself several times (it is almost like fold in functional language).
Example:
add 4 add 4 add 4 5 --> cascade 3 [add 4 ?1] 5 == 17
2^8 --> cascade 8 [?1 * 2] 1
fibonacci 5 --> (cascade 5 [?1 + ?2] 1 [?1] 0)
factorial 5 --> (cascade 5 [?1 * ?2] 1 [?2 + 1] 1)
General notation for multi-input cascade, in Logo:
(cascade how many function1 start1 function2 start2 ...) with:
function1 -> ?1 ,
function2 -> ?2 ...
Cascade returns the final value of ?1.
In Rebol:
cascade1: func [howmany function1 start1] [....]
cascade2: func [howmany function1 start1 function2 start2] [....]
How to write cascade1 and cascade2 in Rebol ?
My answer uses REBOL 3, but could be backported to 2 without too much trouble. (I'd have done it in REBOL 2, but I don't have REBOL 2 on my system and haven't used it in a long time.) This implements cascade fully (i.e., with any number of "functions") and does it in an idiomatically REBOL kind of way: It uses a simple DSL.
cascade: funct [
count [integer!]
template [block!]
/only "Don't reduce TEMPLATE"
/local arg fun-block
][
param-list: copy []
param-number: 1
arg-list: copy []
fun-list: copy []
template-rules: [
some [
copy fun-block block! (
append param-list to word! rejoin ["?" ++ param-number]
append fun-list fun-block
)
copy arg any-type! (
append arg-list :arg
)
]
end
]
unless only [template: reduce template]
unless parse template template-rules [
do make error! rejoin ["The template " mold/flat template " contained invalid syntax."]
]
while [! tail? fun-list] [
fun-list: change fun-list func param-list first fun-list
]
fun-list: head fun-list
loop count [
temp-args: copy []
for f 1 length? fun-list 1 [
append/only temp-args apply pick fun-list f arg-list
]
arg-list: copy temp-args
]
first arg-list
]
Using it is simple:
print cascade 23 [[?1 + ?2] 1 [?1] 0]
This correctly gives the value 46368 from one of the cascade examples given in the Logo cascade documentation linked by the questioner. The syntax of the DSL should be brutally obvious. It's a series of blocks followed by starting arguments. The outer block is reduced unless the /only refinement is used. A block itself will work just fine as an argument, e.g.,
cascade 5 [[?1] [1 2 3]]
This is because the first block is interpreted as a "function", the second as a starting argument, the third as a "function" and so on until the template block is exhausted.
As far as I can tell, this is a complete (and rather elegant) implementation of cascade. Man, I love REBOL. What a shame this language didn't take off.
With bind, that Binds words to a specified context (in this case local context of function), and compose function, I get:
cascade: func [
times
template
start
] [
use [?1] [
?1: start
template: compose [?1: (template)]
loop times bind template '?1
?1
]
]
cascade 8 [?1 * 2] 1
== 256
cascade 3 [add 4 ?1] 5
== 17
val: 4
cascade 3 [add val ?1] 5
== 17
cascade2: func [
times
template1 start1
template2 start2
/local **temp**
] [
use [?1 ?2] [ ; to bind only ?1 and ?2 and to avoid variable capture
?1: start1
?2: start2
loop
times
bind
compose [**temp**: (template1) ?2: (template2) ?1: **temp**]
'?1
?1
]
]
cascade2 5 [?1 * ?2] 1 [?2 + 1] 1
== 120
cascade2 5 [?1 + ?2] 1 [?1] 0
== 8
Here is a somewhat working cascade in Rebol. It won't work with op! datatype--i.e. +, *--but it will work with add and multiply. You may want to check out the higher order functions script to see some other examples. I haven't had time to write cascade2 yet
cascade: func [
times [integer!]
f [any-function!]
partial-args [series!]
last-arg
][
expression: copy reduce [last-arg]
repeat n times [
insert head expression partial-args
insert head expression get 'f
]
expression
]
With your examples:
probe cascade 3 :add [4] 5
print cascade 3 :add [4] 5
will result in:
[make action! [[
"Returns the addition of two values."
value1 [scalar! date!]
value2
]] 4 make action! [[
"Returns the addition of two values."
value1 [scalar! date!]
value2
]] 4 make action! [[
"Returns the addition of two values."
value1 [scalar! date!]
value2
]] 4 5]
17
and
probe cascade 8 :multiply [2] 1
print cascade 8 :multiply [2] 1
Will result in:
[make action! [[
"Returns the first value multiplied by the second."
value1 [scalar!]
value2 [scalar!]
]] 2 make action! [[
"Returns the first value multiplied by the second."
value1 [scalar!]
value2 [scalar!]
]] 2 make action! [[
"Returns the first value multiplied by the second."
value1 [scalar!]
value2 [scalar!]
]] 2 make action! [[
"Returns the first value multiplied by the second."
value1 [scalar!]
value2 [scalar!]
]] 2 make action! [[
"Returns the first value multiplied by the second."
value1 [scalar!]
value2 [scalar!]
]] 2 make action! [[
"Returns the first value multiplied by the second."
value1 [scalar!]
value2 [scalar!]
]] 2 make action! [[
"Returns the first value multiplied by the second."
value1 [scalar!]
value2 [scalar!]
]] 2 make action! [[
"Returns the first value multiplied by the second."
value1 [scalar!]
value2 [scalar!]
]] 2 1]
256
I use for checking the number of params in bash shell as follows:
#! /bin/bash
usage() {
echo "Usage: $0 <you need to specify at least 1 param>"
exit -1
}
[ x = x$1 ] && usage
where, if [ x = x$1 ] condition is not satisfied, execute usage.
Here, my question is, I never really think about the expression [ x = x$1 ] which looks a lot like a condition expression. Is x counted as a literal? and how come can we use = for comparison. Typically should it be something like ==?
Could anybody please fill the void here?
[ x = y ] condition is for comparing strings. (just once =)
x$1 means concatenating two string x and $1.
So, if $1 is empty, x$1 equals x, and [ x = x ] will be true as a result.
[ x = x$1 ] is error prone, don't use it. Do this instead [ "$1" ]
The difference is that if $1 contains a space or other special characters, your script will crash, for example:
$ a='hello world'
$ [ x = x$a ] && echo works
-bash: [: too many arguments
To fix this you could do [ x = x"$1" ], but [ "$1" ] is shorter, so what's the point.
[] expressions are used extensively in shell scripts, I recommend to read help test. The [ is a synonym for the "test" builtin, but the last argument must be a literal ], to match the opening [. In there you will find the explanation of the differences between = and == operators.
Finally, literal text in conditions is evaluated to true if not empty. Some more examples:
[ x ] # true
[ abc ] # true
[ a = a ] # true
[ a = x ] # false
[ '' ] # false
[ b = '' ] # false
Also common gotchas are these:
[ 0 ] # true
[ -n ] # true
[ -blah ] # true
[ false ] # true
These are true, because 0, -n, false or anything being the only argument, they are treated as literal strings, and so the condition evaluates to true.
Use $# to count the number of parameters and use the OR operator instead of the AND so that usage() only gets executed if the first condition fails.
#! /bin/bash
usage() {
echo "Usage: $0 <you need to specify at least 1 param>"
exit -1
}
[ x = $# ] || usage
SCRIPT :
IMAGE=$imgvalue;
if [ $imgvalue :=1 ]
then
echo DO=ABC;
elif [ $imgvalue :=2 ]
then
echo DO=ETC;
elif [ $imgvalue :=3 ]
then
echo DO=XYZ;
else
echo "$imgvalue is unsupported";
exit 1;
fi
In the script above, IMAGE=1, IMAGE=2, IMAGE=3 whatever may be the value I have assigned. It's showing only DO=ABC. Other conditions not working. Can anyone explain what's wrong with my script?
If $imgvalue is not an empty string, your first test is a syntax error, so I am assuming it is empty in the tests you are doing. In that case, your first test is equivalent to:
if [ :=1 ]
which is always true because :=1 is not an empty string. You probably meant to write:
if [ "$imgvalue" = 1 ]