Array extend [
Array class >> bin: val left: l right: r [
^ super binSearch: val left: l right: r
]
binSearch: val left: l right: r [
|arr iter|
arr := self.
[l == r]
ifTrue: [^ (-1)].
iter := (r + l)/2.
[arr at: iter == val]
ifTrue: [^iter].
[arr at: iter < val]
ifTrue:[^ super binSearch val left: l right: iter]
ifFalse: [^ super binSearch val left: iter right: r]
]
]
arr := #(3 6 9 10).
arr bin: 6 left: 1 right: 4.
This is my current code, but I get a compilation error: "Object: Array new: 4 "<0x7fe20936e940>" error: did not understand #bin:left:right:". I was wondering what I was doing wrong.
Thanks
The first part makes no sense to me. Your algorithm is recursive and so it should call itself rather than delegating to the class, which is a different object.
To do this, replace super with self and the same method will be invoked again with the new parameters.
Array extend [
binSearch: val left: l right: r [
|arr iter|
arr := self.
l = r
ifTrue: [^ -1].
iter := (r + l) // 2.
(arr at: iter) = val
ifTrue: [^iter].
(arr at: iter) < val
ifTrue:[^ self binSearch: val left: l right: iter]
ifFalse: [^ self binSearch: val left: iter right: r]
]
]
Further remarks
[Boleans] The receiver of ifTrue: & friends must be a Boolean (i.e., true or false). By enclosing the condition between squared brackets you are creating a BlockClosure instead. I've mentally replaced [...] with (...) where appropriate and then removed them whenever they are not required (see [Precedence] below).
[Comparisons] This is debatable but, while the condition l==r is not entirely wrong, however, l=r is generally better. The reason: the semantics of == corresponds to being the very same object (low level), the semantics of = of being equal (or equivalent). Your algorithm doesn't care whether l and r are represented by exactly the very same object, it only needs to know if both variables hold the same integer. Although the distinction is not relevant in this case, you might create an habit of using == which will fail the day you deal with other kinds of objects (v.g. LargeIntegers, etc.)
[Parenthesis] There is no need to add parenthesis to ^ -1.
[Division] Since + and / are messages, there is no need either to add parenthesis in r + 1 / 2. However, the division may produce a Fraction where your code requires an Integer. Use // instead to get the quotient.
[Colons] You had forgotten the colon after binSearch. This creates a DNU error.
[Precedence] Parenthesis are needed around arr at: iter so to compare the result of this message with val (Recall that the precedence order is: unary, binary, keyword).
[DNU] Regarding the error you get: The selector you created is binSearch:left:right:, however you sent the message bin:left:right: which is not defined.
[self] There is no need to assign self to something else: the receiver will not change along the recursion.
[Return] Many Smalltalkers whould have moved the return symbol ^ to the beginning of the last expression.
In Smalltalk, where arrays are 1-based, the convention broadly accepted consists in returning 0 (rather than -1) when no index is found.
Array extend [
binSearch: val left: l right: r [
| iter |
l = r ifTrue: [^ 0].
iter := (r + l) // 2.
(self at: iter) = val ifTrue: [^iter].
^ (self at: iter) < val
ifTrue:[self binSearch: val left: l right: iter]
ifFalse: [self binSearch: val left: iter right: r]
]
]
Suggestions
Complete your work by adding sufficient unit tests to exercise and improve your method. I've restricted my answer to the coding style, not its correctness.
Add the following method so clients of your service don't need to be verbose when using it.
binSearch: value
^self binSearch: value left: 1 right: self size
Consider changing the selector to something more readable. Your selector doesn't read as a sentence, it reads as a way of naming parameters. What about?
binarySearch: value from: left to: right
Related
I have a dafny defined graph ADT (from this SO question) brought here again for completeness:
class Graph
{
var adjList : seq<seq<int>>;
constructor (adjListInput : seq<seq<int>>)
ensures adjList == adjListInput
{
adjList := adjListInput;
}
}
function ValidGraph(G : Graph) : bool
reads G
{
(forall u :: 0 <= u < |G.adjList| ==> forall v :: 0 <= v < |G.adjList[u]| ==> 0 <= G.adjList[u][v] < |G.adjList|) &&
(forall u :: 0 <= u < |G.adjList| ==> forall v,w :: 0 <= v < w < |G.adjList[u]| ==> G.adjList[u][v] != G.adjList[u][w])
}
method main()
{
var G : Graph := new Graph([[1,2],[0,2],[0,1]]);
var nonRelatedArray := new int[8];
var i := 0; while (i < 14)
{
// nonRelatedArray[3] := 55;
i := i + 1;
}
assert (ValidGraph(G));
}
If I remove the write comment to nonRelatedArray at index 3, I get an assertion violation, which is a bit weird because it seems reasonable that the memory model would be able to determine that nonRelatedArray is (well) non related to G.
You can fix this by adding modifies nonRelatedArray to the loop. The key to this modifies clause is that it does not mention G. So then Dafny knows that G will not be modified by the loop, so it will still be a valid graph.
It is a little confusing what happens if you leave off a modifies clause from a loop. If you don't do any writes to the heap (like when you comment out the write above), then Dafny (actually, Boogie) is able to automatically see that nothing is changed at all. But if you do any writes into the heap, Dafny's default modifies clause all of a sudden becomes "anything the surrounding scope is allowed to modify". If you want something other than these two defaults, you need to ask for it explicitly by giving a modifies clause.
Here's the problem in which I encountered this issue:
The function should compare the value at each index position and score a point if the value for that position is higher. No point if they are the same. Given a = [1, 1, 1] b = [1, 0, 0] output should be [2, 0]
fun compareArrays(a: Array<Int>, b: Array<Int>): Array<Int> {
var aRetVal:Int = 0
var bRetVal:Int = 0
for(i in 0..2){
when {
a[i] > b[i] -> aRetVal + 1 // This does not add 1 to the variable
b[i] > a[i] -> bRetVal++ // This does...
}
}
return arrayOf(aRetVal, bRetVal)
}
The IDE even says that aRetVal is unmodified and should be declared as a val
What others said is true, but in Kotlin there's more. ++ is just syntactic sugar and under the hood it will call inc() on that variable. The same applies to --, which causes dec() to be invoked (see documentation). In other words a++ is equivalent to a.inc() (for Int or other primitive types that gets optimised by the compiler and increment happens without any method call) followed by a reassignment of a to the incremented value.
As a bonus, consider the following code:
fun main() {
var i = 0
val x = when {
i < 5 -> i++
else -> -1
}
println(x) // prints 0
println(i) // prints 1
val y = when {
i < 5 -> ++i
else -> -1
}
println(y) // prints 2
println(i) // prints 2
}
The explanation for that comes from the documentation I linked above:
The compiler performs the following steps for resolution of an operator in the postfix form, e.g. a++:
Store the initial value of a to a temporary storage a0;
Assign the result of a.inc() to a;
Return a0 as a result of the expression.
...
For the prefix forms ++a and --a resolution works the same way, and the effect is:
Assign the result of a.inc() to a;
Return the new value of a as a result of the expression.
Because
variable++ is shortcut for variable = variable + 1 (i.e. with assignment)
and
variable + 1 is "shortcut" for variable + 1 (i.e. without assignment, and actually not a shortcut at all).
That is because what notation a++ does is actually a=a+1, not just a+1. As you can see, a+1 will return a value that is bigger by one than a, but not overwrite a itself.
Hope this helps. Cheers!
The equivalent to a++ is a = a + 1, you have to do a reassignment which the inc operator does as well.
This is not related to Kotlin but a thing you'll find in pretty much any other language
I know blocks can be passed and used in that way.
But is there any way to call a block, just by having a block? Something like this?
aBlock := [ ... ].
aBlock run.
I tried searching for the BlockClosure class in the System browser, but couldn't find it.
Yes! And in fact, you can do pretty interesting things with them, like activating them within themselves. For example, this block computes factorial recursively calling itself:
factorialBlock := [:n |
n <= 1
ifTrue: [n]
ifFalse: [n * (factorialBlock value: n - 1)]
]
and to try it:
factorialBlock value: 5
That would not be an example of a very good coding practice, but it is of the power of block closures!
Let's add that besides value, if your block has arguments, you can also use
[:f | <do something with f>] value: a
where f is a formal argument (an unbound variable name) and a is an actual object that will bind to f when #value: is sent.
For two arguments use value:value: and for many valueWithArguments:, which receives an Array.
Examples
[:x | x squared - 1] value: 3
-> 3 squared - 1 (i.e., 8)
[:x :y | x + 2 / (y - 4)] value: 2 value: 0
-> 2 + 2 / (0 - 4) (i.e., -1)
Exercise
What's the result of evaluating the following?:
block := [:x | x value: 2].
block value: [:y | y + 1]
Yes it can. Also, you send the message 'value' to it to evaluate the block, not 'run'. In fact, you do not have to assign it to a variable. You can just do this:
[ ... ] value.
Check this one:
Lambda Calculus in Pharo
Yes, the Y Combinator is useful in normal programs
https://medium.com/concerning-pharo/lambda-calculus-in-pharo-a4a571869594#.2a78xp31s
From the article:
ycombinator := [ :f |
[ :g | g value: g ] value: [ :g |
f value: [ :x |
(g value: g) value: x ] ] ]
The force is strong in this one.
So I need to get the Caesar Cipher code in smalltalk and create a method and use it so I can do the following test on it
|aString|
aString:=Caesar new encrypt: 'CAESAR'.
Transcript show: aString.
I already have the class made. But I need to make the method of it.
I found this but how can I make a method out of this so I can all the above code in playground.
| i c strCipherText strText iShiftValue iShift |
strText := 'the quick brown fox jumps over the lazy dog'.
iShiftValue := 3.
strCipherText := ''.
iShift := iShiftValue \\ 26.
i := 1.
[ i <= (strText size) ]
whileTrue: [
c := (strText at: i) asUppercase.
( ( c >= $A) & ( c <= $Z ) )
ifTrue: [
((c asciiValue) + iShift > $Z asciiValue)
ifTrue: [
strCipherText := strCipherText, (((c asciiValue) + iShift - 26)
asCharacter asString).
]
ifFalse: [
strCipherText := strCipherText, (((c asciiValue) + iShift)
asCharacter asString).
].
]
ifFalse: [
strCipherText := strCipherText, ' '.
].
i := i + 1.
].
Transcript show: strCipherText.
Transcript cr.
So to make thing clear, I need to make a method using the Caesar Cipher code and use the "aString" code at the beginning and test it with that. I have this code above but this has already text in it and can't be put into the method.
Any help will be appreciated.
As Max said in his comment the code above can be put in a method. The only missing part is a first line with the selector and the formal argument:
caesarCipherOf: strText
<insert the code here>
Another good suggestion by Max is to call the argument aString rather than strText because that's more aligned with how Smalltalkers name things.
But now let's take a look at the source code itself:
The comparison c >= $A & (c <= $Z) means c isLetter.
The conditional calculation of the next character means that we want to shift-rotate c by moving it 3 characters to the right, wrapping it around if it gets beyond $Z. This can be easily expressed as:
(c codePoint - 64 + 3 \\ 26 + 64) asCharacter
where 64 = $A codePoint - 1, is the offset between $A and any given uppercase character c. Note also that I've replaced asciiValue with codePoint.
With these two observations the method can be re-written as
caesarCipherOf: aString
^aString collect: [:c |
c isLetter
ifTrue: [(c asUppercase codePoint - 64 + 3 \\ 26 + 64) asCharacter]
ifFalse: [$ ]]
This is not only shorter, it is more efficient because it avoids creating two new instances of String at every character. Specifically, any expression of the form
string := string , <character> asString
creates two Strings: one as the result of sending #asString, another as the result of sending the concatenation message #,. Instead, #collect: creates only one instance, the one that the method returns.
I usually program by functions in an "instinctive" manner, but my current problem can be easily solved by objects, so I go ahead with this method.
Doing so, I am trying to find a way to give an object a constructor method, the equivalent of init() in python, for example.
I looked in the http://www.rebol.com/docs/core-fr/fr-index.html documentation, but I couldn't find anything relevant.
There is no special constructor function in Rebol, but there is a possibility to write ad hoc init code if you need it on object's creation in the spec block. For example:
a: context [x: 123]
b: make a [
y: x + 1
x: 0
]
So, if you define your own "constructor" function by convention in the base object, you can call it the spec block on creation. If you want to make it automatic, you can wrap that in a function, like this:
a: context [
x: 123
init: func [n [integer!]][x: n]
]
new-a: func [n [integer!]][make a [init n]]
b: new-a 456
A more robust (but bit longer) version of new-a that would avoid the possible collision of passed arguments to init with object's own words would be:
new-a: func [n [integer!] /local obj][
also
obj: make a []
obj/init n
]
You could also write a more generic new function that would take a base object as first argument and automatically invoke a constructor-by-convention function after cloning the object, but supporting optional constructor arguments in a generic way is then more tricky.
Remember that the object model of Rebol is prototype-based (vs class-based in Python and most other OOP languages), so the "constructor" function gets duplicated for each new object created. You might want to avoid such cost if you are creating a huge number of objects.
To my knowledge, there is no formal method/convention for using object constructors such as init(). There is of course the built-in method of constructing derivative objects:
make prototype [name: "Foo" description: "Bar"]
; where type? prototype = object!
My best suggestion would be to define a function that inspects an object for a constructor method, then applies that method, here's one such function that I've proposed previously:
new: func [prototype [object!] args [block! none!]][
prototype: make prototype [
if in self 'new [
case [
function? :new [apply :new args]
block? :new [apply func [args] :new [args]]
]
]
]
]
The usage is quite straightforward: if a prototype object has a new value, then it will be applied in the construction of the derivative object:
thing: context [
name: description: none
new: [name: args/1 description: args/2]
]
derivative: new thing ["Foo" "Bar"]
note that this approach works in both Rebol 2 and 3.
Actually, by reading again the Rebol Core documentation (I just followed the good old advice: "Read The French Manual"), there is another way to implement a constructor, quite simple:
http://www.rebol.com/docs/core-fr/fr-rebolcore-10.html#section-8
Of course it is also in The English Manual:
http://www.rebol.com/docs/core23/rebolcore-10.html#section-7
=>
Another example of using the self variable is a function that clones
itself:
person: make object! [
name: days-old: none
new: func [name' birthday] [
make self [
name: name'
days-old: now/date - birthday
]
]
]
lulu: person/new "Lulu Ulu" 17-May-1980
print lulu/days-old
7366
I find this quite convenient, and this way, the constructor lies within the object. This fact makes the object more self-sufficient.
I just implemented that successfully for some geological stuff, and it works well:
>> source orientation
orientation: make object! [
matrix: []
north_reference: "Nm"
plane_quadrant_dip: ""
new: func [{Constructor, builds an orientation object! based on a measurement, as given by GeolPDA device, a rotation matrix represented by a suite of 9 values} m][
make self [
foreach [a b c] m [append/only matrix to-block reduce [a b c]]
a: self/matrix/1/1
b: self/matrix/1/2
c: self/matrix/1/3
d: self/matrix/2/1
e: self/matrix/2/2
f: self/matrix/2/3
g: self/matrix/3/1
h: self/matrix/3/2
i: self/matrix/3/3
plane_normal_vector: reduce [matrix/1/3
matrix/2/3
matrix/3/3
]
axis_vector: reduce [self/matrix/1/2
self/matrix/2/2
self/matrix/3/2
]
plane_downdip_azimuth: azimuth_vector plane_normal_vector
plane_direction: plane_downdip_azimuth - 90
if (plane_direction < 0) [plane_direction: plane_direction - 180]
plane_dip: arccosine (plane_normal_vector/3)
case [
((plane_downdip_azimuth > 315) or (plane_downdip_azimuth <= 45)) [plane_quadrant_dip: "N"]
((plane_downdip_azimuth > 45) and (plane_downdip_azimuth <= 135)) [plane_quadrant_dip: "E"]
((plane_downdip_azimuth > 135) and (plane_downdip_azimuth <= 225)) [plane_quadrant_dip: "S"]
((plane_downdip_azimuth > 225) and (plane_downdip_azimuth <= 315)) [plane_quadrant_dip: "W"]
]
line_azimuth: azimuth_vector axis_vector
line_plunge: 90 - (arccosine (axis_vector/3))
]
]
repr: func [][
print rejoin ["Matrix: " tab self/matrix
newline
"Plane: " tab
north_reference to-string to-integer self/plane_direction "/" to-string to-integer self/plane_dip "/" self/plane_quadrant_dip
newline
"Line: " tab
rejoin [north_reference to-string to-integer self/line_azimuth "/" to-string to-integer self/line_plunge]
]
]
trace_te: func [diagram [object!]][
len_queue_t: 0.3
tmp: reduce [
plane_normal_vector/1 / (square-root (((plane_normal_vector/1 ** 2) + (plane_normal_vector/2 ** 2))))
plane_normal_vector/2 / (square-root (((plane_normal_vector/1 ** 2) + (plane_normal_vector/2 ** 2))))
]
O: [0 0]
A: reduce [- tmp/2
tmp/1
]
B: reduce [tmp/2 0 - tmp/1]
C: reduce [tmp/1 * len_queue_t
tmp/2 * len_queue_t
]
L: reduce [- axis_vector/1 0 - axis_vector/2]
append diagram/plot [pen black]
diagram/trace_line A B
diagram/trace_line O C
diagram/trace_line O L
]
]
>> o: orientation/new [0.375471 -0.866153 -0.32985 0.669867 0.499563 -0.549286 0.640547 -0.0147148 0.767778]
>> o/repr
Matrix: 0.375471 -0.866153 -0.32985 0.669867 0.499563 -0.549286 0.640547 -0.0147148 0.767778
Plane: Nm120/39/S
Line: Nm299/0
Another advantage of this way is that variables defined by the "new" method directly belongs to the object "instance" (I ran into some trouble, with the other methods, having to mention self/ sometimes, having to initialize variables or not).
I'm trying to find out how OO works in REBOL. Prototypical indeed. Yesterday I came across this page, which inspired me to the classical OO model below, without duplication of functions:
;---- Generic function for class or instance method invocation ----;
invoke: func [
obj [object!]
fun [word!]
args [block!]
][
fun: bind fun obj/.class
;---- Class method names start with a dot and instance method names don't:
unless "." = first to-string fun [args: join args obj]
apply get fun args
]
;---- A class definition ----;
THIS-CLASS: context [
.class: self ; the class refers to itself
;---- Class method: create new instance ----;
.new: func [x' [integer!] /local obj] [
obj: context [x: x' .class: none] ; this is the object definition
obj/.class: self/.class ; the object will refer to the class
; it belongs to
return obj
]
;---- An instance method (last argument must be the instance itself) ----;
add: func [y obj] [
return obj/x + y
]
]
Then you can do this:
;---- First instance, created from its class ----;
this-object: THIS-CLASS/.new 1
print invoke this-object 'add [2]
;---- Second instance, created from from a prototype ----;
that-object: this-object/.class/.new 2
print invoke that-object 'add [4]
;---- Third instance, created from from a prototype in another way ----;
yonder-object: invoke that-object '.new [3]
print invoke yonder-object 'add [6]
;---- Fourth instance, created from from a prototype in a silly way ----;
silly-object: yonder-object/.class/.class/.class/.class/.new 4
print silly-object/.class/add 8 silly-object
print this-object/.class/add 8 silly-object
print THIS-CLASS/add 8 silly-object
(It works in REBOL 2, and prints 3, 6, 9, 12, 12, 12 successively.) Hardly any overhead. Probably it won't be difficult to find a dozen of other solutions. Exactly that is the real problem: there are too many ways to do it. (Maybe we'd better use LoyalScript.)