diff options
author | EmacsConf <emacsconf-org@gnu.org> | 2024-12-08 16:43:19 -0500 |
---|---|---|
committer | EmacsConf <emacsconf-org@gnu.org> | 2024-12-08 16:43:19 -0500 |
commit | 8c171541ee0e6e1ba39015648cd00d1bcfc5da34 (patch) | |
tree | f7a0a6d57fe86f7a299930f5a883aaed94b713f3 /2024/info/transducers-after.md | |
parent | 92851ebc504a8dea7983972c42879b1e2b378d96 (diff) | |
download | emacsconf-wiki-8c171541ee0e6e1ba39015648cd00d1bcfc5da34.tar.xz emacsconf-wiki-8c171541ee0e6e1ba39015648cd00d1bcfc5da34.zip |
update
Diffstat (limited to '2024/info/transducers-after.md')
-rw-r--r-- | 2024/info/transducers-after.md | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/2024/info/transducers-after.md b/2024/info/transducers-after.md index cfd894ee..8888c875 100644 --- a/2024/info/transducers-after.md +++ b/2024/info/transducers-after.md @@ -1,6 +1,422 @@ <!-- Automatically generated by emacsconf-publish-after-page --> +<a name="transducers-mainVideo-transcript"></a> +# Transcript + + +[[!template new="1" text="""Intro""" start="00:00:00.000" video="mainVideo-transducers" id="subtitle"]] + +[[!template text="""Hi everyone, this is EmacsConf 2024. I'm Colin, and today""" start="00:00:00.000" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""I'll be talking about transducers.""" start="00:00:10.800" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""After introducing them, I'll share a bit of history about""" start="00:00:17.320" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""transducers and the problems that they solve, some basics""" start="00:00:21.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""about how we can use them, how they work, like how they're""" start="00:00:25.360" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""implemented, some demonstrations of how we can actually""" start="00:00:28.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""use them in the wild, and then some other discussions about""" start="00:00:32.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""issues that they have.""" start="00:00:36.960" video="mainVideo-transducers" id="subtitle"]] + +[[!template new="1" text="""What are transducers?""" start="00:00:41.520" video="mainVideo-transducers" id="subtitle"]] + +[[!template text="""Okay, let's get right in. What are transducers?""" start="00:00:41.520" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Transducers are a way to do streaming iteration with a""" start="00:00:46.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""modern API.""" start="00:00:49.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Who are transducers for, and thereby, who is""" start="00:00:55.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""this talk for? Well, it's for people who want to do streamed""" start="00:01:00.360" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""data processing in Emacs. It's for people who perhaps""" start="00:01:05.600" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""aren't satisfied with the existing APIs, for example, the""" start="00:01:10.520" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""seq API, or some other common libraries that provide""" start="00:01:14.200" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""similar functionality. Maybe you're not a fan of the loop""" start="00:01:19.360" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""macro. Some people find it difficult to understand. Or""" start="00:01:23.720" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""maybe you've done a bunch of Clojure before, and you'd like""" start="00:01:29.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""more aspects of Clojure in your Emacs Lisp. Or maybe you're""" start="00:01:32.720" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""just interested in transducers in general, because the""" start="00:01:36.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""pattern has now been ported to multiple different Lisps.""" start="00:01:40.240" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""So I'm Colin. I'm fosskers on everything online, and I do""" start="00:01:48.840" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""mainly back-end programming work and a lot of open source""" start="00:01:55.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""software. I wrote Haskell for a long time, both as a hobbyist""" start="00:01:58.520" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""and professionally. Since the COVID years, I've been""" start="00:02:05.160" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""writing Rust, both open source and professionally. But now""" start="00:02:09.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""I find that in my spare time, I'm mostly writing Common Lisp.""" start="00:02:13.440" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Some things I learned from my years of Haskell was that a lot""" start="00:02:19.720" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""of programming is just altering the shape of data. You know,""" start="00:02:22.720" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""sometimes we work through our algorithm line by line. We're""" start="00:02:27.520" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""trying to just tell the computer exactly what to do. But if we""" start="00:02:31.360" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""step back, a lot of the time we're just getting in data of some""" start="00:02:36.240" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""shape, changing it, and then passing it along. A lot of""" start="00:02:39.640" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""these patterns are common, identified""" start="00:02:44.120" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""decades ago. For instance, we have some collection, and we""" start="00:02:49.280" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""want to transform every element of that collection and then""" start="00:02:53.640" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""pass it on. Or maybe we're trying to filter out bad elements""" start="00:02:57.000" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""in that collection. Or maybe we're looking for a specific""" start="00:03:01.200" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""element in that collection. Yes, you could write all that""" start="00:03:04.800" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""with for loops, but these kind of common patterns were""" start="00:03:07.760" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""identified and given names decades ago. So why not use them?""" start="00:03:11.840" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""They say that there are two major problems in computer""" start="00:03:18.560" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""science, one being cache validation and the other being""" start="00:03:21.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""naming things.""" start="00:03:25.760" video="mainVideo-transducers" id="subtitle"]] + +[[!template new="1" text="""Common issues""" start="00:03:27.590" video="mainVideo-transducers" id="subtitle"]] + +[[!template text="""I've identified five other problems that""" start="00:03:27.590" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""come up when we're trying to deal with collections of data,""" start="00:03:29.800" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""or big streams of data. One is that if we were trying to""" start="00:03:33.200" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""load a file all into memory all at once and process the whole""" start="00:03:40.600" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""thing, sometimes we can have memory problems. You've""" start="00:03:45.280" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""probably seen out-of-memory errors or such things.""" start="00:03:48.280" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""A second issue that comes up is that if we were looking at a""" start="00:03:55.000" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""giant for loop, in particular a nested for loop or such""" start="00:03:58.200" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""things, it can be hard to tell just by looking at the code what""" start="00:04:01.800" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""it's trying to do, what it intends. If we don't go character""" start="00:04:06.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""by character or line by line, it can be hard to understand it.""" start="00:04:11.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Furthermore, and this is particularly an issue with Emacs""" start="00:04:16.440" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Lisp, is that if one call, for instance, to seq-map, then""" start="00:04:20.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""piped into seq-filter, for instance, will have an""" start="00:04:26.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""intermediate allocation, the map will take the source""" start="00:04:29.320" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""container, allocate a new one, and then the filter will""" start="00:04:33.600" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""operate over the second one. This is wasteful.""" start="00:04:37.640" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Furthermore, it can often be difficult to abort a stream.""" start="00:04:40.320" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""For instance, if we were filtering through our collection,""" start="00:04:48.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""but we knew we only wanted to go halfway, for instance, for""" start="00:04:53.200" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""some reason, we have no way to stop it halfway through. We""" start="00:04:57.320" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""just have to process the whole thing, even if we know we don't""" start="00:05:01.760" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""need to. Another issue is that for languages that have""" start="00:05:05.480" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""traits, or in Haskell they're called type classes, if you""" start="00:05:11.920" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""are defining what it means to map over something, you often""" start="00:05:18.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""have to redefine that for every kind of container or thing""" start="00:05:22.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""that you're iterating over. Wouldn't it be nice if we could""" start="00:05:27.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""define things like map just once and then reuse them""" start="00:05:31.240" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""everywhere? Now, transducers solve all five of these,""" start="00:05:34.720" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""without the addition of new language features, and with""" start="00:05:39.840" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""little more than plain old function composition.""" start="00:05:44.040" video="mainVideo-transducers" id="subtitle"]] + +[[!template new="1" text="""Transducers""" start="00:05:47.280" video="mainVideo-transducers" id="subtitle"]] + +[[!template text="""If this is your first time hearing of transducers, yeah,""" start="00:05:47.280" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""no problem. They were originally invented in Clojure by""" start="00:05:53.120" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Rich Hickey, and this is a quote from him. He thinks""" start="00:05:57.440" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""transducers are a fundamental primitive that decouple""" start="00:06:01.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""critical logic from list or sequence processing, and if he""" start="00:06:05.440" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""had to do Clojure all over, he'd put them at the bottom, at the""" start="00:06:10.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""very bottom of all the fundamental primitives. Now, that's""" start="00:06:14.000" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Rich speaking quite highly of them. And I think he has a point""" start="00:06:19.280" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""here.""" start="00:06:24.600" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""They were invented originally in Clojure. In more""" start="00:06:25.160" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""recent years, they were brought over to Scheme""" start="00:06:32.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""via SRFI 171. That's where I found them""" start="00:06:34.773" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""when I was learning the Guile language.""" start="00:06:38.775" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""In the process of submitting a patch, I realized""" start="00:06:41.522" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""that there were other things to be improved. So I ported the""" start="00:06:43.920" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""pattern to Common Lisp, then Fennel, and then more""" start="00:06:48.200" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""recently, Emacs Lisp. The Common Lisp and Emacs Lisp APIs""" start="00:06:51.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""are identical. And the Fennel one is not identical, but""" start="00:06:56.640" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""fairly similar. Overall, everywhere you find""" start="00:07:01.200" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""transducers, they should basically be fairly uniform.""" start="00:07:05.800" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""When I originally made the Common Lisp variant first, I""" start="00:07:10.280" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""sampled the APIs from a number of different languages and""" start="00:07:15.760" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""came up with what I believed to be a representative sample of""" start="00:07:18.800" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""what most people would want out of such a library. I gave""" start="00:07:23.440" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""functions their common modern names. For instance, map""" start="00:07:27.960" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""is map and filter is filter and so on.""" start="00:07:32.440" video="mainVideo-transducers" id="subtitle"]] + +[[!template new="1" text="""Using transducers""" start="00:07:35.280" video="mainVideo-transducers" id="subtitle"]] + +[[!template text="""What does the usage of transducers look like? Well,""" start="00:07:35.280" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""these examples will all be the Emacs Lisp variant, but the""" start="00:07:42.600" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Common Lisp will look basically exactly the same, minus""" start="00:07:48.960" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""this little t- prefix.""" start="00:07:52.360" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Running transducers requires three things. It requires a""" start="00:07:54.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""source. This could be an obvious thing like a list or a""" start="00:08:00.920" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""vector, but it could be other things like a file, or in Emacs""" start="00:08:06.440" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""list in particular, a buffer.""" start="00:08:11.480" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""A reducer is a function. It's something like""" start="00:08:16.349" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""the + operator or the \* operator,""" start="00:08:20.113" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""or certain constructors of various containers.""" start="00:08:22.640" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""It takes values and collates them into some final version.""" start="00:08:26.786" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Now, finally, we have what we're calling here""" start="00:08:32.126" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""a transducer chain. This could be one transducer function""" start="00:08:33.947" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""or it could be multiple composed together. These are the""" start="00:08:37.568" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""functions that actually take data and transform them""" start="00:08:43.480" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""somehow. For instance, this. We have a list of three""" start="00:08:47.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""elements. We want to reduce it into a vector. How we are""" start="00:08:55.280" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""going to transform the elements along the way: we are doing""" start="00:09:04.200" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""plus one to each of them. If this syntax is new to you, just""" start="00:09:07.520" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""know that this #' just means that this thing that""" start="00:09:13.360" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""comes after it is the name of the function. In Common Lisp and""" start="00:09:18.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Emacs Lisp, this is necessary, but for Clojure and Scheme,""" start="00:09:22.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""it is not. So we can see here that just this example is not much""" start="00:09:26.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""different than any other normal map call you might see made,""" start="00:09:32.720" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""but if nothing else, it's a handy way to convert a list to a""" start="00:09:36.120" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""vector or anything else. There are many, many reducers""" start="00:09:40.240" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""available and many different forms that we can""" start="00:09:45.000" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""collate the final value into.""" start="00:09:48.240" video="mainVideo-transducers" id="subtitle"]] + +[[!template new="1" text="""A more involved example with comp""" start="00:09:52.625" video="mainVideo-transducers" id="subtitle"]] + +[[!template text="""Let's see a more involved example.""" start="00:09:52.625" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Okay, now we've got some more meat here.""" start="00:09:55.087" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Here we can see usage of the comp function""" start="00:09:58.050" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""and a custom source, ints.""" start="00:10:01.773" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Ints is an infinite generator of integer values. That's not""" start="00:10:05.256" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""like a list or a file. It will generate infinitely.""" start="00:10:11.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Comp is letting us compose multiple transducer functions""" start="00:10:14.784" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""together. Notice that this is the opposite order of what""" start="00:10:19.440" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""we'd usually be used to from a function like comp. The order""" start="00:10:23.760" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""here is top to bottom, basically, so that the map goes first,""" start="00:10:28.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""then the filter, and then the take. So effectively is what""" start="00:10:32.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""we're doing is taking all the integers that exist,""" start="00:10:37.840" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""positive, adding one to them, filtering out only the even""" start="00:10:40.920" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""ones, but then just taking 10. Cons here is a function that""" start="00:10:45.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""just produces the ending result as a list. So what happens""" start="00:10:50.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""here specifically is how we are avoiding intermediate""" start="00:10:57.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""allocations. First, the number 0 will come through.""" start="00:11:00.480" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""It will be pulled out of this source internally by transduce.""" start="00:11:04.239" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""It will make its way into the map. The map will add it. Then it""" start="00:11:07.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""will immediately go into this filter step. So it's not like""" start="00:11:10.920" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""all the maps occur, and then all the filters occur. We do""" start="00:11:15.800" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""everything for each element. So the 0 comes in, now it's 1.""" start="00:11:19.120" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""The filter would occur. Well, it's going to fail that""" start="00:11:24.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""because it's not even, so it will just bail there. Now we'll""" start="00:11:27.560" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""go to the next one. Now 1 will come, it will become 2, then""" start="00:11:31.120" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""it will be saved by this evenp call, and then the take will""" start="00:11:35.240" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""capture it, because we only want 10 values here. You can""" start="00:11:39.120" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""see 2, 4, 6, 8, and so on is the result that we""" start="00:11:42.600" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""expect. So let's play around a little bit.""" start="00:11:45.240" video="mainVideo-transducers" id="subtitle"]] + +[[!template new="1" text="""In Emacs""" start="00:11:49.333" video="mainVideo-transducers" id="subtitle"]] + +[[!template text="""Let's jump into Emacs and see what we can do.""" start="00:11:49.333" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Alright, you should see my Emacs screen here.""" start="00:11:53.337" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""These are the actual notes for the actual""" start="00:11:58.501" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""presentation done in Org Mode. I'll boost that up in size for""" start="00:12:04.360" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""a little bit. That should be more than big enough for you.""" start="00:12:08.960" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Just by changing the reducer, we can change the result.""" start="00:12:12.640" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Okay, now it's a vector. Well, what else can we do to it? Well,""" start="00:12:17.720" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""let's just add up the results. Maybe we just want to count the""" start="00:12:21.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""results. Oh, indeed, there were 10. What if we want to find""" start="00:12:25.960" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""the average of the results? What if we want to find the median""" start="00:12:30.920" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""of the results? And so on. Here's some more interesting""" start="00:12:36.960" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""things that we could do. We could add different steps. So""" start="00:12:40.960" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""here we have all the integers. Let's add, hmm, okay, we'll""" start="00:12:45.840" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""keep that. We're going to add t-enumerate. What enumerate does""" start="00:12:51.240" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""is for each item that comes through, it is""" start="00:12:57.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""going to add a sort of index to it and make it a pair. In this""" start="00:13:00.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""case, it's going to be equal to what came in here. Well, we can""" start="00:13:06.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""change it. If we start this at 1, now it will be different.""" start="00:13:08.720" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""1 will be paired with 0, and then 2 would be paired""" start="00:13:12.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""with 1, and so on. We'll accept that the even call will change""" start="00:13:15.520" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""that a little bit. Why we're doing this is because we want""" start="00:13:19.560" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""to form a hash table. Let's move that down to 3, maybe""" start="00:13:24.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""we'll get a better result. What do we see? Okay, here now the""" start="00:13:27.280" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""result is a hash table. What are its values? Well, 0 seems""" start="00:13:31.440" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""to have... The key of 0 seems to be paired with 2, the key of""" start="00:13:37.360" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""1 seems to be paired with 4,""" start="00:13:40.480" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""and 2 seems to be paired with 6.""" start="00:13:42.910" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Maybe let's jazz that up even a little bit more.""" start="00:13:47.412" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""We're going to start from a string""" start="00:13:51.294" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""and we'll call it hello.""" start="00:13:52.974" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""That's not going to work anymore""" start="00:13:57.944" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""and neither is that, but what we could do is""" start="00:13:59.565" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""we could say t-map #'string.""" start="00:14:02.586" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""I believe we'll do that.""" start="00:14:05.499" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Let's see if that works. It did. So that's""" start="00:14:08.628" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""going to convert a character into a string.""" start="00:14:08.960" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Let's just go two""" start="00:14:13.590" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""just to make it a little easier. Now you can see that we've""" start="00:14:14.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""constructed a hash table here. The key of 0 is mapped to the""" start="00:14:18.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""string of h and 1 is mapped to e. Now, I really like having""" start="00:14:21.920" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""this reducer in particular.""" start="00:14:27.080" video="mainVideo-transducers" id="subtitle"]] + +[[!template new="1" text="""Hash tables""" start="00:14:29.469" video="mainVideo-transducers" id="subtitle"]] + +[[!template text="""Know that hash tables are""" start="00:14:29.469" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""also legal sources. I find that both in Emacs Lisp and in""" start="00:14:30.640" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Common Lisp, dealing with hash tables--like creating them""" start="00:14:34.200" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""and altering them--can be a bit of a pain. Having them""" start="00:14:37.120" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""immediately available like this with transducers is very""" start="00:14:41.600" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""handy, I find. We can work with something that wasn't a hash""" start="00:14:45.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""table. We can construct it in a way that makes it amenable to""" start="00:14:49.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""that, and then reduce it down into a hash table, and here you""" start="00:14:53.280" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""go. Very handy.""" start="00:14:56.200" video="mainVideo-transducers" id="subtitle"]] + +[[!template new="1" text="""Clarity""" start="00:14:58.040" video="mainVideo-transducers" id="subtitle"]] + +[[!template text="""One last point is that you can see very clearly what""" start="00:14:58.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""this is attempting to do, as opposed to, say, a for loop. It's""" start="00:15:06.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""very clear what that step is doing, and then you can see what""" start="00:15:10.480" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""that is doing, and you know that the result is going to be two.""" start="00:15:12.720" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Each line is kind of its own declarative step, and it should""" start="00:15:15.120" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""be clear, just by staring at this, basically what you're""" start="00:15:18.560" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""going to get out. This is one main difference from other""" start="00:15:22.160" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""languages that have things--say, for instance, Rust's""" start="00:15:25.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""iterator API--is the difference between the transducers""" start="00:15:29.600" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""and the reducers. If we go up here, for example, the""" start="00:15:35.440" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""difference between the transducers and the reducers and""" start="00:15:41.640" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""the sources is not explicitly laid out, whereas with""" start="00:15:44.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""transducers, it is. You have to be aware of how these things""" start="00:15:48.120" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""are different. I think that that helps clarity.""" start="00:15:53.120" video="mainVideo-transducers" id="subtitle"]] + +[[!template new="1" text="""How do transducers work?""" start="00:15:55.800" video="mainVideo-transducers" id="subtitle"]] + +[[!template text="""Moving on. How do transducers work? Well,""" start="00:15:55.800" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""we want to go see the README.""" start="00:16:02.000" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""So, what we're going to do is""" start="00:16:09.858" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""we're going to go to here.""" start="00:16:11.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""You should still be able to see this.""" start="00:16:19.103" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""This is the CL example, actually.""" start="00:16:21.960" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Let's go to transducers.el.""" start="00:16:28.584" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Their APIs and READMEs are the same,""" start="00:16:32.280" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""but just for the sake of it, we will go see""" start="00:16:37.745" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""how this looks on the Emacs side,""" start="00:16:39.920" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""just so that nothing is a surprise.""" start="00:16:45.727" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""But recall that the APIs are essentially the same""" start="00:16:48.047" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""between the two. If you go to this section, writing your""" start="00:16:50.240" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""own primitives, you can read about how transducers are""" start="00:16:53.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""actually formed, whether or not you want to write them""" start="00:16:56.840" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""yourself or not. We can see here t-map. We accept the""" start="00:17:01.000" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""function that you want to operate with. Then you've got""" start="00:17:06.800" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""this extra little lambda here that's coming in, and it's""" start="00:17:10.240" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""receiving a thing that is named reducer. Now, while here""" start="00:17:13.320" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""we're calling it reducer, it's actually the chain of all the""" start="00:17:17.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""composed functions together. It's all those main""" start="00:17:20.440" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""transducer steps. Finally, it's the reducer all""" start="00:17:25.160" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""composed together with normal function composition.""" start="00:17:28.480" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""That will matter very soon. Now here's the actual meat.""" start="00:17:31.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""We can see the accumulative result that's coming in with the""" start="00:17:35.878" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""current element. Now we need to operate on this.""" start="00:17:40.520" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Were it normally mapped, we would see us""" start="00:17:45.740" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""applying the F to the input.""" start="00:17:47.841" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""But here, you can see us applying the F to the input and then""" start="00:17:49.920" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""continuing on. So us calling the rest of the composed chain""" start="00:17:53.520" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""here is the effect of, in the previous slide, moving to the""" start="00:17:58.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""next step. We could ignore this line for now.""" start="00:18:03.160" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""If you're curious, please read the README in detail.""" start="00:18:07.157" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Now, what about reducers?""" start="00:18:13.820" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""What do those look like? Well, let's just scroll""" start="00:18:15.580" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""down here. Recall that a reducer is a function that's""" start="00:18:18.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""consuming a stream, right? Zoom that up for you a little bit.""" start="00:18:22.440" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Now, in the case of count, recall that this is how it's""" start="00:18:26.960" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""working, how we saw a moment ago. So clearly this list of five""" start="00:18:33.920" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""elements only has five things in it. Well, a reducer by""" start="00:18:37.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""structure is a function of two, one, or zero arguments. So we""" start="00:18:42.200" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""can see here in the case of two, this is the normal iterative""" start="00:18:47.600" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""case. We don't care about the input for count, we just care""" start="00:18:50.640" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""about the current accumulated count that we're doing, and""" start="00:18:54.520" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""we add one to it, and that's it. This then goes back to""" start="00:18:58.560" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""the loop and the whole process starts again with the next""" start="00:19:02.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""element. In this kind of done case, this is used internal to""" start="00:19:06.360" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""that sort of the supervising function transduce. It's just""" start="00:19:10.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""confirming the final result. Sometimes some""" start="00:19:16.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""post-processing is necessary here, but in the case of""" start="00:19:19.640" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""count, as it is so simple, that is not necessary. And now""" start="00:19:21.840" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""here's the base case. This is also used within that""" start="00:19:26.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""supervising transduce function at the very top. Well, if""" start="00:19:29.360" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""you're counting, you have to start from somewhere, right?""" start="00:19:34.320" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""In this case, well, what you're starting with is zero.""" start="00:19:36.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""In the case of cons, you'd be starting with an empty list.""" start="00:19:37.350" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""In the case of vector, you'd be starting""" start="00:19:40.252" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""with an empty vector and so on.""" start="00:19:44.435" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Once again, if you are more curious, please take a look at""" start="00:19:54.000" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""the README.""" start="00:19:56.800" video="mainVideo-transducers" id="subtitle"]] + +[[!template new="1" text="""Transducers in the wild - CSV""" start="00:20:00.520" video="mainVideo-transducers" id="subtitle"]] + +[[!template text="""Okay, transducers in the wild. Well, let's go take a look at""" start="00:20:00.520" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""processing some CSV data.""" start="00:20:06.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""We're going to open up a new Emacs Lisp bracket here. So I have""" start="00:20:07.640" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""a file. And in this file, let's just go look at C-x b right""" start="00:20:21.320" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""there, you will see that we've got some bank transaction""" start="00:20:28.840" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""information. It's got these transactions from a whole""" start="00:20:34.840" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""bunch of different people into different accounts,""" start="00:20:37.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""whether it's money coming in, money going out, and then a""" start="00:20:40.200" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""basic description. How's your Latin? But for this little""" start="00:20:43.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""test, what we want to do is we want to find Bob's final bank""" start="00:20:47.840" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""balance. Let's get on to it. First of all, let's""" start="00:20:53.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""just confirm, let's do some basic stuff.""" start="00:20:59.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""with-current-buffer, find-file-noselect.""" start="00:21:04.445" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""What's the name of that file?""" start="00:21:10.845" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""This is pre-organized, so you""" start="00:21:15.543" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""will just see it right here.""" start="00:21:17.440" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""t-transduce and t-comp. We don't know what we're going to comp""" start="00:21:20.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""yet. Actually, I'll just pass to show you. And then we will""" start="00:21:27.000" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""see, let's just do a little t-count just to confirm. What's""" start="00:21:33.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""our source? Well, our source is a buffer, t-buffer-read.""" start="00:21:37.000" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""And note that because we're using with-current-buffer,""" start="00:21:45.113" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""if we go like this, if we go current-buffer, this will just work. So""" start="00:21:50.154" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""now let's... Well, that was odd. I should have done it like""" start="00:21:55.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""that. There we go. So now we should make that a little smaller""" start="00:21:59.920" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""so you can see what it is. Now if we hit RET, we should get the""" start="00:22:02.160" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""right result. Okay, so there are 50,001 lines in this file,""" start="00:22:04.800" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""but the one extra one is the name of the headers, right?""" start="00:22:09.560" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""We want to process this file in more detail. So how can we do""" start="00:22:13.517" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""that? Well, let's start by just automatically""" start="00:22:18.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""interpreting the results as CSV. If we do that, okay, well""" start="00:22:22.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""now we only have 50,000 entries as we expected, right?""" start="00:22:28.800" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Because it's going to pull out the header line. If we now say""" start="00:22:31.560" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""we want to just filter out, you know, We only want Bob, right?""" start="00:22:36.760" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""So if... gethash, it was in the row of name. Each line here is""" start="00:22:42.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""made into, at least by default, is made into a hash map. So if""" start="00:22:53.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""we go like this, we should see that. Okay, so 12,000 of these""" start="00:22:57.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""lines or thereabout belong to Bob.""" start="00:23:02.760" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Let's just move that over a little bit. Actually, I suppose we don't even""" start="00:23:05.640" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""need that anymore. I'll just keep that full size for you.""" start="00:23:13.840" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Okay, so all right, there's about 12,000 results for Bob of""" start="00:23:17.800" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""the 50,000. What's next? Well, we want to confirm,""" start="00:23:24.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""we want to pull out everything,""" start="00:23:32.480" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""all of the in and the out entries.""" start="00:23:40.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Thank you. So, string to number, because we know that""" start="00:23:43.080" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""everything came in as strings. Unfortunately, the from-csv""" start="00:23:56.280" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""doesn't try to be smart at all, it's just pulling everything""" start="00:24:01.240" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""in as string values. If you want actual things to be""" start="00:24:03.800" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""numbers or whatever, that is up to you to do the parsing""" start="00:24:09.480" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""yourself. Okay, so we have those two values now. We know""" start="00:24:13.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""that we saw from the data just a moment ago that you're only""" start="00:24:20.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""going to have a value in one column or the other. It's either""" start="00:24:23.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""going to be 0 in the empty one, or you're going to have some""" start="00:24:27.000" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""number in the other. So we know that we can just naively add""" start="00:24:29.120" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""them. If it was in, it would always be positive. So we'll just""" start="00:24:32.160" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""add that. But in the negative case, we want to just make it""" start="00:24:35.480" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""negative really briefly before we add them all together.""" start="00:24:41.520" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""let's now just prove to ourselves that we are sane here. What""" start="00:24:45.280" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""we're going to do is we're going to quickly go say take""" start="00:24:50.520" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""5 just to convince ourselves, and we'll go cons, and let's""" start="00:24:52.480" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""see if we get kind of results that make sense. Okay, these""" start="00:24:57.040" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""sort of make sense. It looks like you know Bob's got some big""" start="00:24:59.840" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""expenses here. If we take say 15, does it look any better?""" start="00:25:02.800" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Okay, looks like he had a payday. All right, good job Bob.""" start="00:25:07.680" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Let's get back in there. Now we only really care about""" start="00:25:10.320" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""adding the final result, right? So there we go. Add that all""" start="00:25:15.440" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""together and we'll see what we get in a moment. Okay, wow,""" start="00:25:20.120" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Bob's rich. Okay, so it looks like in his 12,000""" start="00:25:24.560" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""transaction, Bob has an overall net worth of $8.5 million.""" start="00:25:27.520" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Looking pretty good.""" start="00:25:32.280" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""So here's an example of how you can, particularly in Emacs""" start="00:25:34.440" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Lisp, how you can very easily just get a file, consider it the""" start="00:25:39.000" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""current buffer, and then just do whatever you want to it.""" start="00:25:42.960" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Note that there is sort of first-class support for both CSV""" start="00:25:45.880" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""and JSON, and then you have, and both of those bring in their""" start="00:25:50.360" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""values as hash maps, and then you're just free to do whatever""" start="00:25:54.360" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""you want and process them, potentially both writing them""" start="00:25:57.720" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""back out as CSV or JSON once again.""" start="00:26:00.440" video="mainVideo-transducers" id="subtitle"]] + +[[!template new="1" text="""Issues and next steps""" start="00:26:03.240" video="mainVideo-transducers" id="subtitle"]] + +[[!template text="""Some issues with transducers that can come up is""" start="00:26:03.240" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""that one, a zip operator is missing, but I'm working on it.""" start="00:26:10.720" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""Two is that performance, particularly in Emacs Lisp, isn't""" start="00:26:14.920" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""that great. It could be due to the sort of nested lambda calls""" start="00:26:19.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""that have to occur internally, but the common Lisp""" start="00:26:24.120" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""implementation is quite good. and there's yet no support""" start="00:26:27.760" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""for parallelism. You can imagine that a lot of those steps""" start="00:26:32.240" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""you could potentially perform in parallel depending on the""" start="00:26:35.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""platform, but research has not yet gotten that far. Okay,""" start="00:26:38.560" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""that's all. Thank you very much. If you have any questions,""" start="00:26:44.400" video="mainVideo-transducers" id="subtitle"]] +[[!template text="""please contact me.""" start="00:26:47.640" video="mainVideo-transducers" id="subtitle"]] + + + +Captioner: sachac + Questions or comments? Please e-mail [emacsconf-org-private@gnu.org](mailto:emacsconf-org-private@gnu.org?subject=Comment%20for%20EmacsConf%202023%20transducers%3A%20Transducers%3A%20finally%2C%20ergonomic%20data%20processing%20for%20Emacs%21) |