Custom block doesn't work, why?

I tried to make a custom block but it doesn't work and I don't know why.

The target_list's value is (as intended) made empty list and then added the txt_input_value. But this change is lost on the outside of the custom block (after being run). What am I missing here? Link.

Inside the custom block if list_target = 0, global foo is not changed, but rather the paramater list_target.

Is there any way I can change the global foo by a custom block, too?

Put set foo to empty list in the block definition.

Then it will work only for this particular global variable but when I will drag into the block's second slot any other (global) variable, the other (dragged-in) variable will not be changed.

Ah. It's the value of the 'foo' variable that gets passed to the block instead of the variable itself.

You can fix this by changing the 'list_target' variable to be an unevaluated input.

Once you've done that, the 'list_target' variable will no longer have the value of 'foo', which is (initially) 0, but the 'foo' variable block itself. You can call it to get the current value of 'foo', or use the 'set' and 'run' blocks to set it.

Making_an_Add_to_list_custom_block script pic

Note that, in the 'set' block above, the value that's auto-filling into the 'set' block isn't the 'list_target' variable block itself, but the value of the 'list_target' variable, which is the 'foo' variable block.

Imho the right solution is to initialize FOO in the main script before calling your ADD block. When a block takes a list as an input, you have to call it with a list, not with a variable whose value you wish were a list but isn't.

Yeah, choosing for the slot's type the 'list' option instead of 'Any (unevaluated)' was a mistake I did, as explained by @rdococ above. But before I decided to post yet another question (I was afraid I may be posting too much recently), I already knew I should choose something else for the slot, but was not sure - so I experimented with Any type that didn't work either.

Since I have no intuition and even less knowledge what might be the difference between 'Any type' and 'Any (unevaluated)' options, I decided to post yet another question to get some answers.

I looked up in the Manual's index and the term 'Any (unevaluated)' is mentioned only once at page 53 in the context of making an "if then else" custom block in order to explain 'Special Forms' (which I must admit I didn't understand).

Could you explain what is the difference between 'Any type' and 'Any (unevaluated)' options?

I can try, but first I'm going to reiterate that this is a very complicated solution to a very simple problem that should be solved by initialilzing the variable before calling the block. We are still going back and forth about the fact that you want variables to have types, and they don't.

Lists are a mutable data type. If you use a list as the input to your ADD TO LIST block, then your block can mutate the list (just as the primitive one does), whether or not the list is the value of a variable. You'll be able to say ADD 3 TO LIST (ITEM 5 OF FOO) or ADD 3 TO LIST (LIST 1 2 8) or any list-valued expression. Whereas what you're trying to do is restrict your block so it only works in the special case of a variable whose value is a list.

Okay, now to answer your question.

Ordinarily, :sn:, like most programming languages, uses applicative order evaluation. This means that when you call a procedure, the evaluator first evaluates all the input expressions, and then calls the procedure, giving it the input values. So when you say (5 + (3 * 4)), the + block knows only that its input values are 5 and 12. It doesn't know whether you said (5 + 12) or (5 + (24 / 2)) or (5 + FOO) where FOO is a variable whose value right now is 12.

This is mostly what you (generic you) want, and almost always what you should want, so that your block doesn't have to know who's calling it and why. It just does the job it contracts to do.

But there are a few situations in which applicative order evaluation doesn't work. The canonical example is writing a conditional operation, such as reporter-IF. That's now a primitive in :sn:, but it didn't used to be. At first glance it seems like it should be easy to write:
U1L1-ClickAlonzo script pic (1)
and this does work in easy situations:
U1L1-ClickAlonzo script pic (3)
But it doesn't work in the very important case of the base case test of a recursive procedure:
U1L1-ClickAlonzo script pic
Why not? Because of applicative order evaluation. If you ask for (factorial 0), it's not going to work if the call to the IF block first evaluates its three input expressions, then calls IF with the three values. Why not? Because the third one involves a request to compute (factorial -1), and that will ask for (factorial -2), and so on forever.

