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.
Related
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 want to define block and call it in this way:
add := [ :a :b |
^(a+b).
].
n := add value: 1 value: 2.
But when I try it, I get an error:
$ gst 3.1.st
Object: 3 error: return from a dead method context
SystemExceptions.BadReturn(Exception)>>signal (ExcHandling.st:254)
SystemExceptions.BadReturn class(Exception class)>>signal (ExcHandling.st:151)
SmallInteger(Object)>>badReturnError (Object.st:1389)
UndefinedObject>>executeStatements (3.1.st:3)
How can I call a function in GNU Smalltalk?
Well, I dropped the return statement, and this code works fine. But when I try to define more complicated function, for example:
nod := [ :a :b |
(a=b) ifTrue: [a].
(a>b) ifTrue: [nod value: (a-b) value: b].
(a<b) ifTrue: [nod value: a value: (b-a)].
].
n := nod value: 1 value: 2.
n printNl.
It prints nil. And if I define with "early exit":
nod := [ :a :b |
(a=b) ifTrue: [^a].
(a>b) ifTrue: [nod value: (a-b) value: b].
(a<b) ifTrue: [nod value: a value: (b-a)].
].
n := nod value: 1 value: 2.
n printNl.
It gives me the same error: return from a dead method context.
I solve this problem in this way:
nod := [ :a :b |
(a=b) ifTrue: [
a
] ifFalse: [
(a>b) ifTrue: [nod value: (a-b) value: b] ifFalse: [nod value: a value: (b-a)].
]
].
n := nod value: 1 value: 2.
n printNl.
But I think, it is not beautiful way.
Drop the return statement (^) from your code and it will work fine.
In smalltalk, returning exits the method in which the return statement appears. It's used for early exits, for example a < b ifTrue: [^a] ifFalse:[^b].
In this case, you don't want the block to exit the containing method, you just want it to evaluate to something when sending it value:value:. A block evaluates to the last statement in it, so just make it a regular statement there and it will do the trick.
The error message you got, by the way, also explains the problem: you're trying to return 3 from a method which is already dead.
Remove non-local return (^), parenthesis, and period inside a block. And try doing it again.
You've already accepted an answer to your original question, then redefined your question.
To answer your updated question, you could use the fact that a block returns the value of its last statement, and use a local variable:
nod := [ :a :b | |r|
(a = b) ifTrue: [r := a].
(a > b) ifTrue: [r := nod value: (a-b) value: b].
(a < b) ifTrue: [r := nod value: a value: (b-a)].
r
].
I am curious, though, about the context. I suspect this might more appropriately be defined as a selector/method for a class.
By the way, the above implementation will go into an infinite recursion if either argument is negative.
The simplest way to get the results you're after would be:
nod := [ :a :b | a gcd: b ].
:)
I attempted to write a C-style for-loop in REBOL:
for [i: 0] [i < 10] [i: i + 1] [
print i
]
This syntax doesn't appear to be correct, though:
*** ERROR
** Script error: for does not allow block! for its 'word argument
** Where: try do either either either -apply-
** Near: try load/all join %/users/try-REBOL/data/ system/script/args...
Does REBOL have any built-in function that is similar to a C-style for loop, or will I need to implement this function myself?
The equivalent construct in a C-like language would look like this, but I'm not sure if it's possible to implement the same pattern in REBOL:
for(i = 0; i < 10; i++){
print(i);
}
Because of the rebol3 tag, I'll assume this question pertains to Rebol 3.
Proposed "CFOR" for Rebol 3
For Rebol 3, there is a proposal (which got quite a bit of support) for a "general loop" very much along the lines of a C-style for and therefore currently going under the name of cfor as well: see CureCode issue #884 for all the gory details.
This includes a much refined version of Ladislav's original implementation, the current (as of 2014-05-17) version I'll reproduce here (without the extensive inline comments discussing implementation aspects) for the sake of easy reference:
cfor: func [ ; Not this name
"General loop based on an initial state, test, and per-loop change."
init [block! object!] "Words & initial values as object spec (local)"
test [block!] "Continue if condition is true"
bump [block!] "Move to the next step in the loop"
body [block!] "Block to evaluate each time"
/local ret
] [
if block? init [init: make object! init]
test: bind/copy test init
body: bind/copy body init
bump: bind/copy bump init
while test [set/any 'ret do body do bump get/any 'ret]
]
General problems with user-level control structure implementations in Rebol 3
One important general remark for all user-level implementation of control constructs in Rebol 3: there is no analogue to Rebol 2's [throw] attribute in R3 yet (see CureCode issue #539), so such user-written ("mezzanine", in Rebol lingo) control or loop functions have problems, in general.
In particular, this CFOR would incorrectly capture return and exit. To illustrate, consider the following function:
foo: function [] [
print "before"
cfor [i: 1] [i < 10] [++ i] [
print i
if i > 2 [return true]
]
print "after"
return false
]
You'd (rightly) expect the return to actually return from foo. However, if you try the above, you'll find this expectation disappointed:
>> foo
before
1
2
3
after
== false
This remark of course applies to all the user-level implementation given as answers in this thread, until bug #539 is fixed.
There is an optimized Cfor by Ladislav Mecir
cfor: func [
{General loop}
[throw]
init [block!]
test [block!]
inc [block!]
body [block!]
] [
use set-words init reduce [
:do init
:while test head insert tail copy body inc
]
]
The other control structure that most people would use in this particular case is repeat
repeat i 10 [print i]
which results in:
>> repeat i 10 [print i]
1
2
3
4
5
6
7
8
9
10
I generally do no use loop very often, but it can be used to a similar extent:
>> i: 1
>> loop 10 [print ++ i]
1
2
3
4
5
6
7
8
9
10
Those are some useful control structures. Not sure if you were looking for cfor but you got that answer from others.
I have implemented a function that works in the same way as a C for loop.
cfor: func [init condition update action] [
do init
while condition [
do action
do update
]
]
Here's an example usage of this function:
cfor [i: 0] [i < 10] [i: i + 1] [
print i
]
For simple initial value, upper limit and step, following works:
for i 0 10 2
[print i]
This is very close to C for loop.
The return value of #value: message, when sent to a block, is the value of the last sentence in that block. So [ 1 + 2. 3 + 4. ] value evaluates to 7.
I find that hard to use sometimes. Is there a way to explicitly set the returning value and stop executing the block?
For exercise, try rewriting this block without using my imaginary #return: message and see how ugly it gets. I must be missing something.
[ :one :two |
one isNil ifTrue: [ two isNil ifTrue: [ self return: nil ] ifFalse: [ self return: true ] ].
two ifNil: [ self return: false ].
(one > two)
ifTrue: [ self return: true ]
ifFalse: [ (one < two)
ifTrue: [ self return: false ]
ifFalse: [ self return: nil ]
].
]
EDIT: self return: sth really is nonsense, but it does make sense at some level :)
There's nothing like a guard clause - blah ifTrue: [^ foo] - inside a block, because ^ is a non-local return, returning from the method calling the block rather than the block itself.
Big blocks - like big anythings - should be refactored into smaller, more understandable/tractable subparts, but sometimes that's not always possible. I mean this answer to suggest options to try when you can't really simplify in the usual ways.
If your block is really that complicated, and you can't get it simpler (splitting it up delocalises the information too much, for instance) then perhaps you can use an explicit return value. In particular, if your block doesn't return nil you could do something like
[:one :two | | result |
result := (one isNil and: [two isNil]) ifTrue: [false].
result ifNil: ["do one thing, possibly setting result"].
result]
If your block can return nil, you'll need another sentinel value:
[:one :two | | result marker |
result := marker := Object new.
(result == marker) ifTrue: ["do one thing, possibly setting result"].
result]
Lastly - and I hesitate to suggest this - you could do this:
[1 + 2.
thisContext return: 5.
3 + 4] value
which returns 5.
(Verifying how this interacts with ^ and inlined selectors like #ifTrue:ifFalse: left as an exercise for the reader.)
It seems that your code tries to handles nil like an infinity value when comparing one and two. The following code may be more readable depending on the context:
a := [:one :two |
| x y |
x := one ifNil: [Float infinity].
y := two ifNil: [Float infinity].
(x = y) ifTrue: [nil] ifFalse: [x > y]]
A useful feature of #ifTrue:ifFalse:, #ifNil:ifNotNil: and similar testing methods is that they return the value of the block that gets evaluated. e.g. (4 > 1) ifTrue: ['greater'] ifFalse: ['not-greater'] evaluates to 'greater'. This feature often makes it possible to return a value from a nested block in tail position.
When the code inside a block gets too complicated I suggest your refactor it to a method. But see Frank's answer for workarounds.
Edit:
As pointed out in the comments the code above assumes numbers. I also came up with something that works with other comparable objects:
a:=
[ :one :two |
true caseOf: {
[one = two]->[nil].
[one isNil]->[true].
[two isNil]->[false]
} otherwise: [one>two]]
That #caseOf: construct is rarely used but it's certainly better than thisContext return:
You'd like to implement some break, continue, exit...
The usual way to control flow in Smalltalk is with blocks.
So one funny solution is to use a helper method with a Block return value to break the flow, like described here .
Object>>exitThru: aBlock
^aBlock value: [:result | ^result]
Now, let see how to use it:
| aBlock |
aBlock := [ :one :two |
self exitThru: [:exit |
one isNil ifTrue: [ two isNil ifTrue: [exit value: nil ] ifFalse: [ exit value: true ] ].
two isNil ifTrue: [ exit value: false ].
one > two ifTrue: [ exit value: true ].
one < two ifTrue: [ exit value: false ].
exit value: nil] ].
#(('abc' nil) (nil nil) (nil 'def') ('y' 'abc') ('y' 'y') ('y' 'z'))
collect:
[:pair |
aBlock value: pair first value: pair last ]
-> #(false nil true true nil false)
EDIT my first version was unnecessarily complex, can't remember what lead me to an additional indirection:
| aBlock |
aBlock := [:wrapOne :wrapTwo |
self exitThru: [:exit |
[ :one :two |
one isNil ifTrue: [ two isNil ifTrue: [exit value: nil ] ifFalse: [ exit value: true ] ].
two isNil ifTrue: [ exit value: false ].
one > two ifTrue: [ exit value: true ].
one < two ifTrue: [ exit value: false ].
exit value: nil ]
value: wrapOne value: wrapTwo ] ].
Well, more funny than usefull, I hope you will find more simple and expressive way to code.
This shows how to have a static variable inside an object or context:
http://www.mail-archive.com/list#rebol.com/msg04764.html
But the scope is too large for some needs, is it possible to have a static variable inside an object function ?
Or you can use FUNCTION/WITH. This makes the function generator take a third parameter, which defines a persistent object that is used as the "self":
accumulate: function/with [value /reset] [
accumulator: either reset [
value
] [
accumulator + value
]
] [
accumulator: 0
]
To use it:
>> accumulate 10
== 10
>> accumulate 20
== 30
>> accumulate/reset 0
== 0
>> accumulate 3
== 3
>> accumulate 4
== 7
You may also want to look at my FUNCS function.
In Rebol 3, use a closure (or CLOS) rather than a function (or FUNC).
In Rebol 2, fake it by having a block that contains your static values, eg :
f: func [
/local sb
][
;; define and initialise the static block
sb: [] if 0 = length? sb [append sb 0]
;; demonstate its value persists across calls
sb/1: sb/1 + 1
print sb
]
;; sample code to demonstrate function
loop 5 [f]
== 1
== 2
== 3
== 4
== 5