<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Eli Bendersky's website - Functional programming</title><link href="https://eli.thegreenplace.net/" rel="alternate"/><link href="https://eli.thegreenplace.net/feeds/functional-programming.atom.xml" rel="self"/><id>https://eli.thegreenplace.net/</id><updated>2026-11-02T23:32:44.981329-08:00</updated><entry><title>The power of single-method interfaces in Go</title><link href="https://eli.thegreenplace.net/2023/the-power-of-single-method-interfaces-in-go/" rel="alternate"/><published>2023-03-17T06:23:00-07:00</published><updated>2026-11-02T23:32:44.981329-08:00</updated><author><name>Eli Bendersky</name></author><id>tag:eli.thegreenplace.net,2023-03-17:/2023/the-power-of-single-method-interfaces-in-go/</id><summary type="html">&lt;p&gt;The other day I was pondering on the prevalence of single-method interfaces
(SMI) in Go, and what makes them so effective and useful. SMIs have proven to
be a very successful software modeling tool for Go programmers, and you find
them all over Go code-bases.&lt;/p&gt;
&lt;p&gt;I tried to think about …&lt;/p&gt;</summary><content type="html">&lt;p&gt;The other day I was pondering on the prevalence of single-method interfaces
(SMI) in Go, and what makes them so effective and useful. SMIs have proven to
be a very successful software modeling tool for Go programmers, and you find
them all over Go code-bases.&lt;/p&gt;
&lt;p&gt;I tried to think about the fundamentals, which brought me to some of the
earliest roots of our trade: functional programming and higher-order functions
(HOF).
I discussed some examples of &lt;a class="reference external" href="https://eli.thegreenplace.net/2023/higher-order-functions-in-go/"&gt;applying higher-order functions in Go recently&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This post will describe how SMIs are a more general and powerful technique than
HOFs. It makes the following claims:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;SMIs can do whatever HOFs can&lt;/li&gt;
&lt;li&gt;SMIs are more general&lt;/li&gt;
&lt;li&gt;SMIs are somewhat more verbose for simple cases&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To begin, let's use the same example as before.&lt;/p&gt;
&lt;div class="section" id="the-tree-search-example-using-smis"&gt;
&lt;h2&gt;The tree search example using SMIs&lt;/h2&gt;
&lt;p&gt;The &lt;a class="reference external" href="https://eli.thegreenplace.net/2023/higher-order-functions-in-go/"&gt;previous post&lt;/a&gt; demonstrated
a Go solution using higher-order functions for the tree search problem &lt;a class="reference external" href="https://eli.thegreenplace.net/2023/building-abstractions-using-higher-order-functions/"&gt;described earlier&lt;/a&gt;.
I encourage you to review the earlier posts to get the most out of this one.&lt;/p&gt;
&lt;p&gt;Let's now see how the same task can be accomplished using SMIs instead of HOFs;
the &lt;a class="reference external" href="https://github.com/eliben/code-for-blog/tree/main/2023/go-intefaces-functions"&gt;full code is on GitHub&lt;/a&gt;.
Starting with the types:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;