Well, as it turns out, :sn: has (and has always had, from BYOB3) a solution to this problem: use functions as the THEN and ELSE inputs to IF. Functions are a way to make an expression but not evaluate it right away. So we change the IF block:
U1L1-ClickAlonzo script pic (4)
This version will work, but it's a little ugly. The block itself looks like this:
U1L1-ClickAlonzo script pic (5)
and its use in FACTORIAL looks even worse:
U1L1-ClickAlonzo script pic (6)
(We need the VALUE function, which just reports its input, because you can't type a number into a reporter-type input slot.)

Okay, you still following? Recap: The easy version of IF doesn't work. We can fix it by using the fact that we have first class procedures to delay the evaluation of the THEN and ELSE expressions. The IF block will then pick one of them to evaluate based on the value of the first input. But the cost of this is making the interface to IF kind of offputting.

It's important that you understand that as far as being able to do the job is concerned, we've already solved the problem. It's just the notation we don't like.

So, we want something that looks like the first version of IF, but works like the second one. Saying that another way, we want a special kind of procedure whose inputs :sn: knows not to evaluate. Historically, that "special kind of procedure" is called a special form. (Fine print: Programming language mavens will tell you that a special form isn't a procedure at all. It's a special syntax that may look like a procedure call but is really something else. In muggle languages there are tons of special syntaxes, for IF, WHILE, FOR, all those things. But muggles expect to have a zillion different syntactic forms, so they don't think of them as "special.")

In :sn: we allow "specialness" to be determined for each input slot; traditional Lisp has it all or nothing. So, in the case of the IF reporter, the first input doesn't have to be special, because it's definitely going to be evaluated first thing, so we can let the :sn: evaluator take care of that before calling IF. But the other two inputs are going to be declared "Any (unevaluated)." This means exactly the same thing as if they'd been declared Reporter type, i.e., the expression is turned into a procedure as if it had a ring around it. But the notation is different; what the user sees is a rectangular Any-type slot. The ring is still there, so to speak, but it's hidden.

That's the story. Still not clear? Ask a more specific question.

Ha ha, good one. (Thanks for making me laugh) Also, I like words that I as a non-native English speaker haven't met yet - such as maven, an interesting word with an interesting history.

Yeah, I learned programming mainly from muggles' sources. And I must admit it makes a nice difference to be from time to time taught by a maven.

I'd like to double check if I understand the following correctly:

a) the rule is: I should not want any procedure's behavior to depend on its caller, right?

b) a procedure should evaluate all inputs before giving an answer

c) there is an exception to the rule above, because recursive procedures (question: all of them? or just this particular one, i.e. computing the factorial?) will get into trouble evaluating the second (i.e. ELSE) input for the base case, so we need to revert to a solution offered by BYOB3, i.e. ringified functions (question: why don't we evaluate the first (i.e. "THEN input") only - while skipping the evaluation of "ELSE input" - if the "IF input" proves to be true?).

d) the solution (offered by :sn: since BYOB3) involves using the 'Any(unevaluated)'.

e) what the user sees is a rectangular Any-type slot (question: do you mean 'Any(unevaluated)' or 'Any' slot?)

e) the ring will be invisible to the user.


More like ":sn: will evaluate all inputs before calling the procedure." If you want to express that from the procedure's point of view, it'd be "a procedure should expect to be given input values, not input expressions."

Here I think you're a little confused. It's not the recursive procedure (using factorial as the example, but not specific to factorial) that's special. It's the IF block that's special. The thing about recursive procedures is that when IF is used to check the base case of a recursion, that's the main situation in which it matters that IF's inputs don't get evaluated before IF is called. But it's not the only situation; consider this one:
U1L1-ClickAlonzo script pic
If all IF's inputs were evaluated in advance, and if FOO isn't a number, the THEN input will cause an error. We only get to multiply it by itself if it's a number.

So, IF is the thing that has to be a special form. We could do that by declaring the THEN and ELSE inputs to be of type Reporter, but then the block looks intimidating and you can't use a constant value as input (such as the 1 in the factorial example). So instead we cheat, and use "Any (unevaluated)" as the input type. That means "this input is really a Reporter, but we're going to make it look like an Any input. There's still sort of the ghost of a ring around that input slot.

We do! Look again at the definition:
U1L1-ClickAlonzo script pic (1)
Only one of those CALL blocks will be run, so only one of the TRUE and FALSE inputs will be evaluated.

Yes and yes. As for your question under (e), the answer is that we're talking about what the user sees, and the "Any (unevaluated)" input slot looks just like the regular Any slot. That's the whole point; we are pretending it's an Any slot when really it's a Reporter slot.

But, I don't understand, you say "if FOO isn't a number" and if, as you say next, we "do evaluate the first (i.e. the THEN input), only when the IF input did prove to be true, isn't it so that because the "IF input" didn't prove to be true, we then don't need to evaluate the first one (i.e. "THEN input" one) at all?

Oh, I see now what you mean.

Maybe you can put an additional text/description beside the AUE option in the dialog with the options?

additional text for the AUE option

Short answer: Any type evaluates the input expression before calling the block and the result of the expression is passed to the block. Any (unevaluated) ringifies the input expression and the ring is passed to the block.

Nice. Thank you.

The subject under discussion is why this IF block has to be a special form, not an ordinary procedure. And the answer is, for ordinary procedures, all the inputs are evaluated before the procedure is called! What I said was, "If all IF's inputs were evaluated in advance, and if FOO isn't a number, the THEN input will cause an error." So this example shows that IF's inputs mustn't be evaluated in advance! Yes, you're right that we don't need to evaluate the THEN input (don't call it "the first input"; it's the second input), and in fact it's worse than that: We must not try to evaluate that second input. And that's why this IF block has to be a special form, not an ordinary procedure!