five

33
five implementing streams using classes

description

five. implementing streams using classes. Exercise 1. [repeat list count ] Returns count copies of list , in order [random-pattern count elements … ] Returns a list of count objects randomly chosen from elements. Limitations of lists. What wrong with these? - PowerPoint PPT Presentation

Transcript of five

five

implementing streams using classes

Exercise 1

[repeat list count] Returns count copies of list, in order

[random-pattern count elements …] Returns a list of count objects randomly

chosen from elements

Limitations of lists

What wrong with these? [repeat [list 1 2 3 4]

∞] [random-pattern ∞ 1 2 3 4 5]

SuperCollider lets you make patterns that run infinitely But lists have to be finite length because they store all

the elements in memory at once And memory is finite

Streams

Streams are like lists They “contain” a set of objects In a specified order

But unlike lists You can’t ask for an arbitrary elelement (i.e. you can’t

to get or second) You can only ask for the “next” element On the other hand, they can be infinitely long

The basic idea

Rather than storing all the elements in memory at once

We store just enough information to figure out what the next element should be

And then run code to figure it out each time we need a new element

Implementing streams using classes

Make a “base class” called Stream

Implement different Pseq, etc. operators as subclasses of stream

Each stream supports two generic functions

[next-element s]Returns the next element of s

[reset s]Goes back to the first element

[done? s]Returns true is s has no more elements

Stream

ListStream RandomStream

RandomStreamNoRepeats

JoinedStream

Last time

[class [Name fields …] Parent-type additional-fields …] Creates a new data type Has all the fields of Parent-type, plus fields, and additional-fields Note: last week, this was called “class-type”; I’ve decided to

shorten the name

[new Type field-values …] Creates a new data object of the specified Type (class) Field-values are used as values for fields mentioned in the class

definition, but not additional-fields.

Last time

[generic-procedure] Makes a kind of procedure whose behavior depends

on the types of its arguments

[define-method [generic [type arg] …] code …] Specifies what code to run a generic procedure is

given arguments with a certain set of types When each arg is passed a value of its respective

type, then code is run.

Code for the base class

[using Packages.SimpleClasses]

[define Stream [class [Stream] Object]]]

[define next-element [generic-procedure]]

[define reset [generic-procedure]]

[define done? [generic-procedure]]

The ListStream class

Simple example

Idea: make a stream from a list [new ListStream list]

Should return a stream that will generate each of list, in order, and then end

Code for the ListStream class

[define ListStream [class [ListStream list] Stream position]]

[define-method [reset [ListStream s]][s.position ← 0]]

[define-method [next-element [ListStream s]][with answer = [get s.list s.position] [s.position ← [+ s.position 1]]

answer]]

[define-method [done? [ListStream s]][= s.position [length s.list]]]

Initializing objects

[define ListStream [class [ListStream list] Stream position]]

Okay we know that the list field gets its value from the call to new: [new ListStream list]

But what value does position get? Answer: null

This is a pain, because we need position to be a number

The initialize generic procedure

[define-method [initialize [ListStream s]] [s.position ← 0]]

When an object is created Meta calls the initialize procedure on it Before returning it from new

So you can provide any special code you want to run by providing a method for your new class

But wait …

[define-method [initialize [ListStream s]] [s.position ← 0]]

[define-method [reset [ListStream s]][s.position ← 0]]

This is the same code as reset…

But wait …

[define-method [initialize [ListStream s]] [reset s]]

[define-method [reset [ListStream s]][s.position ← 0]]

So why not just have initialize call reset?

But wait …

[define-method [initialize [Stream s]] [reset s]]

[define-method [reset [ListStream s]][s.position ← 0]]

In fact, we can make it a method for the whole Stream class, not just for ListStreams It will still run for ListStreams because they’re a kind of Stream

Random streams

ListStreams don’t let us do anything we couldn’t do with lists

Let’s think about how to implement the random streams in such a way that the streams can be “infinite”

[new RandomStream list-of-elements desired-length] Should generate a stream of desired-length elements from list-of-elements

The objects need to store The list of objects to choose (randomly) from The number of objects we’ve generated The number of objects we need to generate

RandomStream code

[define RandomStream [class [RandomStream list desired-length] Stream current-count]]

[define-method [reset [RandomStream s]][s.current-count ← 0]]

[define-method [done? [RandomStream s]][= s.current-count s.desired-length]]

[define-method [next-element [RandomStream s]][s.current-count ← [+ s.current-count 1]][get s.list [random-integer 0 [length s.list]]]]

Note no initialize methodWhy?

Testing it out

[define stream→list[stream max-length → [with elements = [new System.Collections.ArrayList] count = 0 [while [and [< count max-length] [not [done? stream]]] [count ← [+ count 1]] [elements.Add [next-element stream]]] elements]]]

We need some way of testing out whether it works The easiest way is to make a procedure that will read a list of

