Mapping list over list

There's a difference i don't get between "numbers from 1 to 10" and a variable that has "numbers form 1 to 10" assigned. Is that intentional? I included a rather silly workaround

Another workaround that works:

Right click on MyList; local menu "ringify" ...
pixelPerf script pic

When you drop a variable into the map grey ring - it is removed (for reasons )

So you need to explicitly add it back in again


I drag the ring out - put my variable in it and then put them both back in

[edit] Obviously @dardoro method is much quicker :slight_smile: [/edit]

It looks like it's not about lists but about the slots of the map-block:

Thank @dardaro and @cymplacy for pointing me to the missing ring

There must be a very good reason for removing the ring :slight_smile:


for explanation - its been mentioned a few times

What is the underlying problem you're trying to solve? I don't really understand why you'd want to put something other than a function in the first slot. (You're putting a list there.)

I was recreating Jens' explanation of the digitar. Started with list of 50000 randoms from [-1,1] that sounds like noise. Then put the first (say) 200 items in a "short list" and wanted that short list 249 times appended to itself. I got myself into trouble by working with a temporary variable for the short list …, because moving this list into the ring of the map-block removed the ring.

So this is problematic

And this works

But, I admit, I haven't read the manual after version 5 . So sorry for posting this as under bugs.

In the first of the two images, you put the slice variable in the bottom map reporter, but what is the value of slice? It is a list because (item (numbers from (1) to (200)) of (noise)) reports a list and it's not ringified, so it gets evaluated.
Notice how in the second image the item reporter is ringified in the bottom map reporter.

Exactly! But it's quite a feature that the ring disappears when you insert a list into it.

Yes, I agree that the automatic disappearance of the ring when you drop a variable reporter onto it is almost unexplainable when you begin to think about it. It is documented on p. 50 of the Reference Manual, though. This atypical behavior has been one of the few really major and serious disagreements between Brian and me, and I was not convinced but "had my arms twisted" and my will broken about the decision at the time. The argument that a variable reporter should not be regarded as a "reporter" but as something else revulsed me (still does).

BUT: I've since come around!

In the vast majority of use-cases you will actually want the ring to disappear, and you would have to remember to do it manually. There would be lots and lots of bugs where you'd forget to unringify variables that already point to a procedure, as that is the primary use of variables - formal parameters! - inside custom block definitions.

Your way of using MAP to repeat a list of numbers is the exception, and a somewhat kludgy one (yes, I know, I showed you, that doesn't make it less kludgy), because we never use any of the numbers in the list we're mapping over. Instead we're soft of hijacking MAP to be a reporter version of REPEAT. That's clever, but ... a kludge. Also, this only covers the first part of the digitar algorithm, which just repeats a short list of noise. The trick behind the Karplus-Strong string synthesis is the feedback part. For this you'll need to mutate the "buffer" of random numbers at every repeat. Much as I'm a proponent of functional programming this part of the algorithm can really be written much more effectively and simpler in plain old imperative style.

... or you build a bigger toolkit of higher order functions, something like this:

where the append and list are accumulating a melody, and the better-noise and map are refining a noise burst. I'd have to look up the complete example to see all the details.

By the way, this is a canonical example of the need for variadic input groups. Instead of separate cascade (in the iteration library) and cascade2 (which I just hacked up for the occasion), what I want is a single cascade block with a variadic function-and-initial-value input group.

(Maybe not obvious: the two inputs to append will be the values-so-far of the two iterated values, so it's (append melody-so-far best-noise-so-far). Better-noise takes two inputs but ignores the first one, so it effectively just uses the previous noise.)

Could Snap!'s long to-do list be extended to address terrible error messages? Why not an error message that says that a ringed value was expected to map instead of "Cannot read property 'length' of undefined"?

The disappearance of the ring to me is an instance of DWIM. I recall in the 70s it was popular at Stanford and PARC and people at MIT were very critical of it. I see it as a trade-off between convenience most of the time at the cost of mysterious behaviour on the occasions where the system didn't really know what you meant.

Historical anecdote: When I first used InterLisp (after 10 years of MacLisp and CommonLisp) I named a variable 'ab' since it was the product of a and b. Well, DWIM thought I meant ( a b) instead.

I agree about the terrible error messages, which are the ones we get from Javascript. Over time we've replaced some of the worst offenders one at a time, but we're not more aggressive about this partly because Jens correctly points out that checking for errors really slows Snap! down, even when there isn't an error.

Maybe someday we can have the best of both worlds by interposing an error handler between JS's one and the user, to translate the terrible error message into an appropriate one.

I was at Stanford when I learned about DWIM, so maybe that's why it occurred to me to put in this special case. I have DWIM-like instincts in a lot of situations but most of the time I fight them down. (To be fair, the fact that making a clone shares certain attributes but copies others is Jens's doing, so he has DWIM-like instincts too, sometimes.) The one idea I have for Snap! that's explicitly based on DWIM is hybrid scope, which would come into play only at the point where Snap! is about to give an unbound variable error. (But we don't have hybrid scope because Jens convinced me that it'd still slow down Snap! because of tail call elimination, which loses the dynamic environment. I have to invent an algorithm without that weakness.)

Anyway, back to the topic: I think that this particular DWIM-like behavior is a pragmatic necessity for us. There are two reasons. One is that using a niladic function in the function input of a HOF is really quite rare and non-intuitive. The other, larger reason is that we've learned from a ton of experience with students that developing a solid mental model of function as data is much, much harder for students than using HOFs without thinking about them too hard. And we want to encourage that! Let students get a lot of practical experience with HOFs first, and then develop the rigorous understanding later. And putting a variable into the function slot is very common, especially when it comes to implementing a HOF.

I think it might be worth considering adding a "(number) COPIES OF (expression)" primitive, even though that's trivial to implement in Snap!, just to finesse the one case in which calling a niladic function in a MAP is useful.

Regarding the cost of generating better error messages, while I see the issue in general, I'm uncertain in this case. map need only check the function argument upon entry - not on every iteration. And if the map is itself inside of a map or another kind of iteration a clever implementation needn't check on every iteration.

I wonder if these well-motivated instances of DWIM could be enhanced if the user is informed of what is going on. E.g. dropping a variable on map causes a message to be displayed for a few seconds. It could say something like "Ring was removed on the assumption that variable names a function. For more information see page of the manual." This would avoid some confusion and have some pedagogic value. But also may be annoying so perhaps this could be controlled by a setting.

The kind of DWIM that is most questionable is not when it occurs during program construction (e.g. dropping a variable on map). But when it occurs at runtime (e.g. the cloning example you mention) it has the added cost of making a user's conceptual model of the language more complex.

I definitely agree with this part. :~P