TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Defunctionalize the Continuation

236 pointsby Darmanialmost 6 years ago

13 comments

Smaug123almost 6 years ago
Defunctionalisation is a beautifully powerful technique. I&#x27;ve found it fits really neatly with the initial algebra pattern of data processing as repeated conversion of a &quot;description&quot; structure into more useful &quot;implementation&quot; structures.<p>In particular, my most recent project at work consisted of a system that takes a description of a computation from the user and successively performs optimisation passes on the description until we get a description of something that could run really efficiently, and then evaluating that efficient description into an actual computation that you really can run. If the successively-more-optimised descriptions are all defunctionalised to the greatest possible extent (in effect, deferring any concrete implementation details for as long as possible), you have much broader scope to optimise during later passes (since all the information &quot;remains visible&quot;, not hidden away in function calls).<p>Moreover, this approach is extremely testable: initial algebras are built to be re-interpreted, so you can write reference evaluators for them; while defunctionalisation gives you a way of checking output without needing to run any pesky programs.
评论 #20445418 未加载
0815testalmost 6 years ago
Kudos for providing a nicely-formatted transcript of this talk and not forcing us to watch a video. Learning about defunctionalization (and lambda lifting, which is closely related) was how I first managed to understand what this &quot;first-class functions&quot; language feature&#x2F;pattern was all about, and why it could be useful. It&#x27;s something that should be generally taught as part of any introduction to functional programming.
JackFralmost 6 years ago
Reminded me of <a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Immanentize_the_eschaton" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Immanentize_the_eschaton</a>
评论 #20447559 未加载
caternalmost 6 years ago
Note that you don&#x27;t have to defunctionalize to be serializable or perform other manipulations. Tagless final style extensible-interpreter techniques allows direct-style programs to be serialized and manipulated.
评论 #20445625 未加载
评论 #20446083 未加载
agbellalmost 6 years ago
Jimmy&#x27;s transcripts are great. I have been reading through his blog in preparation for a podcast interview and at first, I was a bit skeptical that a transcript could replace a talk but now I find I am liking the format.
ufoalmost 6 years ago
Over the years there have been countless times when I had to convert an easy to understand recursive program into a messy state machine or a heap of callbacks, for one reason or the other.<p>I always did these conversions in an ad-hoc fashion but this approach based on CPS + defunctionalization is definitely much clearer and easier on the brain!
mechrophilealmost 6 years ago
I&#x27;m having trouble working through the recursion -&gt; iteration process with functions that return a value. For instance, what if instead of printing the tree, we were summing the tree, as in a fibonacci sequence?<p>recursive:<p><pre><code> def fib(n): n = min(n, 0) if n &gt; 1: return fib(n-1) + fib(n-2) else: return n </code></pre> CPS:<p><pre><code> def fib(n, kont): n = min(n, 0) if n &gt; 1: return fib(n - 1, lambda x: x + fib(n - 2, kont)) else: return n </code></pre> but then I get stuck at defunctionalizing. I can&#x27;t figure out where the logic of combining values from the reduction step should go, or how to properly structure the continuation data structure.<p><pre><code> # BROKEN -- where do I combine the values? def fib(n, kont): n = min(n, 0) if n &gt; 1: return fib(n-1, {&quot;val&quot;: n, &quot;next&quot;: kont}) else: return kapply(kont, n) def kapply(kont, n): if kont: return fib(kont[&quot;val&quot;] - 2, kont[&quot;next&quot;]) return n</code></pre>
peconnalmost 6 years ago
This sounds really interesting, but I&#x27;m getting a bit confused trying to apply it to a simpler problem. Say I start with this recursive function to filter a list:<p><pre><code> def my_filter_recursive(l, f): if l: x, *xs = l if f(x): return [x] + my_filter_recursive(xs, f) else: return my_filter_recursive(xs, f) else: return [] </code></pre> In Continuation Passing Style it becomes:<p><pre><code> def my_filter_cps(l, f, kont): if l: x, *xs = l if f(x): my_filter_cps(xs, f, lambda y: kont([x] + y)) else: my_filter_cps(xs, f, lambda y: kont(y)) else: kont([]) </code></pre> Then I think with defunctionalisation it becomes:<p><pre><code> def my_filter_defun(l, f, kont): if l: x, *xs = l if f(x): my_filter_defun(xs, f, KontAdd(x, kont)) else: my_filter_defun(xs, f, KontSkip(kont)) else: kont.apply([]) class KontAdd: def __init__(self, var, kont): self.var = var self.kont = kont def apply(self, acc): self.kont.apply([self.var] + acc) class KontSkip: def __init__(self, kont): self.kont = kont def apply(self, acc): self.kont.apply(acc) class KontPrint: def apply(self, acc): print(acc) </code></pre> Is that right? It seems that we&#x27;ve basically just moved the recursion from one place to another.
评论 #20451160 未加载
评论 #20451094 未加载
divs1210almost 6 years ago
Very nice! I wrote a library (not long ago) for stackless recursion in Clojure, which uses core.async and the go macro to automatically turn recursive calls into defunctionalized continuations - no (structural) refactoring required! [1]<p>It&#x27;s not as fast as a plain iterative version would be, though, and the article gave me some ideas to experiment with.<p>[1] <a href="https:&#x2F;&#x2F;github.com&#x2F;divs1210&#x2F;xodarap&#x2F;" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;divs1210&#x2F;xodarap&#x2F;</a>
newenalmost 6 years ago
This is a very nice technique. I tried it for a couple of algorithms and while the author said that it a pretty mechanical to go from a recursive function to an iterative one, I think the non-mechanical work required to go from recursive to the CPS style is about the same as the work required to go directly from recursive to iterative. At least that was my experience.
peter_l_downsalmost 6 years ago
James is a fantastic person and an excellent teacher. Jimmy, if you&#x27;re reading the comments, hello and thank you!
andonisusalmost 6 years ago
If the old hacker news server in this example were to crash, wouldn&#x27;t that mean they lost the context of their continuation)? Wouldn&#x27;t this mean it is better to use the discrete data as the continuation (which they achieved by realizing all the continuations in code)?
renoxalmost 6 years ago
Thanks, I learned something new today.