&lt;span class="c1"&gt;// GoalDetector is an interface that wraps a single IsGoal method. IsGoal&lt;/span&gt;
&lt;span class="c1"&gt;// takes a state and determines whether it&amp;#39;s a goal state.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GoalDetector&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;IsGoal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// SuccessorGenerator is an interface that wraps a single Successors method.&lt;/span&gt;
&lt;span class="c1"&gt;// Successors returns the successors of a state.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SuccessorGenerator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Successors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Combiner is an interface that wraps a single Combine method. Combine&lt;/span&gt;
&lt;span class="c1"&gt;// determines the search strategy by combining successors of the current state&lt;/span&gt;
&lt;span class="c1"&gt;// with all the other states into a single list of states.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Combiner&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;others&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These are the equivalent SMIs to the &lt;tt class="docutils literal"&gt;GoalP&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;Successors&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;Combiner&lt;/tt&gt;
function types we've seen before; the names are slightly modified to be more
suitable for interfaces and their methods.&lt;/p&gt;
&lt;p&gt;The tree search itself - using these interfaces - is almost identical to the
previous version:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;treeSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;states&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GoalDetector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SuccessorGenerator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;combiner&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Combiner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;states&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;states&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IsGoal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;treeSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;combiner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Successors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;states&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;combiner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To implement BFS, we reuse &lt;tt class="docutils literal"&gt;prependOthers&lt;/tt&gt; from the previous post (it remains
identical):&lt;/p&gt;
&lt;p&gt;And again, &lt;tt class="docutils literal"&gt;appendOthers&lt;/tt&gt; and implementing DFS:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bfsTreeSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GoalDetector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SuccessorGenerator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;treeSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CombineFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prependOthers&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What is &lt;tt class="docutils literal"&gt;CombineFunc&lt;/tt&gt;? Since &lt;tt class="docutils literal"&gt;prependOthers&lt;/tt&gt; is a function - while
&lt;tt class="docutils literal"&gt;treeSearch&lt;/tt&gt; takes interfaces - we need an &lt;em&gt;adapter&lt;/em&gt; type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CombineFunc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CombineFunc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;others&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;others&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you have a bit of Go experience already, this may seem familiar. It's exactly
the same breed of adapter as &lt;a class="reference external" href="https://pkg.go.dev/net/http#HandlerFunc"&gt;http.HandlerFunc&lt;/a&gt;.
Unfortunately, at this time a Go function cannot be assigned to a SMI with a
compatible method signature, so these adapters are required (see the Appendix
for more details).&lt;/p&gt;
&lt;p&gt;The rest of the code is also very similar, with an adapter thrown in here and
there. Feel free to &lt;a class="reference external" href="https://github.com/eliben/code-for-blog/tree/main/2023/go-intefaces-functions"&gt;read the rest of it&lt;/a&gt; and
compare to &lt;a class="reference external" href="https://github.com/eliben/code-for-blog/tree/main/2023/go-higher-order-functions"&gt;the HOF version&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since a SMI wraps a method, it can do whatever a function type can do. We can
pass SMIs to functions; we can return SMIs from functions. There are &lt;em&gt;tons&lt;/em&gt; of
examples of this across the Go standard library, and in almost any non-trivial
Go project.&lt;/p&gt;
&lt;p&gt;So is this it? Are SMIs just a cumbersome variation on higher-order functions?
No, not at all. The code sample used in this blog post is unfair to SMIs because
it was originally written and designed for HOFs. What's important to take
from here is that it's also possible to accomplish the same goal with SMIs.
This is the basis of the power of SMIs - they can serve the same role as
higher-order functions; but they have additional features that HOFs lack.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="smis-are-more-general-than-function-types"&gt;
&lt;h2&gt;SMIs are more general than function types&lt;/h2&gt;
&lt;p&gt;In examining the generality of SMIs, the topic of &lt;em&gt;state&lt;/em&gt; immediately comes up.
I will only discuss it briefly, because it's a known &lt;em&gt;red herring&lt;/em&gt;. One could
claim that SMIs are more general because they can represent objects with
built-in state (for example, a struct value where the struct type implements a
SMI). Functions can represent state too, however, by means of closures. In fact,
our sample code clearly shows this in functions like &lt;tt class="docutils literal"&gt;stateIs&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;costDiffTarget&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;The real reasons for why SMIs are more general are:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;SMIs naturally extend to multi-method interfaces&lt;/li&gt;
&lt;li&gt;Go values can implement more than one interface&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let's discuss these in detail.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Single&lt;/em&gt;-method interfaces; it's in the name! Interfaces with a single method
to implement, like the ubiquitous &lt;tt class="docutils literal"&gt;io.Reader&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Reader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But just as easily, Go has multi-method interfaces, like &lt;tt class="docutils literal"&gt;io.ReadWriter&lt;/tt&gt; &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ReadWriter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are many other useful multi-method interfaces in the standard library:
&lt;a class="reference external" href="https://pkg.go.dev/net/http#ResponseWriter"&gt;net/http.ResponseWriter&lt;/a&gt;,
&lt;a class="reference external" href="https://pkg.go.dev/context#Context"&gt;context.Context&lt;/a&gt;, &lt;a class="reference external" href="https://pkg.go.dev/io/fs#File"&gt;fs.File&lt;/a&gt; and so on. While the extension from a SMI
to a multi-method interface in Go is trivial, this is difficult and unnatural to
achieve with function types &lt;a class="footnote-reference" href="#footnote-2" id="footnote-reference-2"&gt;[2]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next, a single Go value can implement multiple interfaces. Implicit interface
implementation is one of the banner features of Go - a type does not have to
declare that it implements an interface; it does so implicitly if it has the
right method. There are many good examples of this in the Go standard library;
for example the &lt;tt class="docutils literal"&gt;encoding.BinaryMarshaler&lt;/tt&gt; interface:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BinaryMarshaler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;MarshalBinary&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And the &lt;tt class="docutils literal"&gt;encoding/json.Marshaler&lt;/tt&gt; interface:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Marshaler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;MarshalJSON&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A type like &lt;a class="reference external" href="https://pkg.go.dev/time#Time"&gt;time.Time&lt;/a&gt; implements both, and
can thus be encoded into a binary format and JSON.&lt;/p&gt;
&lt;p&gt;Another interesting example is the &lt;tt class="docutils literal"&gt;fmt.Stringer&lt;/tt&gt; interface:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Stringer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Many Go types implement this interface along with other interfaces
(&lt;tt class="docutils literal"&gt;time.Time&lt;/tt&gt; does too, of course); overall it's not uncommon to see large,
sophisticated types implementing 5 or more interfaces.&lt;/p&gt;
&lt;p&gt;Both of the capabilities presented here (multi-method interfaces and a single
value implementing multiple SMIs) are very hard to achieve with function types
and first-class functions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="conclusion"&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The goal of this post was to discuss the prevalence and power of single-method
interfaces (SMIs) in Go. It started by showing how SMIs can do whatever
higher-order functions (HOFs) can do (albeit somewhat more verbosely, given that
the task at hand was tailored for HOFs in previous posts).&lt;/p&gt;
&lt;p&gt;Then, we discussed additional capabilities of SMIs that make them unique and
aren't achievable with HOFs in a reasonable way.&lt;/p&gt;
&lt;p&gt;In functional languages, HOFs are heavily used to implement sophisticated and
useful abstractions. In Go, you can use HOFs as well but most Go code prefers
to use SMIs for this purpose, because of the added generality.&lt;/p&gt;
&lt;p&gt;So which approach should you use? The best tool for the job at hand, of course.
While SMIs are more general and powerful, they are also more verbose for the
simple cases. When all you need is a function - use a function! Otherwise,
interfaces are a powerful and versatile tool Go programmers employ for many
tasks.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="appendix-adapter-types-for-converting-functions-to-smis"&gt;
&lt;h2&gt;Appendix: adapter types for converting functions to SMIs&lt;/h2&gt;
&lt;p&gt;There is some work in the Go developer community to reduce the
toil required to convert between a plain function and a SMI. Here's &lt;a class="reference external" href="https://github.com/golang/go/issues/47487"&gt;one
proposal&lt;/a&gt; that was discussed
fairly recently and is currently at an advanced stage - waiting for a prototype
before decision. In our example with the &lt;tt class="docutils literal"&gt;Combiner&lt;/tt&gt; interface, this would
enable writing:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;Combiner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prependOthers&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Combine&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Instead of having to define the &lt;tt class="docutils literal"&gt;CombineFunc&lt;/tt&gt; adapter. While it's still not as
terse as passing &lt;tt class="docutils literal"&gt;prependOthers&lt;/tt&gt; where a &lt;tt class="docutils literal"&gt;Combiner&lt;/tt&gt; is expected, it's an
appreciable reduction in boilerplate. For the more ambitious notion of
&lt;em&gt;assignability&lt;/em&gt;, there's an &lt;a class="reference external" href="https://github.com/golang/go/issues/21670"&gt;older, farther-reaching proposal&lt;/a&gt;.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://pkg.go.dev/io#ReadWriter"&gt;This interface&lt;/a&gt; is actually
defined using &lt;a class="reference external" href="https://eli.thegreenplace.net/2020/embedding-in-go-part-2-interfaces-in-interfaces/"&gt;interface embedding&lt;/a&gt;,
but the effect is the same.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;It's theoretically possible using closures that return a
&lt;em&gt;dispatch function&lt;/em&gt; accepting multiple commands and invoking a different
operation for each; this technique is described in
&lt;a class="reference external" href="https://eli.thegreenplace.net/2007/09/25/sicp-section-311"&gt;chapter 3 of SICP&lt;/a&gt;.
It's so unlike the typical use of HOFs that I consider it just a (cool)
implementation trick, showing how interfaces are implemented using
simpler building blocks.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="misc"/><category term="Go"/><category term="Functional programming"/></entry><entry><title>Higher-order functions in Go</title><link href="https://eli.thegreenplace.net/2023/higher-order-functions-in-go/" rel="alternate"/><published>2023-03-04T19:37:00-08:00</published><updated>2026-11-02T23:32:44.981329-08:00</updated><author><name>Eli Bendersky</name></author><id>tag:eli.thegreenplace.net,2023-03-04:/2023/higher-order-functions-in-go/</id><summary type="html">&lt;p&gt;&lt;a class="reference external" href="https://eli.thegreenplace.net/2023/building-abstractions-using-higher-order-functions/"&gt;A few weeks ago I wrote&lt;/a&gt;
about the powerful abstractions that higher-order functions enable, using
Clojure code as an example.&lt;/p&gt;
&lt;p&gt;In this post I want to show equivalent code using a modern statically-typed
language - Go. Please make sure to review the previous post first, since it
describes the problem statement …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a class="reference external" href="https://eli.thegreenplace.net/2023/building-abstractions-using-higher-order-functions/"&gt;A few weeks ago I wrote&lt;/a&gt;
about the powerful abstractions that higher-order functions enable, using
Clojure code as an example.&lt;/p&gt;
&lt;p&gt;In this post I want to show equivalent code using a modern statically-typed
language - Go. Please make sure to review the previous post first, since it
describes the problem statement in detail.&lt;/p&gt;
&lt;div class="section" id="go-and-higher-order-functions"&gt;
&lt;h2&gt;Go and higher-order functions&lt;/h2&gt;
&lt;p&gt;While Go has many of the building blocks required to support functional
programming, at this time it's not considered a mainstream programming paradigm
for the language.&lt;/p&gt;
&lt;p&gt;That said, my favorite part of functional programming is definitely supported
and widely used in Go - higher-order functions. Go makes it simple to pass
functions as arguments to other functions, and return functions from functions.
Moreover, it has first-class support for &lt;em&gt;closures&lt;/em&gt;, which makes the
function-based design process much more powerful. This also meshes well with
Go's automatic memory management, mostly eliminating worries about values going
in and out of scope in closures.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-tree-search-example-in-go"&gt;
&lt;h2&gt;The tree search example in Go&lt;/h2&gt;
&lt;p&gt;Let's reproduce the tree search example from &lt;a class="reference external" href="https://eli.thegreenplace.net/2023/building-abstractions-using-higher-order-functions/"&gt;the previous post&lt;/a&gt;
in Go; &lt;a class="reference external" href="https://github.com/eliben/code-for-blog/tree/main/2023/go-higher-order-functions"&gt;the full code is here&lt;/a&gt;.
The first task we run into is &lt;em&gt;types&lt;/em&gt;; since Go is statically typed, we have to
define our types explicitly:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;

&lt;span class="c1"&gt;// GoalP takes a state and determines whether it&amp;#39;s a goal state.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GoalP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;

&lt;span class="c1"&gt;// Successors returns the successors of a state.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;