numbers from the stream and print them

Testing it out

► [stream→list [new RandomStream [list 1 2 3] ∞] 20]

[2 2 1 3 3 3 2 3 1 3 3 2 1 1 1 3 2 2 1 1]

Random without repeats

Now let’s do the equivalent of SuperCollider’s Pxrand

All we need to do is Remember one additional piece of

information: the last number we generated Change the next-element method

RandomStreamNoRepeats code

[define RandomStreamNoRepeats [class [RandomStreamNoRepeats list desired-length] RandomStream last-value]]

[define-method [reset [RandomStreamNoRepeats s]][s.last-value ← null][call-next-method]]

[define-method [next-element [RandomStreamNoRepeats s]][with new-value = s.last-value [while [= new-value s.last-value] [new-value ← [get s.list [random-integer 0 [length s.list]]]]] [s.last-value ← new-value] new-value]]

Testing it out

► [stream→list [new RandomStreamNoRepeats [list 1 2] 100] 20]

[1 1 1 2 2 2 1 1 2 2 2 2 2 1 2 2 2 1 1 1]

Oops….

RandomStreamNoRepeats code

[define RandomStreamNoRepeats [class [RandomStreamNoRepeats list desired-length] RandomStream last-value]]

[define-method [reset [RandomStreamNoRepeats s]][s.last-value ← null][call-next-method]]

[define-method [next-element [RandomStreamNoRepeats s]][with new-value = s.last-value [while [= new-value s.last-value] [new-value ← [get s.list [random-integer 0 [length s.list]]]]] [s.current-count ← [+ s.current-count 1]] [s.last-value ← new-value] new-value]]

Testing it out

► [stream→list [new RandomStreamNoRepeats [list 1 2] 100] 20]

[1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2]

Oops….

RandomStreamNoRepeats code

[define RandomStreamNoRepeats [class [RandomStreamNoRepeats list desired-length] RandomStream last-value]]

[define-method [reset [RandomStreamNoRepeats s]][s.last-value ← null][call-next-method]]

[define-method [next-element [RandomStreamNoRepeats s]][with new-value = s.last-value [while [= new-value s.last-value] [new-value ← [get s.list [random-integer 0 [length s.list]]]]] [s.current-count ← [+ s.current-count 1]] [s.last-value ← new-value] new-value]]

This time, the parentclass is RandomStream

RandomStreamNoRepeats code

[define RandomStreamNoRepeats [class [RandomStreamNoRepeats list desired-length] RandomStream last-value]]

[define-method [reset [RandomStreamNoRepeats s]][s.last-value ← null][call-next-method]]

[define-method [next-element [RandomStreamNoRepeats s]][with new-value = s.last-value [while [= new-value s.last-value] [new-value ← [get s.list [random-integer 0 [length s.list]]]]] [s.current-count ← [+ s.current-count 1]] [s.last-value ← new-value] new-value]]

Notice there’s no done? methodWhy?

RandomStreamNoRepeats code

[define RandomStreamNoRepeats [class [RandomStreamNoRepeats list desired-length] RandomStream last-value]]

[define-method [reset [RandomStreamNoRepeats s]][s.last-value ← null][call-next-method]]

[define-method [next-element [RandomStreamNoRepeats s]][with new-value = s.last-value [while [= new-value s.last-value] [new-value ← [get s.list [random-integer 0 [length s.list]]]]] [s.current-count ← [+ s.current-count 1]] [s.last-value ← new-value] new-value]]

calls the method of the parent class(so we don’t need to init s.current-count)

Pasting streams together

Now we need a way to paste streams together

We just make a new class That remembers the list of streams to paste together And its position in the list And calls the substreams’ next-element methods to

get new elements [new JoinedStream list-of-streams]

Should return a stream that generates all the elements of all the streams

JoinedStream class

[define JoinedStreams [class [JoinedStreams stream-list] Stream position]]

[define-method [reset [JoinedStreams j]][for-each reset j.stream-list][j.position ← 0]]

To reset the stream, we reset all the substreams Now, how do we figure out if we’re done?

The done? method

[define-method [done? [JoinedStreams j]] [and [= j.position [− [length j.stream-list] 1]] [done? [get j.stream-list j.position]]]]

Check that we’re on the last substream And the last substream is done

How do we generate the next element?

The next-element method

[define-method [next-element [JoinedStreams j]][when [done? [get j.stream-list j.position]] [j.position ← [+ j.position 1]]][next-element [get j.stream-list j.position]]]

We check whether we need to move on to the next stream yet Note that when is a variant of if that doesn’t take an else clause

Then we generate an element from whatever the current stream is

Testing it out

► [stream→list [new JoinedStreams [list [new ListStream [list 3 2 1]] [new RandomStreamNoRepeats [list 1 2] 100]]] 20]

[3 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2]

It works!ListStream RandomStreamNoRepeats