(Attachment Five) Minutes (Attachment Five-A) (Attachment ...
five
-
Upload
zivanka-rumer -
Category
Documents
-
view
24 -
download
0
description
Transcript of five
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