&lt;span class="c1"&gt;// Combiner determines the search strategy by combining successors of the&lt;/span&gt;
&lt;span class="c1"&gt;// current state with all the other states into a single list of states.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Combiner&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;others&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And this is the tree search function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// treeSearch returns the state if it&amp;#39;s found in the tree; returns -1 if such a&lt;/span&gt;
&lt;span class="c1"&gt;// state wasn&amp;#39;t found.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;treeSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;states&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;goalp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GoalP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Successors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;combiner&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Combiner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;states&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;states&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;goalp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;treeSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;combiner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;states&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;goalp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;combiner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While it's somewhat more verbose, its logic follows the Clojure code very
closely. Now we're ready to define BFS search:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// prependOthers is a Combiner function that prepends others to succ.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prependOthers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;others&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;others&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bfsTreeSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;goalp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GoalP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Successors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;treeSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;goalp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prependOthers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To see how this function is invoked, we'll define a general infinite binary
tree &lt;tt class="docutils literal"&gt;Successors&lt;/tt&gt; function, and another for finite binary trees:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;binaryTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;finiteBinaryTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;binaryTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;finiteBinaryTree&lt;/tt&gt; is a nice example of higher-order functions in Go. It
takes a value and returns a function that adheres to the &lt;tt class="docutils literal"&gt;Successors&lt;/tt&gt;
function type; in fact, it returns a new function created at runtime - a
&lt;em&gt;closure&lt;/em&gt; that closes over the value &lt;tt class="docutils literal"&gt;n&lt;/tt&gt;. Moreover, the function it returns
also makes use of higher-order functions in its body, because it invokes
&lt;tt class="docutils literal"&gt;filter&lt;/tt&gt; with a filtering function as a parameter. &lt;tt class="docutils literal"&gt;filter&lt;/tt&gt; is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// filter filters a slice based on a predicate, returning a new slice whose&lt;/span&gt;
&lt;span class="c1"&gt;// elements fulfill the predicate.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pred&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pred&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To call &lt;tt class="docutils literal"&gt;bfsTreeSearch&lt;/tt&gt; we need to figure out another function parameter - the
goal function (&lt;tt class="docutils literal"&gt;GoalP&lt;/tt&gt;). We can use a higher-order function for this as well:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// stateIs returns a GoalP that checks a state for equality with n.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stateIs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GoalP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we're ready to invoke &lt;tt class="docutils literal"&gt;bfsTreeSearch&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;treeLimit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;finiteBinaryTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;treeLimit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nx"&gt;bfsFound&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bfsTreeSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stateIs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note how similar this code is to the Clojure variant; Go supports all the same
higher-order function constructs, letting us build powerful abstractions using
them. The static types make the code somewhat more verbose, but this has
advantages as well!&lt;/p&gt;
&lt;p&gt;Imagine that you don't remember in which order &lt;tt class="docutils literal"&gt;successors&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt;
should be passed to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;tree-search&lt;/span&gt;&lt;/tt&gt; in the Clojure code; if you pass them in
the wrong order, the code will build fine and you will get an error at runtime
about invoking some function with the wrong number of arguments. This is lucky,
because these two functions just happen to have different arities; in less lucky
cases the error could come much later or be more obscure; or, there could be
no error at all and the result could be incorrect.&lt;/p&gt;
&lt;p&gt;In Go if you pass &lt;tt class="docutils literal"&gt;succ&lt;/tt&gt; after &lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt;, you'll just get a compile-time
type error.&lt;/p&gt;
&lt;p&gt;Types have a benefit for documentation and code-reading purposes as well, but
I don't want to turn this post into a static vs. dynamic typing debate. Let's
look at some of the more advanced tree searching functions instead.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="even-more-higher-order-functions-in-best-first-search"&gt;
&lt;h2&gt;Even more higher-order functions in best-first search&lt;/h2&gt;
&lt;p&gt;A slightly more advanced example involves a &amp;quot;best&amp;quot;-first search; a greedy
heuristic that sorts all state candidates by some criteria and pursues them in a
priority order. We can still reuse our &lt;tt class="docutils literal"&gt;treeSearch&lt;/tt&gt; function for it, but have
to devise an appropriate &lt;tt class="docutils literal"&gt;Combiner&lt;/tt&gt;. Let's start with a new function type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CostFunc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Given a state &lt;tt class="docutils literal"&gt;s&lt;/tt&gt;, a cost function returns the integer cost. Now we can write
our combiner that sorts a list of states based on a cost function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sorter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CostFunc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Combiner&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;others&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;others&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another nice example of higher-order functions in action. &lt;tt class="docutils literal"&gt;sorter&lt;/tt&gt; can be seen
as a &lt;em&gt;generator&lt;/em&gt; of &lt;tt class="docutils literal"&gt;Combiner&lt;/tt&gt; functions; it can generate a new &lt;tt class="docutils literal"&gt;Combiner&lt;/tt&gt;
given a cost function. At this point we have all we need to implement
&lt;tt class="docutils literal"&gt;bestCostTreeSearch&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bestCostTreeSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;goalp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GoalP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Successors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CostFunc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;treeSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;States&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;goalp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;succ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sorter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The only thing remaining is figuring out what cost function we'd like to pass
to the search. A simple one just measures the linear distance of a given state
from our goal state:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// costDiffTarget creates a cost function that uses numerical distance from `n`&lt;/span&gt;
&lt;span class="c1"&gt;// as the cost.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;costDiffTarget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CostFunc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;delta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;delta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;delta&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;delta&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Given a target state, &lt;tt class="docutils literal"&gt;costDiffTarget&lt;/tt&gt; generates a function that can serve
as the cost function for search. We can now invoke &lt;tt class="docutils literal"&gt;bestCostTreeSearch&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;treeLimit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;finiteBinaryTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;treeLimit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nx"&gt;bestFound&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bestCostTreeSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stateIs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;costDiffTarget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="conclusion"&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Go has complete and powerful support for higher-order functions - including
proper closures. While the syntax - mostly due to static typing - is somewhat
more verbose than in other languages, it's more of an issue for code samples
than it is for large code bases.&lt;/p&gt;
&lt;p&gt;The verbosity issue is also in discussion by the Go developers, with proposals
like &lt;a class="reference external" href="https://github.com/golang/go/issues/21498"&gt;Lightweight anonymous function syntax&lt;/a&gt; promising terser syntax and more
powerful type inference. So there's hope for further improvement in this area.&lt;/p&gt;
&lt;p&gt;Go itself uses higher-order functions extensively in the standard library;
some examples include &lt;a class="reference external" href="https://pkg.go.dev/bufio#Scanner.Split"&gt;bufio.Scanner.Split&lt;/a&gt;,
a whole array of &lt;tt class="docutils literal"&gt;*Func&lt;/tt&gt; functions in the &lt;tt class="docutils literal"&gt;strings&lt;/tt&gt; package (e.g. &lt;a class="reference external" href="https://pkg.go.dev/strings#FieldsFunc"&gt;FieldsFunc&lt;/a&gt;),
the &lt;a class="reference external" href="https://pkg.go.dev/sort#Slice"&gt;sort.Slice&lt;/a&gt; function used in this post
and of course &lt;a class="reference external" href="https://pkg.go.dev/net/http#ServeMux.HandleFunc"&gt;net/http.ServeMux.HandleFunc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Examples of returning functions also abound; the best known is probably the
convention of the &lt;tt class="docutils literal"&gt;context&lt;/tt&gt; package to return &lt;tt class="docutils literal"&gt;context.CancelFunc&lt;/tt&gt; for
context cancellation. But there are other examples, like &lt;a class="reference external" href="https://pkg.go.dev/net/http#ProxyURL"&gt;net/http.ProxyUrl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Additional resources, if you found this post interesting:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;A followup on &lt;a class="reference external" href="https://eli.thegreenplace.net/2023/the-power-of-single-method-interfaces-in-go/"&gt;The power of single-method interfaces in Go&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://eli.thegreenplace.net/2022/the-y-combinator-in-go-with-generics/"&gt;The Y combinator in Go with generics&lt;/a&gt;
for a more mind-bending example of Go's higher-order functions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="misc"/><category term="Go"/><category term="Functional programming"/></entry><entry><title>Building abstractions using higher-order functions</title><link href="https://eli.thegreenplace.net/2023/building-abstractions-using-higher-order-functions/" rel="alternate"/><published>2023-02-04T05:40:00-08:00</published><updated>2026-11-02T23:32:44.981329-08:00</updated><author><name>Eli Bendersky</name></author><id>tag:eli.thegreenplace.net,2023-02-04:/2023/building-abstractions-using-higher-order-functions/</id><summary type="html">&lt;p&gt;A &lt;em&gt;higher-order function&lt;/em&gt; is a function that takes other functions as arguments,
or returns a function as its result. Higher-order functions are an exceptionally
powerful software design tool because they can easily create new abstractions
and are composable. In this post I will present a case study - a set of …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A &lt;em&gt;higher-order function&lt;/em&gt; is a function that takes other functions as arguments,
or returns a function as its result. Higher-order functions are an exceptionally
powerful software design tool because they can easily create new abstractions
and are composable. In this post I will present a case study - a set of
functions that defines an interesting problem domain. By reading and
understanding this code, hopefully anyone can appreciate the power and beauty of
higher-order functions and how they enable constructing powerful abstractions
from basic building blocks.&lt;/p&gt;
&lt;p&gt;One of my &lt;a class="reference external" href="https://eli.thegreenplace.net/2005/06/12/lessons-from-paip"&gt;all-time favorite&lt;/a&gt; programming
books is Peter Norvig's &lt;a class="reference external" href="https://norvig.github.io/paip-lisp/#/"&gt;PAIP&lt;/a&gt; . In
section &lt;em&gt;6.4 - A set of Searching Tools&lt;/em&gt;, it presents some code for defining
different variants of tree searching that I've always found very elegant.&lt;/p&gt;
&lt;p&gt;Here's a quick reimplementation of the main idea in Clojure (see &lt;a class="reference external" href="https://github.com/eliben/paip-in-clojure/tree/master/src/paip/6_tools"&gt;this
repository&lt;/a&gt; for
the full, runnable code); I'm using Clojure since it's a modern Lisp that &lt;a class="reference external" href="https://eli.thegreenplace.net/2017/clojure-the-perfect-language-to-expand-your-brain/"&gt;I
enjoy learning and using&lt;/a&gt;
from time to time.&lt;/p&gt;
&lt;p&gt;First, some prerequisites. As is often the case in dynamically-typed Lisp,
entities can be described in a very abstract way. The code presented here
searches trees, but there is no tree data structure per-se; it's defined using
functions. Specifically, there's a notion of a &amp;quot;state&amp;quot; (tree node) and a way
to get from a given state to its children states (successors); a function maps
between the two.&lt;/p&gt;
&lt;p&gt;In our case let's have integers as states; then, an infinite binary tree can
be defined using the following successor function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;binary-tree&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;A successors function representing a binary tree.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Given a state (a number), it returns its children as a list. Simplistically, in
this tree, node N has the children 2N and 2N+1.&lt;/p&gt;
&lt;p&gt;Here are the first few layers of such a tree:&lt;/p&gt;
&lt;object class="align-center" data="https://eli.thegreenplace.net/images/2023/binary-tree-graph.svg" type="image/svg+xml"&gt;Binary tree with 15 nodes 1-15&lt;/object&gt;
&lt;p&gt;In one sense, the tree is infinite because &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;binary-tree&lt;/span&gt;&lt;/tt&gt; will happily return
the successors for any node we ask:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (binary-tree 9999)
(19998 19999)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But in another sense, &lt;em&gt;there is no tree&lt;/em&gt;. This is a beautiful implication
of using functions instead of concrete data - they easily enable &lt;em&gt;lazy
evaluation&lt;/em&gt;. We cannot materialize an infinite tree inside a
necessarily finite computer, but we can operate on it all the same because of
this abstraction. As far as the search algorithm is concerned, there exists an
abstract &lt;em&gt;state space&lt;/em&gt; and we tell it how to navigate and interpret it.&lt;/p&gt;
&lt;p&gt;Now we're ready to look at the generic search function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;tree-search&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Finds a state that satisfies goal?-fn; Starts with states, and searches&lt;/span&gt;
&lt;span class="s"&gt;  according to successors and combiner. If successful, returns the state;&lt;/span&gt;
&lt;span class="s"&gt;  otherwise returns nil.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;states&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;combiner&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cond &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;states&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;states&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;states&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="ss"&gt;:else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tree-search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;combiner&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;states&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                                     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;rest &lt;/span&gt;&lt;span class="nv"&gt;states&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nv"&gt;combiner&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let's dig in. The function accepts the following parameters:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;states&lt;/tt&gt;: a list of starting states for the search. When invoked by the
user, this list will typically have a single element; when &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;tree-search&lt;/span&gt;&lt;/tt&gt;
calls itself, this list is the states that it plans to explore next.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;goal?-fn&lt;/span&gt;&lt;/tt&gt;: a goal detection function. The search doesn't know anything
about states and what the goal of the search is, so this is parameterized
by a function. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;goal?-fn&lt;/span&gt;&lt;/tt&gt; is expected to return &lt;tt class="docutils literal"&gt;true&lt;/tt&gt; for a goal
state (the state we were searching for) and &lt;tt class="docutils literal"&gt;false&lt;/tt&gt; for all other states.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;successors&lt;/tt&gt;: the search function also doesn't know anything about what
kind of tree it's searching through; what are the children of a given state?
Is it searching a binary tree? A N-nary tree? Something more exotic? All of
this is parameterized via the &lt;tt class="docutils literal"&gt;successors&lt;/tt&gt; function provided by the user.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt;: finally, the search strategy can be parameterized as well.
There are many different kinds of searches possible - BFS, DFS and others.
&lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt; takes a list of successors for the current state the search is
looking at, as well as a list of all the other states the search still plans
to look at. It combines these into a single list &lt;em&gt;somehow&lt;/em&gt;, and thus guides
the order in which the search happens.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even before we see how this function is used, it's already apparent that this
is quite a powerful abstraction. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;tree-search&lt;/span&gt;&lt;/tt&gt; defines the essence of what
it means to &amp;quot;search a tree&amp;quot;, while being oblivious to what the tree contains,
how it's structured and even what order it should be searched in; all of this
is supplied by functions passed in as parameters.&lt;/p&gt;
&lt;p&gt;Let's see an example, doing a BFS search on our infinite binary tree. First,
we define a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;breadth-first-search&lt;/span&gt;&lt;/tt&gt; function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;breadth-first-search&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Search old states first until goal is reached.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tree-search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;prepend&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This function takes a start state (a single state, not a list), &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;goal?-fn&lt;/span&gt;&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;successors&lt;/tt&gt;, but it sets the &lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt; parameter to the &lt;tt class="docutils literal"&gt;prepend&lt;/tt&gt;
function, which is defined as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;prepend&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;concat &lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It defines the search strategy (BFS = first look at the rest of the states and
only then at successors of the current state), but still leaves the tree
structure and the notion of what a goal is to parameters. Let's see it in
action:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (breadth-first-search 1 #(= % 9) binary-tree)
9
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we pass the anonymous function literal &lt;tt class="docutils literal"&gt;#(= % 9)&lt;/tt&gt; as the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;goal?-fn&lt;/span&gt;&lt;/tt&gt;
parameter. This function simply checks whether the state passed to it is the
number 9. We also pass &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;binary-tree&lt;/span&gt;&lt;/tt&gt; as the &lt;tt class="docutils literal"&gt;successors&lt;/tt&gt;, since we're going
to be searching in our infinite binary tree. BFS works layer by layer, so it
has no issue with that and finds the state quickly.&lt;/p&gt;
&lt;p&gt;We can turn on verbosity (refer to &lt;a class="reference external" href="https://github.com/eliben/paip-in-clojure/tree/master/src/paip/6_tools"&gt;the full code&lt;/a&gt; to
see how it works) to see what &lt;tt class="docutils literal"&gt;states&lt;/tt&gt; parameter &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;tree-search&lt;/span&gt;&lt;/tt&gt; gets called
with, observing the progression of the search:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (with-verbose (breadth-first-search 1 #(= % 9) binary-tree))
;; Search: (1)
;; Search: (2 3)
;; Search: (3 4 5)
;; Search: (4 5 6 7)
;; Search: (5 6 7 8 9)
;; Search: (6 7 8 9 10 11)
;; Search: (7 8 9 10 11 12 13)
;; Search: (8 9 10 11 12 13 14 15)
;; Search: (9 10 11 12 13 14 15 16 17)
9
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is the &lt;tt class="docutils literal"&gt;prepend&lt;/tt&gt; combiner in action; for example, after &lt;tt class="docutils literal"&gt;(3 4 5)&lt;/tt&gt;, the
combiner prepends &lt;tt class="docutils literal"&gt;(4 5)&lt;/tt&gt; to the successors of 3 (the list &lt;tt class="docutils literal"&gt;(6 7)&lt;/tt&gt;), getting
&lt;tt class="docutils literal"&gt;(4 5 6 7)&lt;/tt&gt; as the set of states to search through. Overall, observing the
first element in the &lt;tt class="docutils literal"&gt;states&lt;/tt&gt; list through the printed lines, it's clear this
is classical BFS where the tree is visited in &amp;quot;layers&amp;quot;.&lt;/p&gt;
&lt;p&gt;Implementing DFS using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;tree-search&lt;/span&gt;&lt;/tt&gt; is similarly easy:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;depth-first-search&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Search new states first until goal is reached.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tree-search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The only difference from BFS is the &lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt; parameter - here we use
&lt;tt class="docutils literal"&gt;concat&lt;/tt&gt; since we want to examine the successors of the first state &lt;em&gt;before&lt;/em&gt;
we examine the other states on the list. If we run &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;depth-first-search&lt;/span&gt;&lt;/tt&gt; on our
infinite binary tree we'll get a stack overflow (unless we're looking for a
state that's on the left-most path), so let's create a safer tree first. This
function can serve as a &lt;tt class="docutils literal"&gt;successors&lt;/tt&gt; to define a &amp;quot;finite&amp;quot; binary tree, with
the given maximal state value:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;finite-binary-tree&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Returns a successor function that generates a binary tree with n nodes.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;lt;= &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;binary-tree&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note the clever use of higher-order functions here. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;finite-binary-tree&lt;/span&gt;&lt;/tt&gt; is
not a &lt;tt class="docutils literal"&gt;successors&lt;/tt&gt; function itself - rather it's a generator of such
functions; given a value, it creates a new function that acts as &lt;tt class="docutils literal"&gt;successors&lt;/tt&gt;
but limits the the states' value to &lt;tt class="docutils literal"&gt;n&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;For example, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;(finite-binary-tree&lt;/span&gt; 15)&lt;/tt&gt; will create a &lt;tt class="docutils literal"&gt;successors&lt;/tt&gt; function
that represents exactly the binary tree on the diagram above; if we ask it about
successors of states on the fourth layer, it will say there are none:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (def f15 (finite-binary-tree 15))
#&amp;#39;paip.core/f15
paip.core=&amp;gt; (f15 4)
(8 9)
paip.core=&amp;gt; (f15 8)
()
paip.core=&amp;gt; (f15 7)
(14 15)
paip.core=&amp;gt; (f15 15)
()
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As another test, let's try to look for a state that's not in our finite tree.
Out infinite tree theoretically has &lt;em&gt;all&lt;/em&gt; the states:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (breadth-first-search 1 #(= % 33) binary-tree)
33
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But not the finite tree:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (breadth-first-search 1 #(= % 33) (finite-binary-tree 15))
nil
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With our finite tree, we are ready to use &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;depth-first-search&lt;/span&gt;&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (with-verbose (depth-first-search 1 #(= % 9) (finite-binary-tree 15)))
;; Search: (1)
;; Search: (2 3)
;; Search: (4 5 3)
;; Search: (8 9 5 3)
;; Search: (9 5 3)
9
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note the search order; when &lt;tt class="docutils literal"&gt;(2 3)&lt;/tt&gt; is explored, 2's successors &lt;tt class="docutils literal"&gt;(4 5)&lt;/tt&gt; then
come &lt;em&gt;before&lt;/em&gt; 3 in the next call; this is the definition of DFS.&lt;/p&gt;
&lt;p&gt;We can implement more advanced search strategies using this infrastructure. For
example, suppose we have a heuristic that tells us which states to prioritize in
order to get to the goal faster (akin to A* search on graphs). We can define
a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;best-first-search&lt;/span&gt;&lt;/tt&gt; that sorts the states according to our heuristic and
tries the most promising states first (&amp;quot;best&amp;quot; as in &amp;quot;best looking among the
current candidates&amp;quot;, not as in &amp;quot;globally best&amp;quot;).&lt;/p&gt;
&lt;p&gt;First, let's define a couple of helper higher-order functions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;diff&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Given n, returns a function that computes the distance of its argument from n.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Math/abs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;- &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;sorter&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Returns a combiner function that sorts according to cost-fn.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;cost-fn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new &lt;/span&gt;&lt;span class="nv"&gt;old&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sort-by &lt;/span&gt;&lt;span class="nv"&gt;cost-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;concat &lt;/span&gt;&lt;span class="k"&gt;new &lt;/span&gt;&lt;span class="nv"&gt;old&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;diff&lt;/tt&gt; is a function generator like &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;finite-binary-tree&lt;/span&gt;&lt;/tt&gt;; it takes a target
number &lt;tt class="docutils literal"&gt;n&lt;/tt&gt; and returns a function that computes its parameter &lt;tt class="docutils literal"&gt;x&lt;/tt&gt;'s distance
from &lt;tt class="docutils literal"&gt;n&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;sorter&lt;/tt&gt; returns a function that serves as the &lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt; for our
search, based on a cost function. This is done by concatenating the two lists
(successors of first state and the rest of the states) first, and then sorting
them by the cost function. &lt;tt class="docutils literal"&gt;sorter&lt;/tt&gt; is a powerful example of modeling with
higher-order functions.&lt;/p&gt;
&lt;p&gt;With these building blocks in place, we can define &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;best-first-search&lt;/span&gt;&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;best-first-search&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Search lowest cost states first until goal is reached.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cost-fn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tree-search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sorter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cost-fn&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once again, this is just like the earlier BFS and DFS - only the strategy
(&lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt;) changes. Let's use it to find 9 again:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;paip.core=&amp;gt; (with-verbose (best-first-search 1 #(= % 9) (finite-binary-tree 15) (diff 9)))
;; Search: (1)
;; Search: (3 2)
;; Search: (7 6 2)
;; Search: (6 14 15 2)
;; Search: (12 13 14 15 2)
;; Search: (13 14 15 2)
;; Search: (14 15 2)
;; Search: (15 2)
;; Search: (2)
;; Search: (5 4)
;; Search: (10 11 4)
;; Search: (11 4)
;; Search: (4)
;; Search: (9 8)
9
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While it finds the state eventually, we discover that our heuristic is not a
great match for this problem, as it sends the search astray. The goal of this
post is to demonstrate the power of higher-order functions in building modular
code, not to discover an optimal heuristic for searching in binary trees, though
:-)&lt;/p&gt;
&lt;p&gt;One last search variant before we're ready to wrap up. As we've seen with the
infinite tree, sometimes the search space is too large and we have to compromise
on which states to look at and which to ignore. This technique works
particularly well if the target is not some single value that we must find, but
rather we want to get a &amp;quot;good enough&amp;quot; result in a sea of bad options. We can
use a technique called &lt;em&gt;beam search&lt;/em&gt;; think of a beam of light a flashlight
produces in a very dark room; we can see what the beam points at, but not much
else.&lt;/p&gt;
&lt;p&gt;Beam search is somewhat similar to our &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;best-first-search&lt;/span&gt;&lt;/tt&gt;, but after combining
and sorting the list of states to explore, it only keeps the first N, where
N is given by the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;beam-width&lt;/span&gt;&lt;/tt&gt; parameter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;beam-search&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Search highest scoring states first until goal is reached, but never consider&lt;/span&gt;
&lt;span class="s"&gt;  more than beam-width states at a time.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cost-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;beam-width&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tree-search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list &lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;goal?-fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;successors&lt;/span&gt;
&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;old&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;new&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;sorted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nf"&gt;sorter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cost-fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;old&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;take &lt;/span&gt;&lt;span class="nv"&gt;beam-width&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once again, higher-order functions at play: as its &lt;tt class="docutils literal"&gt;combiner&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;beam-search&lt;/span&gt;&lt;/tt&gt;
creates an anonymous function that sorts the list based on &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;cost-fn&lt;/span&gt;&lt;/tt&gt;, and then
keeps only the first &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;beam-width&lt;/span&gt;&lt;/tt&gt; states on that list.&lt;/p&gt;
&lt;p&gt;Exercise: Try to run it - what beam width do you need to set in order to
successfully find 9 using our cost heuristic? How can this be improved?&lt;/p&gt;
&lt;div class="section" id="conclusion"&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This post attempts a code-walkthrough approach to demonstrating the power of
higher-order functions. I always found this particular example from PAIP very
elegant; a particularly powerful insight is the distilled difference between
DFS and BFS. While most programmers intuitively understand the difference and
could write down the pseudo-code for both search strategies, modeling the
problem with higher-order functions lets us really get to the essence of the
difference - &lt;tt class="docutils literal"&gt;concat&lt;/tt&gt; vs. &lt;tt class="docutils literal"&gt;prepend&lt;/tt&gt; as the combiner step.&lt;/p&gt;
&lt;p&gt;See also: &lt;a class="reference external" href="https://eli.thegreenplace.net/2023/higher-order-functions-in-go/"&gt;this code sample ported to Go&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
</content><category term="misc"/><category term="Clojure"/><category term="Lisp"/><category term="Programming"/><category term="Functional programming"/></entry><entry><title>The Y combinator in Go with generics</title><link href="https://eli.thegreenplace.net/2022/the-y-combinator-in-go-with-generics/" rel="alternate"/><published>2022-06-11T07:55:00-07:00</published><updated>2026-11-02T23:32:44.981329-08:00</updated><author><name>Eli Bendersky</name></author><id>tag:eli.thegreenplace.net,2022-06-11:/2022/the-y-combinator-in-go-with-generics/</id><summary type="html">&lt;p&gt;A few years ago I've &lt;a class="reference external" href="https://eli.thegreenplace.net/2016/some-notes-on-the-y-combinator/"&gt;written in some detail&lt;/a&gt; about
the Y combinator, including implementations in Clojure and Python.&lt;/p&gt;
&lt;p&gt;This short post is showing how to implement the Y combinator in Go using
generics; in general, static typing makes the Y combinator somewhat less
appealing, but I figured that generics …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A few years ago I've &lt;a class="reference external" href="https://eli.thegreenplace.net/2016/some-notes-on-the-y-combinator/"&gt;written in some detail&lt;/a&gt; about
the Y combinator, including implementations in Clojure and Python.&lt;/p&gt;
&lt;p&gt;This short post is showing how to implement the Y combinator in Go using
generics; in general, static typing makes the Y combinator somewhat less
appealing, but I figured that generics will at least allow the implementation to
be reasonably reusable. Not that this is useful in any real-world scenario, of
course :-)&lt;/p&gt;
&lt;p&gt;I won't explain how the Y combinator itself
works here (please refer to the &lt;a class="reference external" href="https://eli.thegreenplace.net/2016/some-notes-on-the-y-combinator/"&gt;previous post&lt;/a&gt; for
that), only the Go specifics. The full, runnable code for this post is available
&lt;a class="reference external" href="https://github.com/eliben/code-for-blog/tree/main/2022/ycombinator-go"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TagFunc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CombinatorFunc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CombinatorFunc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The Y combinator's definition uses several kinds of anonymous functions. In Go,
we need those to have explicit types. &lt;tt class="docutils literal"&gt;Func&lt;/tt&gt; is the underlying computation
function - it's what the function type would be if we'd used normal recursion.
It's parameterized with two generic types: &lt;tt class="docutils literal"&gt;T&lt;/tt&gt; for its parameter type and
&lt;tt class="docutils literal"&gt;U&lt;/tt&gt; for its return type.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;FuncTag&lt;/tt&gt; is the type of the functions users should write now.
&lt;tt class="docutils literal"&gt;CombinatorFunc&lt;/tt&gt; is only used in the definition of the Y combinator itself:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TagFunc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CombinatorFunc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CombinatorFunc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here's how to use it. To define a recursive factorial-computing function that
does not refer to itself by name, the user has to create a &amp;quot;tag&amp;quot; function that
takes and returns a &lt;tt class="docutils literal"&gt;Func&lt;/tt&gt;. At this point we also instantiate the &lt;tt class="docutils literal"&gt;Func&lt;/tt&gt;
to have the exact types we need:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;factorial_tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;recurse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And the actual factorial function that users can call is created with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;fac&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factorial_tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now &lt;tt class="docutils literal"&gt;fac&lt;/tt&gt; is function of type &lt;tt class="docutils literal"&gt;Func&lt;/tt&gt;: it computes and returns the factorial
of its parameter, and can be simply invoked as &lt;tt class="docutils literal"&gt;answer := fac(param)&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;We can also try the other example in my previous post - a function that finds
the sum of values in a binary tree. It demonstrates a slightly more complicated
recursive flow as well as different types for the function's parameter and
return value:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;treesum_tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;recurse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;recurse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And once again, the actual usable function is generated by invoking &lt;tt class="docutils literal"&gt;Y&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;treesum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;treesum_tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</content><category term="misc"/><category term="Go"/><category term="Lisp"/><category term="Functional programming"/></entry><entry><title>Type inference</title><link href="https://eli.thegreenplace.net/2018/type-inference/" rel="alternate"/><published>2018-11-14T06:16:00-08:00</published><updated>2026-11-02T23:32:44.981329-08:00</updated><author><name>Eli Bendersky</name></author><id>tag:eli.thegreenplace.net,2018-11-14:/2018/type-inference/</id><summary type="html">&lt;p&gt;Type inference is a major feature of several programming languages, most notably
languages from the ML family like Haskell. In this post I want to provide a
brief overview of type inference, along with a simple Python implementation for
a toy ML-like language.&lt;/p&gt;
&lt;div class="section" id="uni-directional-type-inference"&gt;
&lt;h2&gt;Uni-directional type inference&lt;/h2&gt;
&lt;p&gt;While static typing is …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Type inference is a major feature of several programming languages, most notably
languages from the ML family like Haskell. In this post I want to provide a
brief overview of type inference, along with a simple Python implementation for
a toy ML-like language.&lt;/p&gt;
&lt;div class="section" id="uni-directional-type-inference"&gt;
&lt;h2&gt;Uni-directional type inference&lt;/h2&gt;
&lt;p&gt;While static typing is very useful, one of its potential downsides is verbosity.
The programmer has to annotate values with types throughout the code, which
results in more effort and clutter. What's really annoying, though, is that in
many cases these annotations feel superfluous. Consider this classical C++
example from pre-C++11 times:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Blob&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;blobs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Blob&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;blobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Clearly when the compiler sees &lt;tt class="docutils literal"&gt;blobs.begin()&lt;/tt&gt;, it knows the type of
&lt;tt class="docutils literal"&gt;blobs&lt;/tt&gt;, so it also knows the type of the &lt;tt class="docutils literal"&gt;begin()&lt;/tt&gt; method invoked on it
because it is familiar with the declaration of &lt;tt class="docutils literal"&gt;begin&lt;/tt&gt;. Why should the
programmer be burdened with spelling out the type of the iterator? Indeed, one
of the most welcome changes in C++11 was lifting this burden by repurposing
&lt;tt class="docutils literal"&gt;auto&lt;/tt&gt; for basic type inference:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Blob&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;blobs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;blobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Go has a similar capability with the &lt;tt class="docutils literal"&gt;:=&lt;/tt&gt; syntax. Given some function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parseThing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can simply write:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parseThing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Without having to explicitly declare that &lt;tt class="docutils literal"&gt;node&lt;/tt&gt; has type &lt;tt class="docutils literal"&gt;Node&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;err&lt;/tt&gt;
has type &lt;tt class="docutils literal"&gt;error.&lt;/tt&gt;&lt;/p&gt;
&lt;p&gt;These features are certainly useful, and they involve some degree of type
inference from the compiler. Some functional programming proponents say this is
not &lt;em&gt;real&lt;/em&gt; type inference, but I think the difference is just a matter of
degree. There's certainly &lt;em&gt;some&lt;/em&gt; inference going on here, with the compiler
calculating and assigning the right types for expressions without the
programmer's help. Since this calculation flows in one direction (from the
declaration of the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;vector::begin&lt;/span&gt;&lt;/tt&gt; method to the &lt;tt class="docutils literal"&gt;auto&lt;/tt&gt; assignment), I'll
call it &lt;em&gt;uni-directional&lt;/em&gt; type inference &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="bi-directional-type-inference-hindley-milner"&gt;
&lt;h2&gt;Bi-directional type inference (Hindley-Milner)&lt;/h2&gt;
&lt;p&gt;If we define a new &lt;tt class="docutils literal"&gt;map&lt;/tt&gt; function in Haskell to map a function over a list,
we can do it as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nf"&gt;mymap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt;
&lt;span class="nf"&gt;mymap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mymap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that we did not specify the types for either the arguments of
&lt;tt class="docutils literal"&gt;mymap&lt;/tt&gt;, or its return value. The Haskell compiler can infer them on its own,
using the definition provided:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&amp;gt; :t Main.mymap
Main.mymap :: (t1 -&amp;gt; t) -&amp;gt; [t1] -&amp;gt; [t]
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The compiler has determined that the first argument of &lt;tt class="docutils literal"&gt;mymap&lt;/tt&gt; is a generic
function, assigning its argument the type &lt;tt class="docutils literal"&gt;t1&lt;/tt&gt; and its return value the type
&lt;tt class="docutils literal"&gt;t&lt;/tt&gt;. The second argument of &lt;tt class="docutils literal"&gt;mymap&lt;/tt&gt; has the type &lt;tt class="docutils literal"&gt;[t1]&lt;/tt&gt;, which means &amp;quot;list
of &lt;tt class="docutils literal"&gt;t1&lt;/tt&gt;&amp;quot;; then the return value of &lt;tt class="docutils literal"&gt;mymap&lt;/tt&gt; has the type &amp;quot;list of &lt;tt class="docutils literal"&gt;t&lt;/tt&gt;&amp;quot;.
How was this accomplished?&lt;/p&gt;
&lt;p&gt;Let's start with the second argument. From the &lt;tt class="docutils literal"&gt;[] = []&lt;/tt&gt; variant, and also
from the &lt;tt class="docutils literal"&gt;(first:rest)&lt;/tt&gt; deconstruction, the compiler infers it has a list
type. But there's nothing else in the code constraining the element type, so the
compiler chooses a generic type specifier - &lt;tt class="docutils literal"&gt;t1&lt;/tt&gt;. &lt;tt class="docutils literal"&gt;f first&lt;/tt&gt; applies &lt;tt class="docutils literal"&gt;f&lt;/tt&gt; to
an element of this list, so &lt;tt class="docutils literal"&gt;f&lt;/tt&gt; has to take &lt;tt class="docutils literal"&gt;t1&lt;/tt&gt;; nothing constrains its
return value type, so it gets the generic &lt;tt class="docutils literal"&gt;t&lt;/tt&gt;. The result is &lt;tt class="docutils literal"&gt;f&lt;/tt&gt; has type
&lt;tt class="docutils literal"&gt;(t1 &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; t)&lt;/tt&gt;, which in Haskell parlance means &amp;quot;a function from &lt;tt class="docutils literal"&gt;t1&lt;/tt&gt; to
&lt;tt class="docutils literal"&gt;t&lt;/tt&gt;&amp;quot;.&lt;/p&gt;
&lt;p&gt;Here is another example, written in a toy language I put together for the sake
of this post. The language is called &lt;strong&gt;microml&lt;/strong&gt;, and its implementation is
described at the end of the post:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;foo f g x = if f(x == 1) then g(x) else 20
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here &lt;tt class="docutils literal"&gt;foo&lt;/tt&gt; is declared as a function with three arguments. What is its type?
Let's try to run type inference manually. First, note that the body of the
function consists of an &lt;tt class="docutils literal"&gt;if&lt;/tt&gt; expresssion. As is common in programming
languages, this one has some strict typing rules in microml; namely, the type of
the condition is boolean (&lt;tt class="docutils literal"&gt;Bool&lt;/tt&gt;), and the types of the &lt;tt class="docutils literal"&gt;then&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;else&lt;/tt&gt;
clauses must match.&lt;/p&gt;
&lt;p&gt;So we know that &lt;tt class="docutils literal"&gt;f(x == 1)&lt;/tt&gt; has to return a &lt;tt class="docutils literal"&gt;Bool&lt;/tt&gt;. Moreover, since &lt;tt class="docutils literal"&gt;x&lt;/tt&gt; is
compared to an integer, &lt;tt class="docutils literal"&gt;x&lt;/tt&gt; is an &lt;tt class="docutils literal"&gt;Int&lt;/tt&gt;. What is the type of &lt;tt class="docutils literal"&gt;g&lt;/tt&gt;? Well, it
has an &lt;tt class="docutils literal"&gt;Int&lt;/tt&gt; argument, and it return value must match the type of the &lt;tt class="docutils literal"&gt;else&lt;/tt&gt;
clause, which is an &lt;tt class="docutils literal"&gt;Int&lt;/tt&gt; as well.&lt;/p&gt;
&lt;p&gt;To summarize:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The type of &lt;tt class="docutils literal"&gt;x&lt;/tt&gt; is &lt;tt class="docutils literal"&gt;Int&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;The type of &lt;tt class="docutils literal"&gt;f&lt;/tt&gt; is &lt;tt class="docutils literal"&gt;Bool &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; Bool&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;The type of &lt;tt class="docutils literal"&gt;g&lt;/tt&gt; is &lt;tt class="docutils literal"&gt;Int &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; Int&lt;/tt&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the overall type of &lt;tt class="docutils literal"&gt;foo&lt;/tt&gt; is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;((Bool -&amp;gt; Bool), (Int -&amp;gt; Int), Int) -&amp;gt; Int
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It takes three arguments, the types of which we have determined, and returns
an &lt;tt class="docutils literal"&gt;Int&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Note how this type inference process is not just going in one direction, but
seems to be &amp;quot;jumping around&amp;quot; the body of the function figuring out known types
due to typing rules. This is why I call it bi-directional type inference,
but it's much better known as Hindley-Milner type inference, since it was
independently discovered by Roger Hindley in 1969 and Robin Milner in 1978.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="how-hindley-milner-type-inference-works"&gt;
&lt;h2&gt;How Hindley-Milner type inference works&lt;/h2&gt;
&lt;p&gt;We've seen a couple of examples of manually running type inference on some code
above. Now let's see how to translate it to an implementable algorithm. I'm
going to present the process in several separate stages, for simplicity. Some
other presentations of the algorithm combine several of these stages, but seeing
them separately is more educational, IMHO.&lt;/p&gt;
&lt;p&gt;The stages are:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Assign symbolic type names (like &lt;tt class="docutils literal"&gt;t1&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;t2&lt;/tt&gt;, ...) to all subexpressions.&lt;/li&gt;
&lt;li&gt;Using the language's typing rules, write a list of &lt;em&gt;type equations&lt;/em&gt; (or
&lt;em&gt;constraints&lt;/em&gt;) in terms of these type names.&lt;/li&gt;
&lt;li&gt;Solve the list of type equations using &lt;a class="reference external" href="https://eli.thegreenplace.net/2018/unification/"&gt;unification&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let's use this example again:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;foo f g x = if f(x == 1) then g(x) else 20
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Starting with &lt;strong&gt;stage 1&lt;/strong&gt;, we'll list all subexpressions in this
declaration (starting with the declaration itself) and assign unique type names
to them:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;foo                                       t0
f                                         t1
g                                         t2
x                                         t3
if f(x == 1) then g(x) else 20            t4
f(x == 1)                                 t5
x == 1                                    t6
x                                         t3
g(x)                                      t7
20                                        Int
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that every subexpression gets a type, and we de-duplicate them (e.g. &lt;tt class="docutils literal"&gt;x&lt;/tt&gt;
is encountered twice and gets the same type name assigned). Constant nodes get
known types.&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;stage 2&lt;/strong&gt;, we'll use the language's typing rules to write down equations
involving these type names. Usually books and papers use slightly scary formal
notation for typing rules; for example, for &lt;tt class="docutils literal"&gt;if&lt;/tt&gt;:&lt;/p&gt;
&lt;object class="align-center" data="https://eli.thegreenplace.net/images/math/67f9df5a4a93c7a445a1568ef49e5a5c3eab4fc5.svg" style="height: 41px;" type="image/svg+xml"&gt;\[\frac{\Gamma \vdash e_0 : Bool, \Gamma \vdash e_1 : T, \Gamma \vdash e_2 : T}{\Gamma \vdash if\: e_0\: then\: e_1\: else\: e_2 : T}\]&lt;/object&gt;
&lt;p&gt;All this means is the intuitive typing of &lt;tt class="docutils literal"&gt;if&lt;/tt&gt; we've described above: the
condition is expected to be boolean, and the types of the &lt;tt class="docutils literal"&gt;then&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;else&lt;/tt&gt;
clauses are expected to match, and their type becomes the type of the whole
expression.&lt;/p&gt;
&lt;p&gt;To unravel the notation, prepend &amp;quot;given that&amp;quot; to the expression above the line
and &amp;quot;we can derive&amp;quot; to the expression below the line;
&lt;object class="valign-m3 latex-math" data="https://eli.thegreenplace.net/images/math/3e4033fef16d01026c5da2f9c029a352f2ad9537.svg" style="height: 16px;" type="image/svg+xml"&gt;\Gamma \vdash e_0 : Bool&lt;/object&gt; means that &lt;object class="valign-m3 latex-math" data="https://eli.thegreenplace.net/images/math/7d22d6376548637fa828311e10662c6ab5e1b439.svg" style="height: 11px;" type="image/svg+xml"&gt;e_0&lt;/object&gt; is typed to Bool in
the set of typing assumptions called &lt;object class="valign-m1 latex-math" data="https://eli.thegreenplace.net/images/math/4c596c27eb47af04b4c9c7534f796b1a3b7f28e4.svg" style="height: 13px;" type="image/svg+xml"&gt;\Gamma&lt;/object&gt;.&lt;/p&gt;
&lt;p&gt;Similarly, a typing rule for single-argument function application would be:&lt;/p&gt;
&lt;object class="align-center" data="https://eli.thegreenplace.net/images/math/a172aee1cd75a57dfd68b6ecf55868500c3bb9ae.svg" style="height: 41px;" type="image/svg+xml"&gt;\[\frac{\Gamma \vdash e_0 : T, \Gamma \vdash f : T \rightarrow U}{\Gamma \vdash f(e_0) : U}\]&lt;/object&gt;
&lt;p&gt;The real trick of type inference is running these typing rules &lt;em&gt;in reverse&lt;/em&gt;. The
rule tells us how to assign types to the whole expression given its constituent
types, but we can also use it as an equation that works both ways and lets us
infer constituent types from the whole expression's type.&lt;/p&gt;
&lt;p&gt;Let's see what equations we can come up with, looking at the code:&lt;/p&gt;
&lt;p&gt;From &lt;tt class="docutils literal"&gt;f(x == 1)&lt;/tt&gt; we infer &lt;tt class="docutils literal"&gt;t1 = (t6 &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; t5)&lt;/tt&gt;, because &lt;tt class="docutils literal"&gt;t1&lt;/tt&gt; is the type of
&lt;tt class="docutils literal"&gt;f&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;t6&lt;/tt&gt; is the type of &lt;tt class="docutils literal"&gt;x == 1&lt;/tt&gt;, and &lt;tt class="docutils literal"&gt;t5&lt;/tt&gt; is the type of &lt;tt class="docutils literal"&gt;f(x ==
1)&lt;/tt&gt;. Note that we're using the typing rules for function application here.
Moreover, we can infer that &lt;tt class="docutils literal"&gt;t3&lt;/tt&gt; is &lt;tt class="docutils literal"&gt;Int&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;t6&lt;/tt&gt; is &lt;tt class="docutils literal"&gt;Bool&lt;/tt&gt; because
of the typing rule of the &lt;tt class="docutils literal"&gt;==&lt;/tt&gt; operator.&lt;/p&gt;
&lt;p&gt;Similarly, from &lt;tt class="docutils literal"&gt;g(x)&lt;/tt&gt; we infer &lt;tt class="docutils literal"&gt;t2 = (t3 &lt;span class="pre"&gt;-&amp;gt;&lt;/span&gt; t7)&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;From the &lt;tt class="docutils literal"&gt;if&lt;/tt&gt; expression, we infer that &lt;tt class="docutils literal"&gt;t6&lt;/tt&gt; is &lt;tt class="docutils literal"&gt;Bool&lt;/tt&gt; (since it's the
condition of the &lt;tt class="docutils literal"&gt;if&lt;/tt&gt;) and that &lt;tt class="docutils literal"&gt;t4 = Int&lt;/tt&gt;, because the &lt;tt class="docutils literal"&gt;then&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;else&lt;/tt&gt; clauses must match.&lt;/p&gt;
&lt;p&gt;Now we have a list of equations, and our task is to find the most general
solution, treating the equations as constraints. This is done by using the
unification algorithm which I described in detail in the &lt;a class="reference external" href="https://eli.thegreenplace.net/2018/unification/"&gt;previous post&lt;/a&gt;. The solution we're seeking
here is precisely the &lt;em&gt;most general unifier&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;For our expression, the algorithm will find the type of &lt;tt class="docutils literal"&gt;foo&lt;/tt&gt; to be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;((Bool -&amp;gt; Bool), (Int -&amp;gt; Int), Int) -&amp;gt; Int)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As expected.&lt;/p&gt;
&lt;p&gt;If we make a slight modification to the expression to remove the comparison of
&lt;tt class="docutils literal"&gt;x&lt;/tt&gt; with 1:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;foo f g x = if f(x) then g(x) else 20
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we can no longer constrain the type of &lt;tt class="docutils literal"&gt;x&lt;/tt&gt;, since all we know about it
is that it's passed into functions &lt;tt class="docutils literal"&gt;f&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;g&lt;/tt&gt;, and nothing else constrains
the arguments of these functions. The type inference process will thus calculate
this type for &lt;tt class="docutils literal"&gt;foo&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;((a -&amp;gt; Bool), (a -&amp;gt; Int), a) -&amp;gt; Int
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It assigns &lt;tt class="docutils literal"&gt;x&lt;/tt&gt; the generic type name &lt;tt class="docutils literal"&gt;a&lt;/tt&gt;, and uses it for the arguments of
&lt;tt class="docutils literal"&gt;f&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;g&lt;/tt&gt; as well.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-implementation"&gt;
&lt;h2&gt;The implementation&lt;/h2&gt;
&lt;p&gt;An implementation of microml is &lt;a class="reference external" href="https://github.com/eliben/code-for-blog/tree/main/2018/type-inference"&gt;available here&lt;/a&gt;, as
a self-contained Python program that parses a microml declaration and infers its
type. The best starting point is &lt;tt class="docutils literal"&gt;main.py&lt;/tt&gt;, which spells out the stages of
type inference:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;foo f g x = if f(x == 1) then g(x) else 20&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Code&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;----&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Parse the microml code snippet into an AST.&lt;/span&gt;
&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_decl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Parsed AST&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;----&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Stage 1: Assign symbolic typenames&lt;/span&gt;
&lt;span class="n"&gt;typing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign_typenames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Typename assignment&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;----&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;typing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show_type_assignment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Stage 2: Generate a list of type equations&lt;/span&gt;
&lt;span class="n"&gt;equations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;typing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generate_equations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;equations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Equations&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;----&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;equations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{:15}&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="si"&gt;{:20}&lt;/span&gt;&lt;span class="s1"&gt; | &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;orig_node&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# Stage 3: Solve equations using unification&lt;/span&gt;
&lt;span class="n"&gt;unifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unify_all_equations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;equations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Inferred type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;----&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;typing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_expression_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rename_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="n"&gt;sep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will print out:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Code
----
foo f g x = if f(x == 1) then g(x) else 20

Parsed AST
----
Decl(foo, Lambda([f, g, x], If(App(f, [(x == 1)]), App(g, [x]), 20)))

Typename assignment
----
Lambda([f, g, x], If(App(f, [(x == 1)]), App(g, [x]), 20))   t0
If(App(f, [(x == 1)]), App(g, [x]), 20)                      t4
App(f, [(x == 1)])                                           t5
f                                                            t1
(x == 1)                                                     t6
x                                                            t3
1                                                            Int
App(g, [x])                                                  t7
g                                                            t2
x                                                            t3
20                                                           Int

Equations
----
Int             Int                  | 1
t3              Int                  | (x == 1)
Int             Int                  | (x == 1)
t6              Bool                 | (x == 1)
t1              (t6 -&amp;gt; t5)           | App(f, [(x == 1)])
t2              (t3 -&amp;gt; t7)           | App(g, [x])
Int             Int                  | 20
t5              Bool                 | If(App(f, [(x == 1)]), App(g, [x]), 20)
t4              t7                   | If(App(f, [(x == 1)]), App(g, [x]), 20)
t4              Int                  | If(App(f, [(x == 1)]), App(g, [x]), 20)
t0              ((t1, t2, t3) -&amp;gt; t4) | Lambda([f, g, x], If(App(f, [(x == 1)]), App(g, [x]), 20))

Inferred type
----
(((Bool -&amp;gt; Bool), (Int -&amp;gt; Int), Int) -&amp;gt; Int)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are many more examples of type-inferred microml code snippets in the test
file &lt;tt class="docutils literal"&gt;test_typing.py&lt;/tt&gt;. Here's another example which is interesting:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&amp;gt; foo f x = if x then lambda t -&amp;gt; f(t) else lambda j -&amp;gt; f(x)
((Bool -&amp;gt; a), Bool) -&amp;gt; (Bool -&amp;gt; a)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The actual inference is implemented in &lt;tt class="docutils literal"&gt;typing.py&lt;/tt&gt;, which is fairly well
commented and should be easy to understand after reading this post. The
trickiest part is probably the unification algorithm, but that one is just a
slight adaptation of the algorithm presented in the previous post.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;p class="first"&gt;After this post was published, it was pointed out that another type
checking / inference technique is already called bi-directional (see
&lt;a class="reference external" href="https://arxiv.org/abs/1306.6032"&gt;this paper&lt;/a&gt; for example); while it's
related to Hindley-Milner (HM), it's a distinct method. Therefore, my
terminology here can create a confusion.&lt;/p&gt;
&lt;p class="last"&gt;I'll emphasize that my only use of the term &amp;quot;bi-directional&amp;quot; is to
distinguish what HM does from the simpler &amp;quot;uni-directional&amp;quot; inference
described at the beginning.&lt;/p&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="misc"/><category term="Python"/><category term="Programming"/><category term="Haskell"/><category term="Functional programming"/></entry></feed>