Recursive collections

In most languages I’ve used you can add a collection to itself (either by pointer or by reference). For example, in python:

x = [1, 2, 3]
x.append(x)
x
>>> [1, 2, 3, [...]]
x[3]
>>> [1, 2, 3, [...]]
x[3][3]
>>> [1, 2, 3, [...]]

I’m trying to do the same thing in SuperCollider, but the interpreter freezes each time. I assume it’s going down a recursive rabbit hole. I’ve tried a few different ways:

x = List[1, 2, 3];
x.add(x);
x = List[1, 2, 3];
x.add(`x);

Is this an interpreter bug? Is there a correct way to do this? I played with Refs but they don’t seem to help. Thanks!

It is recursive as implemented in the language, although it is not represented that way in the code.

You could do this on purpose (not by accident) in a language with lazy evaluation like Haskell.

a = [1, 2, 3];
a = a ++ a;
1 Like
	add {|funcProxy| this.subclassResponsibility(thisMethod) } // proxies call this to add themselves to this dispatcher; should register this if needed

Wow, quick replies here! Thank you :slight_smile:

Lazy evaluation was the magic word, sorry I forgot to mention that.

I think I figured out a workaround, by wrapping the value in a function:

a = List[1, 2, 3];
a.add({a});

Then I can lazily evaluate it like this:

a[3].value;

I know this might seem pointless without context, but I’m trying to build my own pattern library. It’s graph based, so I want patterns to be able to point to themselves, to enable single-pattern looping.

I meant something else with lazy evaluation. In Haskell you can actually have infinite lists, operate and define things logically with them:

https://wiki.haskell.org/The_Fibonacci_sequence

OK, you have LE with patterns, but that’s actually a small language per se in supercollider, you don’t do that with lists

The data structure is constructed in memory exactly as you describe.

The problem is trying to produce a string to print in the post window.

x = [1, 2, 3];  // OK, obviously

// the empty string blocks posting -- this does not hang
x = x.add(x); ""

// the successful identity test here shows
// that the data structure is properly recursive 
x[3] === x[3][3]
-> true

One catch here: “normal” sclang (including running it in SC-IDE) produces post window strings by calling asString on the code block’s result. This method imposes a 512 character limit; a longer result string is truncated, and prints with “…etc…” appended. So the x list in your example will print up to the limit and then stop – no hang.

But, based on your comment in the other thread about preferring vscode, I suppose you’re running it in vscode instead. The language server quark uses CollStream instead of LimitedWriteStream to produce the post window string representation. So it never stops trying to render the infinite recursion.

It’s one of the not-so-ideal things that can happen easily in SC-land, where there isn’t (for instance) a functional spec written down for post window output. So, if someone needs to create an alternate code path to execute code, not going through interpretPrintCmdLine, they are pretty much left to make it up as they go along, and it’s very easy to overlook details like blocking infinite recursion.

You could fix this for yourself in LanguageServer/Providers/EvaluateProvider.sc, around line 46. Probably the easiest way is result[\result] = function.value().asString; and delete the use of CollStream.

It’s graph based, so I want patterns to be able to point to themselves, to enable single-pattern looping.

I don’t know of anything that would prevent you from doing this :+1:

hjh

3 Likes

Oh, I see, so you’re working with patterns.

Interesting to know this about strings. Today I was writing a variation of sclang-eval-string so the result would not be sent to the post window, but appear as a temporary display in the buffer. It made sense in a particular situation, but maybe that’s not something to be playing too much ))

Ah nice, thanks @jamshark70. That is indeed the issue! I’ll take a look at fixing it in the LanguageServer.

@smoge I misspoke, I’m trying to build a pattern-like library and scheduler of my own. Not using the built-in Pattern.

2 Likes