[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: New egg: CHICKEN Transducers
From: |
siiky |
Subject: |
Re: New egg: CHICKEN Transducers |
Date: |
Mon, 9 Jan 2023 18:45:35 +0000 |
Hiya,
This wouldn't work very well with the current API in Scheme, because the
fold is passed to transduce explicitly. And given that, either a
restriction must be imposed on the input data structures (they must all
be of the same type); or the folder of each input data structure must be
given. If the latter something like this would be kinda awkward (though
not impossible, I guess):
(transduce
list-fold vector-fold
(map *)
collect-list
lst vec)
And accepting the optional sentinel with this new API would also be
awkward to implement[^1]...
[^1]: This can be easily remied if the sentinel is given to the collect
instead of the transduce, in which case the current def of transduce is
a single case-lambda case instead of two:
(transduce fold (map *) (collect 'sentinel-value) data)
I was "forced" to procrastinate yesterday by this incredible force... ^^'
I've been thinking for the past couple of days about this and couldn't
come up with any way to make a generic "zip" work with transducers other
than (a) rewriting the basic algorithm of the egg (which is simple and I
prefer that way), or (b) introducing the concept of an "iterator" (which
is, I think, how Rust does it, and is equivalent to C++ Ranges (cf.
"Functional Programming in C++", Ivan Čukić)). The problem is that
type-fold does all the work from start to finish and can't be
"suspended" to look to the side for a second.
Because (a) goes against extending this egg, replacing its
implementation instead, and because it's a lot more work than (and not
as obvious as) (b), I went with (b).
An iterator is some object that keeps internal state about a collection
and how to access it, that can be used to incrementally[^0] traverse
this collection's elements in some (iterator-defined) order. Just like
streams![^1] So after a few hours hacking at it, it's as simple as this:
(transduce
iterator-fold
(map (cute apply * <>))
collect-list
(iterator-zip (list->iterator '(0 1 2 3 4))
(vector->iterator #(5 6 7 8 9))
(range->iterator 5)))
;=> (0 6 28 72 144)
By implementing iterator-fold and the type->iterator functions
everything works OOB with the transducers egg. With some small changes
to the egg[0] (especially [1]), it can be improved (IMO) to this:
(transduce
(zipped-iterator-fold list->iterator vector->iterator range->iterator)
(map (cute apply * <>))
(collect-list)
'(0 1 2 3 4) #(5 6 7 8 9) 5)
This small PoC can be found at [2] (just a bunch of SRFI 41
renames[^2]). The pros/cons of this approach, the way I see it, are:
A new iterator-fold is needed to use the transducers egg with iterators.
However, if you don't want/need iterators, you don't have to implement
type->iterator for your data type(s), just use type-fold and there's no
performance penalty (IIRC the main selling point of one of the
generators SRFI was performance compared with streams?). OTOH if you do
want/need iterators, you have to implement type->iterator too (I say
"too" but one doesn't strictly need both type-fold and type->iterator).
Nevertheless, from my understanding, using transducers on streams should
still be better performance-wise than composing stream-map/filter/...
[^0]: it can be started/stopped at will
[^1]: I also realized why using lists as the intermediate sequence type
is not such a big problem in Haskell and other lazy-by-default
languages: they're actually streams!
[^2]: I also experimented with a hand-written stream-like type. Maybe
it's possible to do better than streams but I dropped it for now.
[0]: https://git.sr.ht/~siiky/chicken-transducers/log/multiple-iterables
[1]:
https://git.sr.ht/~siiky/chicken-transducers/commit/68f9d6d3faaf80e1b57c7bda5dec888b34c670dd
[2]:
https://git.sr.ht/~siiky/experiments/tree/main/item/iterators/transducers-example.scm
PS: great work on the docs, Jeremy, they look very comprehensive!
siiky
- Re: New egg: CHICKEN Transducers, (continued)
- Re: New egg: CHICKEN Transducers, Mario Domenech Goulart, 2023/01/05
- Re: New egg: CHICKEN Transducers, Peter Bex, 2023/01/05
- Re: New egg: CHICKEN Transducers, Chris Brannon, 2023/01/05
- Re: New egg: CHICKEN Transducers, siiky, 2023/01/05
- Re: New egg: CHICKEN Transducers, Jeremy Steward, 2023/01/05
- Re: New egg: CHICKEN Transducers, Moritz Heidkamp, 2023/01/06
- Re: New egg: CHICKEN Transducers, siiky, 2023/01/06
- Re: New egg: CHICKEN Transducers, siiky, 2023/01/06
- Re: New egg: CHICKEN Transducers,
siiky <=
- Re: New egg: CHICKEN Transducers, Jeremy Steward, 2023/01/10
Re: New egg: CHICKEN Transducers, Jeremy Steward, 2023/01/05
Re: New egg: CHICKEN Transducers, siiky, 2023/01/05
Re: New egg: CHICKEN Transducers, Walter Lewis, 2023/01/05
Re: New egg: CHICKEN Transducers, Tomas Hlavaty, 2023/01/11