merge sort in Pharo - pharo

Sorry for my poor english.
So, i have a problem with my merge sort.
This is the merge part :
fusion: nTableau debut: deb1 fin1: fin1 fin2: fin2
| deb2 compt1 compt2 i t |
t := #().
deb2 := fin1 + 1.
compt1 := deb1.
compt2 := deb2.
i:= deb1.
(i to: fin1) do: [ t at:(i-deb1) put: (nTableau at:i) ].
i := deb1.
i to: deb1 do: [
(compt1 = deb2) ifTrue: [ ]
ifFalse: [ compt2 =(fin2 +1)ifTrue: [ nTableau at:i put: (t at: compt1-deb1). compt1 := compt1+1 ] ];
ifFalse: [ (t at: (compt1-deb1) < nTableau at: compt2) ifTrue: [ nTableau at:i put: (t at:(compt1 - deb1)). compt1 := compt1 +1 ] ];
ifFalse: [ nTableau at:i put: (nTableau at:compt2) ]
]
And this is my sort part that do recursivity :
tri
| trier milieu |
trier := nil.
trier := [ :tab :deb :fin |
[ deb := (taille/taille). fin = taille. tab := tableau ].
[ milieu := ( deb + fin ) //
(deb ~= fin) ifTrue: [
trier value: tab value: deb value: milieu.
trier value: tab value: milieu+1 value: fin.
fusion: tab deb: debut fin1: milieu fin2: fin.
]
]
I have the problem on the sort part. Please help me.

It seems you have misunderstood what #ifTrue:ifFalse: and that family of messages do.
They are not syntactic constructions, but messages sent to objects and affected by ; as a cascade.
In your example, you have
i to: deb1 do: [
condition
ifTrue: [ ]
ifFalse: [ condition2 ifTrue: [ actions ] ];
ifFalse: [ condition3 ifTrue: [ other actions ];
ifFalse: [ an action more ]
but that sends to the same boolean condition the first ifTrue:ifFalse: (which, by the way, is the same that just putting ifFalse: because the empty block in the ifTrue: part). And after, ifFalse: again, two more times, to the same object (because that is what the ; means). The condition is not re-evaluated, so if the first time it was true, nothing is done and if it was false, the three bocks of action will be performed.
It is equivalent to have only one ifFalse, concatenating all the actions inside the blocks.
...and I donĀ“t think that is what you intended.
Also, you had before that
i := deb1.
i to: deb1 do: [ ... ]
and there you use the same value, doing deb1 to: deb1.
(Does that even run? I thought that the block requires an argument)

Related

Signatures smartmatching misunderstanding

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).

Can I extend built-in String class with my methods

I find that there is no built-in trim (strip) method to remove leading and trailing spaces from strings in the built-in String class. I want to extend it with my functions. Is it possible? Using example here, I tried following code:
String extend [
trimleading: str [ |ch ret flag|
ret := str. "make a copy of sent string"
flag := true.
[flag] whileTrue: [ "while first char is space"
ch := ret first: 1. "again test first char"
ch = ' ' "check if space remaining"
ifTrue: [ ret := (ret copyFrom: 2 to: ret size)] "copy from 2nd char"
ifFalse: [flag := false]
].
^ret "return modified string"
]
trim: str [ |ret|
ret := str.
ret := (self trimleading: ret). "trim leading spaces"
ret := (self trimleading: (ret reverse)). "reverse string and repeat trim leading"
^(ret reverse) "return re-reversed string"
]
].
oristr := ' this is a test '
('>>',oristr,'<<') displayNl.
('>>',(oristr trim),'<<') displayNl.
Above code does not work and gives following error:
$ gst string_extend_trim.st
>> this is a test <<
Object: ' this is a test ' error: did not understand #trim
MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
String(Object)>>doesNotUnderstand: #trim (SysExcept.st:1448)
UndefinedObject>>executeStatements (string_extend_trim.st:23)
Where is the problem and how can it be corrected? Thanks.
Edit: Following code works but it does not change original string:
String extend [
trimleading [ |ch ret flag|
ret := self. "make a copy of sent string"
flag := true.
[flag] whileTrue: [ "while first char is space"
ch := ret first: 1. "again test first char"
ch = ' ' "check if space remaining"
ifTrue: [ ret := (ret copyFrom: 2 to: ret size)] "copy from 2nd char"
ifFalse: [flag := false]
].
^ret "return modified string"
]
trim [ |ret|
ret := self.
ret := (self trimleading). "trim leading spaces"
ret := ((ret reverse) trimleading ). "reverse string and repeat trim leading"
^(ret reverse) "return re-reverse string"
]
].
oristr := ' this is a test '
('>>',oristr,'<<') displayNl.
('>>',(oristr trim),'<<') displayNl.
('>>',oristr,'<<') displayNl.
oristr := (oristr trim).
('>>',oristr,'<<') displayNl.
How can oristr trim change oristr? I do not want to write oristr := oristr trim.
The first problem you already solved: originally you defined a method trim: with one argument but sent trim with no arguments.
The second problem is to modify the String in place. You can change the chars with self at: index put: aCharacter and some other methods to copy and overwrite ranges, but you won't be able to change the size (length) of the String. In the Smalltalks I know, Objects cannot change their size after they have been created. Therefore I propose that you stick to making a new String with less characters in trim.
There is a method to exchange one object for another everywhere in the System. It is called become:. But I think you should not use it here. Depending on the Smalltalk implementation you might end up with unwanted side effects, such as replacing a String literal in a method (so the next method invocation would actually run with a different, trimmed string in place of the literal).
The difference between your code and the example you have linked is that in the example they are extending a custom class, but you are extending a core class. The difference is in the way you should load your code and run it. You should use Packages in GNU-Smalltalk to build it. There is an excellent answer on SO by #lurker how to use extened classes in gst, please read it and upvote it if you like it, I don't want to duplicate the information here.
To adapt your code to String extend:
String extend [
trimleading: str [ |ch ret flag|
ret := str. "make a copy of sent string"
flag := true.
[flag] whileTrue: [ "while first char is space"
ch := ret first: 1. "again test first char"
ch = ' '
ifTrue: [ ret := (ret copyFrom: 2 to: ret size) ] "copy from 2nd char"
ifFalse: [flag := false ]
].
^ ret "value is modified string"
]
trim [ | ret |
ret := self trimleading: self. "trim leading spaces"
ret := self trimleading: (ret copy reverse). "reverse string and repeat trim leading"
^ (ret reverse) "return re-reverse string"
]
].
oristr := ' this is a test '.
('>>',oristr,'<<') displayNl.
('>>',(oristr trim),'<<') displayNl.
('>>',oristr,'<<') displayNl.
oristr := (oristr trim).
('>>',oristr,'<<') displayNl.
You are sending the message #trim to origstr variable so you must define without any parameters. However, that does not apply to #trimleading: so I have taken your previous code and put it there.
Note: You should really read about the self keyword and what it does and understand it - you are using it incorrectly. You assign the ret := self value but you don't use it, you just overwrite it with next assigment.

Cascade in Rebol

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

If...else if...else in REBOL

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 ]
]

Checking the number of param in bash shell script

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

Resources