aboutsummaryrefslogtreecommitdiffhomepage
path: root/applause.lua
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2015-04-30 00:36:31 +0200
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2015-04-30 00:36:31 +0200
commitb7b7e85c5c6cc752b0b91294e0544976d237bc7c (patch)
treed9a910d721828da15bb8917de85211d90a849613 /applause.lua
parent292dcdca350dc0636dcd766b27aeb5348d8888fe (diff)
downloadapplause2-b7b7e85c5c6cc752b0b91294e0544976d237bc7c.tar.gz
added RavelStream and minor changes to make streams of non-numbers possible
Diffstat (limited to 'applause.lua')
-rw-r--r--applause.lua73
1 files changed, 68 insertions, 5 deletions
diff --git a/applause.lua b/applause.lua
index 6240f43..c2d8c34 100644
--- a/applause.lua
+++ b/applause.lua
@@ -162,6 +162,10 @@ function Stream:sub(i, j)
return SubStream:new(self, i, j)
end
+function Stream:ravel()
+ return RavelStream:new(self)
+end
+
-- This is a linear resampler thanks to the
-- semantics of __index
function Stream:resample(factor)
@@ -311,21 +315,28 @@ function Stream:__call()
local vector = {}
while true do
- local sample = tick()
+ local value = tick()
- if not sample then break end
- table.insert(vector, sample)
+ if not value then break end
+ table.insert(vector, value)
end
return vector
end
function Stream:__tostring()
+ local t
+
if self:len() > 1024 then
- return table.concat(self:sub(1, 1024)(), " ").."..."
+ t = self:sub(1, 1024)()
+ table.insert(t, "...")
else
- return table.concat(self(), " ")
+ t = self()
end
+
+ for i = 1, #t do t[i] = tostring(t[i]) end
+
+ return "{"..table.concat(t, ", ").."}"
end
function Stream.__add(op1, op2)
@@ -373,6 +384,8 @@ end
-- FIXME: Length comparisions can already be written
-- elegantly - perhaps these operators should have
-- more APLish semantics instead?
+-- However Lua practically demands these metamethods
+-- (as well as __eq) to return booleans.
function Stream.__lt(op1, op2)
return op1:len() < op2:len()
@@ -456,6 +469,56 @@ function ConcatStream:len()
return len
end
+-- Ravel operation inspired by APL.
+-- This removes one level of nesting from nested streams
+-- (e.g. streams of streams), and is semantically similar
+-- to folding the stream with the Concat operation.
+RavelStream = DeriveClass(Stream, function(self, stream)
+ self.stream = tostream(stream)
+end)
+
+function RavelStream:tick()
+ local stream_tick = self.stream:tick()
+ local current_tick = nil
+
+ return function()
+ while true do
+ if current_tick then
+ local value = current_tick()
+ if value then return value end
+ current_tick = nil
+ end
+
+ local value = stream_tick()
+
+ if type(value) == "table" and value.is_a_stream then
+ current_tick = value:tick()
+ else
+ return value
+ end
+ end
+ end
+end
+
+function RavelStream:len()
+ if self.stream:len() == math.huge then
+ -- FIXME: Actually, it is possible that the stream
+ -- is infinite but consists only of empty streams.
+ -- In this case, tick() will be stuck in an infinite loop...
+ return math.huge
+ end
+
+ local len = 0
+ local t = self.stream()
+
+ for i = 1, #t do
+ len = len + (type(t[i]) == "table" and t[i].is_a_stream and
+ t[i]:len() or 1)
+ end
+
+ return len
+end
+
IotaStream = DeriveClass(Stream, function(self, v1, v2)
if not v2 then
self.from = 1