-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathdocumentation.txt
144 lines (113 loc) · 6.86 KB
/
documentation.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
PACKAGE
package proto
import "github.com./eblume/proto"
proto gives Go operations like Map, Reduce, Filter, De/Multiplex, etc.
without sacrificing idiomatic harmony or speed.
The `Proto` type is a stand-in approximation for dynamic typing. Due to
Go's powerful casting and type inference idioms, we can approximate the
flexibility of dynamic typing even though Go is a statically typed
language. Doing so sacrifices some of the benefits of static typing AND
some of the benefits of dynamic typing, but this sacrifice is
fundamentally required by Go until such time as a true 'Generic' type is
implemented.
In order to use a Proto-typed variable (from here on out, simply a
'Proto'), you will generally have to cast it to a type that you will
know to use based on the semantics of your program.
This package (specifically, the other files in this package) provide
operations on Proto variables as well as some that make Proto variables
out of 'traditionally typed' variables. Many of the operations will
require the use of higher-order functions which you will need to
provide, and those functions commonly will need you to manually "unbox"
(cast-from-Proto) the variable to perform useful operations.
Examples of the use of this package can be found in the "*_test.go"
files, which contain testing code. A good example of a higher-order
function which will commonly need manual-unboxing is the `Filter`
function, found in "filter.go". `Filter` takes as its first argument a
filter-function which will almost certainly require you to un-box the
Proto channel values that it receives to perform the filtering action.
Finally, a word on the entire point of this package: while it is named
after the Proto type that pervades it and guides its syntax, the true
nature of the `proto` package lies in cascading channels, rather than in
dynamic typing. In fact this package might be more appropriately named
after channels. Maybe `canal` would have been a better name. I wanted to
bring the syntax and familiar patterns of functional programming idioms
to the power and scalability of Go's goroutines and channels, and found
that the syntax made this task very simple.
You may find, as I did, that the majority of the code in this package is
very 'obvious'. At first I was concerned by this - much of the code is
very trivial - but now I feel pleased by the re-usability and natural
'correctness' of `proto`. Look at this package not as some monumental
time-saving framework, but rather as a light scaffold for a useful and
idiomatic style of programming within the existing constructs of Go.
Ultimately, though, you're going to be typing the word Proto an awful
lot, and thus the type became the eponym.
FUNCTIONS
func Demultiplex(fn FilterFn, recv chan Proto) (passed chan Proto,
failed chan Proto)
Separate an input channel in to two output channels by applying a filter
function (see `Filter`). The first output channel will get the values
that passed the filter, the second will get those that did not.
func Filter(fn FilterFn, recv chan Proto) (send chan Proto)
Filter the channel with the given function. `fn` must return true or
false for each individual element the channel may receive. If true, the
element will be sent on the return channel. As usual, this function does
not block beyond the time taken to set up the returned channel.
func Gather(recv chan Proto) (result []Proto)
The inverse of `Send`. Given a channel of Proto's, gathers them in to a
newly created slice, and then returns that slice. This function DOES
BLOCK. If the channel never receives any values, the returned slice will
be empty, with length 0, and capacity 1.
func Map(fn MapFn, recv chan Proto) (send chan Proto)
Apply `fn` to each value on `recv`, and send the results on the return
channel. Order is preserved. Though `Map` does not block, it is not
parallel - for a parallel version, see `PMap`.
func Multiplex(inputs ...chan Proto) (send chan Proto)
Combine multiple input channels in to one.
func PFilter(fn FilterFn, recv chan Proto) (send chan Proto)
Exactly like `Filter`, but every filter application gets its own
goroutine. Order is NOT preserved. As a rule of thumb, `PFilter` is only
preferable over `Filter` if `fn` is very expensive or if the consumer of
the result channel is very slow and buffering would be preferred (thus
keeping up consumption rates of `recv`).
func PMap(fn MapFn, recv chan Proto) (send chan Proto)
Parallel version of `Map`. Order is NOT preserved.
func PTrigger(fn TriggerFn, count int) (send chan Proto)
Exactly like `Trigger`, but each trigger happens in parallel. Order is
NOT preserved.
func Reduce(fn ReduceFn, recv chan Proto) (send chan Proto)
Reduce the `recv` channel by repeatedly applying `fn` on pairs of values
until only one value remains. The first invocation of `fn` will receive
the first two values from `recv`, all subsequent invocations will
receive progressive elements from `recv` *in order* - that is, `fn` may
or may not be associative. If `recv` receives only one value, `fn` will
not be called and the first and only value will be sent as the result.
If `recv` receives no values, `nil` will be sent (as a Proto type) as
the result. Regardless, `recv` will always receive one value and then be
closed.
func Send(vals []Proto) (send chan Proto)
Given a slice of Proto's, send them on a newly created channel and then
close that channel. If the slice is empty, this does the correct thing -
it creates the channel, and then closes it promptly. As expected, this
function does not block beyond the setup time.
func Splice(a chan Proto, b chan Proto)
Sends all items from channel `a` to channel `b`, and then closes `b`.
Does not close `a`. Does not block. This function is useful, eg, when
trying to create a loop of procedures that return channels - take the
output channel of the last element in the chain, create a channel for
the input to the first element in the chain, and link them using Splice.
func Trigger(fn TriggerFn, count int) (send chan Proto)
Call `fn` `count` times, passing the result on to the returned channel.
TYPES
type FilterFn func(Proto) bool
Filter function type definition. A FilterFn is given a single Proto and
must decide whether to return `true` or `false`, meaning "filter" or
"don't filter" respectively. The implementer will probably need to unbox
the Proto argument to a more useful type manually.
type MapFn func(Proto) Proto
Mapping function type definition.
type Proto interface{}
The Proto type. (Get it?)
type ReduceFn func(Proto, Proto) Proto
Reducing function type definition.
type TriggerFn func() Proto
Trigger function type deceleration.