Skip to content

Commit

Permalink
std/stream: fold, repeat, and limit (#165)
Browse files Browse the repository at this point in the history
* std/stream: Add `Fold()`.

* std/stream: Add `Repeat()` and `Limit()`.

* wdte: Update some dependencies.
  • Loading branch information
DeedleFake committed Nov 30, 2018
1 parent cbe58e9 commit 426d1f9
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 6 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ module github.com/DeedleFake/wdte

require (
github.com/peterh/liner v1.1.0
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8 // indirect
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 // indirect
)
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8Bz
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/peterh/liner v1.1.0 h1:f+aAedNJA6uk7+6rXsYBnhdo4Xux7ESLe+kcuVUF5os=
github.com/peterh/liner v1.1.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869 h1:kkXA53yGe04D0adEYJwEVQjeBppL01Exg+fnMjfUraU=
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8 h1:YoY1wS6JYVRpIfFngRf2HHo9R9dAne3xbkGOQ5rJXjU=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI=
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 h1:YAFjXN64LMvktoUZH9zgY4lGc/msGN7HQfoSuKCgaDU=
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
26 changes: 26 additions & 0 deletions std/stream/end.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,32 @@ func Reduce(frame wdte.Frame, args ...wdte.Func) wdte.Func {
}
}

// Fold is a WDTE function with the following signatures:
//
// fold s r
// (fold r) s
//
// Fold is exactly like Reduce, but is uses the first element of the
// Stream s as its initial element, rather than taking an explicit
// one. If there is no first element, it returns End.
func Fold(frame wdte.Frame, args ...wdte.Func) wdte.Func {
frame = frame.Sub("fold")

if len(args) < 2 {
return auto.SaveArgsReverse(wdte.GoFunc(Fold), args...)
}

s := args[0].Call(frame).(Stream)
cur, ok := s.Next(frame)
if !ok {
return End()
}

r := args[1]

return Reduce(frame, s, cur, r)
}

// TODO: Implement this. It should be able to essentially insert its
// own output into another chain, so that
//
Expand Down
85 changes: 85 additions & 0 deletions std/stream/middle.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,88 @@ func Enumerate(frame wdte.Frame, args ...wdte.Func) wdte.Func {
return r, true
})
}

// Repeat is a WDTE function with the following signature:
//
// repeat s
//
// Repeat returns a Stream that buffers the elements from the Stream
// s. Once s has ended, the Stream starts repeating from the begnning
// of the buffer, looping infinitely. In other words,
//
// range 3 -> repeat
//
// will yield the sequence (0, 1, 2) repeatedly with no end.
//
// Repeat is most useful used with Limit. When combining the two, note
// that Limit limits individual elements, not repetitions, so the
// number passed to Limit should be multiplied properly if the client
// wants to limit to a specific number of repetitions.
func Repeat(frame wdte.Frame, args ...wdte.Func) wdte.Func {
frame = frame.Sub("repeat")

switch len(args) {
case 0:
return wdte.GoFunc(Repeat)
}

s := args[0].Call(frame).(Stream)

var buf []wdte.Func
loop := -1
return NextFunc(func(frame wdte.Frame) (wdte.Func, bool) {
frame = frame.Sub("repeat")

exit:
if loop >= 0 {
n := buf[loop]

loop++
loop %= len(buf)

return n, true
}

n, ok := s.Next(frame)
if !ok {
loop = 0
goto exit
}

buf = append(buf, n)
return n, true
})
}

// Limit is a WDTE function with the following signature:
//
// (limit n) s
//
// Limit returns a Stream that stops after a maximum of n elements
// from s have been yielded.
func Limit(frame wdte.Frame, args ...wdte.Func) wdte.Func {
frame = frame.Sub("limit")

if len(args) == 0 {
return wdte.GoFunc(Limit)
}

n := args[0].Call(frame).(wdte.Number)

return wdte.GoFunc(func(frame wdte.Frame, args ...wdte.Func) wdte.Func {
frame = frame.Sub("limit")

s := args[0].Call(frame).(Stream)

return NextFunc(func(frame wdte.Frame) (wdte.Func, bool) {
frame = frame.Sub("limit")

if n <= 0 {
return nil, false
}
n--

return s.Next(frame)
})
})
}
3 changes: 3 additions & 0 deletions std/stream/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ var Scope = wdte.S().Map(map[wdte.ID]wdte.Func{
"filter": wdte.GoFunc(Filter),
"flatMap": wdte.GoFunc(FlatMap),
"enumerate": wdte.GoFunc(Enumerate),
"repeat": wdte.GoFunc(Repeat),
"limit": wdte.GoFunc(Limit),

"end": End(),
"collect": wdte.GoFunc(Collect),
"drain": wdte.GoFunc(Drain),
"reduce": wdte.GoFunc(Reduce),
"fold": wdte.GoFunc(Fold),
//"chain": wdte.GoFunc(Chain),
"any": wdte.GoFunc(Any),
"all": wdte.GoFunc(All),
Expand Down
14 changes: 14 additions & 0 deletions wdte_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,15 @@ func TestStream(t *testing.T) {
wdte.Array{wdte.Number(2), wdte.String("c")},
},
},
{
name: "RepeatAndLimit",
script: `let s => import 'stream'; s.range 3 -> s.repeat -> s.limit 9 -> s.collect;`,
ret: wdte.Array{
wdte.Number(0), wdte.Number(1), wdte.Number(2),
wdte.Number(0), wdte.Number(1), wdte.Number(2),
wdte.Number(0), wdte.Number(1), wdte.Number(2),
},
},
{
name: "Drain",
script: `let s => import 'stream'; let io => import 'io'; let main => s.range 5 -> s.map (io.writeln io.stdout) -> s.drain;`,
Expand All @@ -529,6 +538,11 @@ func TestStream(t *testing.T) {
script: `let s => import 'stream'; let main => s.range 1 6 -> s.reduce 1 *;`,
ret: wdte.Number(120),
},
{
name: "Fold",
script: `let s => import 'stream'; s.range 5 -> s.fold +;`,
ret: wdte.Number(10),
},
{
name: "Any/True",
script: `let s => import 'stream'; let main => s.range 5 -> s.any (== 3);`,
Expand Down

0 comments on commit 426d1f9

Please sign in to comment.