Planet FactorJohn Benediktsson: Random Derangement2024-12-16T15:00:00.000000Z<p>I had a lot of fun writing code to compute
<a href="https://re.factorcode.org/2024/12/derangements.html">derangements</a> recently. I thought I was done with
that topic until I bumped into a question on
<a href="https://stackoverflow.com">StackOverflow</a> asking how to <a href="https://stackoverflow.com/questions/25200220/generate-a-random-derangement-of-a-list">generate a random
derangement of a
list</a>.
Being <a href="https://xkcd.com/356/">nerd sniped</a> is a real thing, and so I started
looking at solutions.</p>
<p>There’s a paper called “<a href="https://labdisia.disia.unifi.it/merlini/papers/Derangements.pdf">An analysis of a simple algorithm for random
derangements</a>”
that has an, ahem, <em>simple</em> algorithm. The basic idea is to generate a random
permutation of indices, breaking early if the <em>random permutation</em> is obviously
not a derangement.</p>
<p>One way to take a random permutation would be to use our <a href="https://docs.factorcode.org/content/word-__lt__permutations__gt__,math.combinatorics.html">permutations virtual
sequence</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"ABCDEF"</span> <permutations> random <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span><span class="s">"FCEBDA"</span> <span class="c">! is a derangement</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"ABCDEF"</span> <permutations> random <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span><span class="s">"DFBCEA"</span> <span class="c">! is NOT a derangement</span>
</span></span></code></pre></div><p>And so you could loop until a <em>derangement</em> of indices is found:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">random-derangement-indices</span> <span class="nf">( </span><span class="nv">n</span> <span class="nf">-- </span><span class="nv">seq</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> <span class="no">f </span><span class="nb">swap </span><iota> <permutations>
</span></span><span class="line"><span class="cl"> '[ <span class="nb">drop </span>_ random <span class="nb">dup </span>derangement? <span class="nb">not </span>] <span class="nb">loop </span><span class="k">;
</span></span></span></code></pre></div><p>But, since only 36% or so of permutations are derangements, perhaps it would be
faster and better to implement the algorithm from that paper – making our own
random permutation of indices and breaking early if obviously not a
<em>derangement</em>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">::</span> <span class="nf">random-derangement-indices</span> <span class="nf">( </span><span class="nv">n</span> <span class="nf">-- </span><span class="nv">indices</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> n <iota> <span class="nb">>array </span>:> seq
</span></span><span class="line"><span class="cl"> <span class="no">f </span>[
</span></span><span class="line"><span class="cl"> <span class="nb">dup </span>:> v
</span></span><span class="line"><span class="cl"> n <span class="m">1 </span>(a..b] [| j |
</span></span><span class="line"><span class="cl"> j <span class="m">1 </span><span class="nb">+ </span>random :> p
</span></span><span class="line"><span class="cl"> p v <span class="nb">nth </span>j <span class="nb">= </span>[ <span class="no">t </span>] [ j p v <span class="nb">exchange </span><span class="no">f </span>] <span class="nb">if
</span></span></span><span class="line"><span class="cl"><span class="nb"></span> ] <span class="nb">any? </span>v <span class="nb">first zero? or
</span></span></span><span class="line"><span class="cl"><span class="nb"></span> ] [ <span class="nb">drop </span>seq <span class="nb">clone </span>] <span class="nb">do while </span><span class="k">;
</span></span></span></code></pre></div><p>We can use that to build a <code>random-derangement</code> word:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">random-derangement</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nf">-- </span><span class="nv">seq'</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> [ <span class="nb">length </span>random-derangement-indices ] [ <span class="nb">nths </span>] <span class="nb">bi </span><span class="k">;
</span></span></span></code></pre></div><p>And then, for example, get a <em>random derangement</em> of the alphabet – of which
there are one hundred and forty-eight septillion derangements, give or take –
in under a millisecond:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</span> random-derangement <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span><span class="s">"CZFABMSUXRQDEHGYJLTPVOIKWN"</span>
</span></span></code></pre></div><p>We could check to make sure that we generate all derangments with equal
possibility using a simple test case:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="m">1,000,000 </span>[
</span></span><span class="line"><span class="cl"> <span class="s">"ABCD"</span> random-derangement
</span></span><span class="line"><span class="cl"> ] <span class="nb">replicate </span>histogram sort-keys <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span>{
</span></span><span class="line"><span class="cl"> { <span class="s">"BADC"</span> <span class="m">111639 </span>}
</span></span><span class="line"><span class="cl"> { <span class="s">"BCDA"</span> <span class="m">110734 </span>}
</span></span><span class="line"><span class="cl"> { <span class="s">"BDAC"</span> <span class="m">110682 </span>}
</span></span><span class="line"><span class="cl"> { <span class="s">"CADB"</span> <span class="m">111123 </span>}
</span></span><span class="line"><span class="cl"> { <span class="s">"CDAB"</span> <span class="m">111447 </span>}
</span></span><span class="line"><span class="cl"> { <span class="s">"CDBA"</span> <span class="m">111147 </span>}
</span></span><span class="line"><span class="cl"> { <span class="s">"DABC"</span> <span class="m">111215 </span>}
</span></span><span class="line"><span class="cl"> { <span class="s">"DCAB"</span> <span class="m">111114 </span>}
</span></span><span class="line"><span class="cl"> { <span class="s">"DCBA"</span> <span class="m">110899 </span>}
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p>Looks good to me!</p>
John Benediktsson: Derangements2024-12-08T15:00:00.000000Z<p><a href="https://en.wikipedia.org/wiki/Derangement">Derangements</a>, also sometimes known
as <em>deranged permutations</em>, are described as:</p>
<blockquote>
<p>In <a href="https://en.wikipedia.org/wiki/Combinatorics">combinatorial</a>
<a href="https://en.wikipedia.org/wiki/Mathematics">mathematics</a>, a derangement is a
<a href="https://en.wikipedia.org/wiki/Permutation">permutation</a> of the elements of a
<a href="https://en.wikipedia.org/wiki/Set_(mathematics)">set</a> in which no element
appears in its original position. In other words, a derangement is a
permutation that has no <a href="https://en.wikipedia.org/wiki/Fixed_point_(mathematics)">fixed
points</a>.</p>
</blockquote>
<p>There is a fun online <a href="https://www.dcode.fr/derangements-generator">derangements generator
tool</a> that you can use to play
with computing the <em>derangements of a sequence</em> as well as calculating the
<em>number of derangements</em> for a given sequence size.</p>
<p>As an example, we can use the <a href="https://docs.factorcode.org/content/vocab-math.combinatorics.html">math.combinatorics
vocabulary</a>,
to generate all the permutations of the sequence <code>{ 0 1 2 }</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> { <span class="m">0 1 2 </span>} all-permutations <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span>{
</span></span><span class="line"><span class="cl"> { <span class="m">0 1 2 </span>}
</span></span><span class="line"><span class="cl"> { <span class="m">0 2 1 </span>}
</span></span><span class="line"><span class="cl"> { <span class="m">1 0 2 </span>}
</span></span><span class="line"><span class="cl"> { <span class="m">1 2 0 </span>}
</span></span><span class="line"><span class="cl"> { <span class="m">2 0 1 </span>}
</span></span><span class="line"><span class="cl"> { <span class="m">2 1 0 </span>}
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p>Since a <em>derangement</em> is a permutation that requires each element to be in a
different slot, we could write a word to check the permuted indices to see if
that is true:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">derangement?</span> <span class="nf">( </span><span class="nv">indices</span> <span class="nf">-- </span><span class="nv">?</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> <span class="nb">dup length </span><iota> [ <span class="nb">= </span>] 2any? <span class="nb">not </span><span class="k">;
</span></span></span></code></pre></div><p>These would be the two <em>derangements</em> of the indices <code>{ 0 1 2 }</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> { <span class="m">0 1 2 </span>} all-permutations [ derangement? ] <span class="nb">filter </span><span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span>{
</span></span><span class="line"><span class="cl"> { <span class="m">1 2 0 </span>}
</span></span><span class="line"><span class="cl"> { <span class="m">2 0 1 </span>}
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p>The <em>number of derangements</em> is the
<a href="https://mathworld.wolfram.com/Subfactorial.html">subfactorial</a> of the length
of the sequence:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">subfactorial</span> <span class="nf">( </span><span class="nv">n</span> <span class="nf">-- </span><span class="nv">?</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> [ <span class="m">1 </span>] [ factorial <span class="m">1 </span><span class="nb">+ </span>e <span class="nb">/i </span>] <span class="nb">if-zero </span><span class="k">;
</span></span></span></code></pre></div><p>We can build a <code><derangement-iota></code> that is a sequence as long as that
number:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf"><derangement-iota></span> <span class="nf">( </span><span class="nv">seq</span> <span class="nf">-- </span><span class="nv"><iota></span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> <span class="nb">length </span>subfactorial <iota> <span class="k">; inline
</span></span></span></code></pre></div><p>And we can build a <code>next-derangement</code> word that calculates the <a href="https://re.factorcode.org/2012/03/next-permutation.html">next
permutation</a> that is a
<em>derangement</em>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">next-derangement</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nf">-- </span><span class="nv">seq</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> [ <span class="nb">dup </span>derangement? ] [ next-permutation ] <span class="nb">do until </span><span class="k">;
</span></span></span></code></pre></div><p>We can then build upon some of the code for <a href="https://docs.factorcode.org/content/word-each-permutation,math.combinatorics.html">iterating
permutations</a>,
designing an internal <code>derangements-quot</code> word that is similar in form to the
existing <code>permutations-quot</code> word:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">derangements-quot</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nv">quot</span> <span class="nf">-- </span><span class="nv">seq</span> <span class="nv">quot'</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> [ [ <derangement-iota> ] [ <span class="nb">length </span><iota> <span class="nb">>array </span>] [ ] <span class="nb">tri </span>] <span class="nb">dip
</span></span></span><span class="line"><span class="cl"><span class="nb"></span> '[ <span class="nb">drop </span>_ next-derangement _ nths-unsafe @ ] <span class="k">; inline
</span></span></span></code></pre></div><p>And then use it to build a series of words that can provide iteration across
<em>derangements</em>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">each-derangement</span> <span class="nf">( </span><span class="nv">...</span> <span class="nv">seq</span> <span class="nv">quot:</span> <span class="nf">( </span><span class="nv">...</span> <span class="nv">elt</span> <span class="nf">-- </span><span class="nv">...</span> <span class="nf">) -- </span><span class="nv">...</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> derangements-quot <span class="nb">each </span><span class="k">; inline
</span></span></span><span class="line"><span class="cl"><span class="k"></span>
</span></span><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">map-derangements</span> <span class="nf">( </span><span class="nv">...</span> <span class="nv">seq</span> <span class="nv">quot:</span> <span class="nf">( </span><span class="nv">...</span> <span class="nv">elt</span> <span class="nf">-- </span><span class="nv">...</span> <span class="nv">newelt</span> <span class="nf">) -- </span><span class="nv">...</span> <span class="nv">newseq</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> derangements-quot <span class="nb">map </span><span class="k">; inline
</span></span></span><span class="line"><span class="cl"><span class="k"></span>
</span></span><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">filter-derangements</span> <span class="nf">( </span><span class="nv">...</span> <span class="nv">seq</span> <span class="nv">quot:</span> <span class="nf">( </span><span class="nv">...</span> <span class="nv">elt</span> <span class="nf">-- </span><span class="nv">...</span> <span class="nv">?</span> <span class="nf">) -- </span><span class="nv">...</span> <span class="nv">newseq</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> <span class="nb">selector </span>[ each-derangement ] <span class="nb">dip </span><span class="k">; inline
</span></span></span><span class="line"><span class="cl"><span class="k"></span>
</span></span><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">all-derangements</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nf">-- </span><span class="nv">seq'</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> [ ] map-derangements <span class="k">;
</span></span></span><span class="line"><span class="cl"><span class="k"></span>
</span></span><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">all-derangements?</span> <span class="nf">( </span><span class="nv">...</span> <span class="nv">seq</span> <span class="nv">quot:</span> <span class="nf">( </span><span class="nv">...</span> <span class="nv">elt</span> <span class="nf">-- </span><span class="nv">...</span> <span class="nv">?</span> <span class="nf">) -- </span><span class="nv">...</span> <span class="nv">?</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> derangements-quot <span class="nb">all? </span><span class="k">; inline
</span></span></span><span class="line"><span class="cl"><span class="k"></span>
</span></span><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">find-derangement</span> <span class="nf">( </span><span class="nv">...</span> <span class="nv">seq</span> <span class="nv">quot:</span> <span class="nf">( </span><span class="nv">...</span> <span class="nv">elt</span> <span class="nf">-- </span><span class="nv">...</span> <span class="nv">?</span> <span class="nf">) -- </span><span class="nv">...</span> <span class="nv">elt/f</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> '[ _ <span class="nb">keep and </span>] derangements-quot <span class="nb">map-find drop </span><span class="k">; inline
</span></span></span><span class="line"><span class="cl"><span class="k"></span>
</span></span><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">reduce-derangements</span> <span class="nf">( </span><span class="nv">...</span> <span class="nv">seq</span> <span class="nv">identity</span> <span class="nv">quot:</span> <span class="nf">( </span><span class="nv">...</span> <span class="nv">prev</span> <span class="nv">elt</span> <span class="nf">-- </span><span class="nv">...</span> <span class="nv">next</span> <span class="nf">) -- </span><span class="nv">...</span> <span class="nv">result</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> <span class="nb">swapd </span>each-derangement <span class="k">; inline
</span></span></span></code></pre></div><p>And, now we can use this to find the nine <em>derangements</em> for <code>"ABCD"</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"ABCD"</span> all-derangements <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span>{
</span></span><span class="line"><span class="cl"> <span class="s">"BADC"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"BCDA"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"BDAC"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"CADB"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"CDAB"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"CDBA"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"DABC"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"DCAB"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"DCBA"</span>
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p>This is available on my
<a href="https://github.com/mrjbq7/re-factor/blob/master/derangements/derangements.factor">GitHub</a>.</p>
John Benediktsson: Zen of Factor2024-12-05T15:00:00.000000Z<p>Years ago, I remember reading a blog post called “<a href="http://factor-language.blogspot.com/2006/06/why-is-groovy-is-big.html">Why is Groovy is
big?</a>”
by <a href="https://factorcode.org/slava/">Slava Pestov</a>, the original author of
<a href="https://factorcode.org">Factor</a>. In it, he talks about lines of code and
sets the stage for how <a href="https://re.factorcode.org/2011/07/concatenative-thinking.html">concatenative
thinking</a> can lead to properties like
<a href="https://re.factorcode.org/2011/04/verbosity.html">conciseness</a> and
<a href="https://re.factorcode.org/2012/02/readability.html">readability</a>, ending with this:</p>
<blockquote>
<p>I tend to think the majority of code people write is overly complicated,
full of redundancy, and designed for such flexibility that in practice is
not needed at all. I hope one day this trend reverses.</p>
</blockquote>
<p>I’ve been thinking a lot recently about <a href="https://re.factorcode.org/2024/08/reflecting-on-20-years.html">20 years of
Factor</a> and I thought it would be fun to
write a <em>Zen of Factor</em>. Perhaps inspired by the <a href="https://www.amazon.com/Zen-Programming-Geoffrey-James/dp/0931137098">Zen of
Programming</a>
book written in 1987 by Geoffrey James, there are a couple of examples I wanted
to point to first.</p>
<h3 id="python">Python</h3>
<p>The <a href="https://python.org">Python programming language</a> was one of the first
languages that I am aware of to get a <em>Zen</em>, contributed at least as far
back as <a href="https://github.com/python/cpython/commit/63cd9bf4887cd4603ead4db29c772fa370e68a25">February
2002</a>
in a kind of easter egg fashion encrypted by
<a href="https://en.wikipedia.org/wiki/ROT13">ROT13</a>:</p>
<pre tabindex="0"><code>$ python -c "import this"
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
</code></pre><h3 id="zig">Zig</h3>
<p>Quite a bit more recently, the <a href="https://ziglang.org">Zig programming language</a>
introduced a <em>Zen</em> through a series of commits starting in <a href="https://github.com/ziglang/zig/commit/221e5b188c4aaef9667c8e397d7fac21a8ac8fbd">August
2017</a>.
You can see the current version by running <code>zig zen</code>:</p>
<pre tabindex="0"><code>$ zig zen
* Communicate intent precisely.
* Edge cases matter.
* Favor reading code over writing code.
* Only one obvious way to do things.
* Runtime crashes are better than bugs.
* Compile errors are better than runtime crashes.
* Incremental improvements.
* Avoid local maximums.
* Reduce the amount one must remember.
* Focus on code rather than style.
* Resource allocation may fail; resource deallocation must succeed.
* Memory is a resource.
* Together we serve the users.
</code></pre><h3 id="factor">Factor</h3>
<p>In that spirit, I thought it would be fun to put together some ideas for what a
<em>Zen of Factor</em> might look like, incorporating aspects of the language that I
enjoy, some thematic elements that might make you more successful learning and
developing in it, as well as pointing out the strong community that we have and
hope to grow.</p>
<p>Here is the current draft:</p>
<pre tabindex="0"><code>The Zen of Factor
The REPL is your playground.
Working code beats perfect theory.
Words are better than paragraphs.
Stack effects tell the story.
Any syntax you need, you can create.
Simple primitives yield powerful combinations.
First make it work, then make it beautiful.
Make it beautiful, then make it fast.
Quick hacks grow into robust solutions.
When in doubt, factor it out.
Every word should do one thing well.
Let the stack guide your logic.
Write less, compose more.
If it works, ship it.
If it doesn't work, fix it.
If you don't like it, change it.
Today's beginner is tomorrow's core developer.
Questions encouraged, PRs welcome.
</code></pre><p>I really appreciate hearing about programs and problems that developers work
on, getting feedback that allows us to iteratively improve, and knowing that
every commit leads us towards a better future.</p>
<p>Thank you!</p>
John Benediktsson: Watching Code2024-12-03T15:00:00.000000Z<p><a href="https://factorcode.org">Factor</a> has a <a href="https://re.factorcode.org/2012/09/watching-words.html">watching
words</a> feature that allows you to see the inputs
and outputs of a word when it is called. I have wanted a way to define a
<em>watched code block</em> that we could use to see the stack before and after some
inner part of a word.</p>
<p>It turns out that it’s pretty simple to make this syntax using our existing
<a href="https://docs.factorcode.org/content/word-watch,tools.annotations.html">watch</a>
implementation from the <a href="https://docs.factorcode.org/content/vocab-tools.annotations.html">tools.annotations
vocabulary</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">DEFER:</span> <span class="nf">WATCH></span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">SYNTAX: </span><WATCH
</span></span><span class="line"><span class="cl"> <span class="no">\ WATCH></span> parse-until >quotation <span class="nb">dup </span>(watch) <span class="nb">append! </span><span class="k">;
</span></span></span></code></pre></div><p>Using this, we can now watch the inner part of a word, for example this word
that increments the input by 1:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">foo</span> <span class="nf">( </span><span class="nv">x</span> <span class="nf">-- </span><span class="nv">y</span> <span class="nf">) </span><span class="m">1 </span><WATCH <span class="nb">+ </span>WATCH> <span class="k">;
</span></span></span></code></pre></div><p>And see it used:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="m">10 </span>foo
</span></span><span class="line"><span class="cl">--- Entering [ <span class="nb">+ </span>]
</span></span><span class="line"><span class="cl">x <span class="m">10
</span></span></span><span class="line"><span class="cl"><span class="m"></span>x <span class="m">1
</span></span></span><span class="line"><span class="cl"><span class="m"></span>--- Leaving [ <span class="nb">+ </span>]
</span></span><span class="line"><span class="cl">x <span class="m">11
</span></span></span><span class="line"><span class="cl"><span class="m"></span>
</span></span><span class="line"><span class="cl">--- Data stack:
</span></span><span class="line"><span class="cl"><span class="m">11
</span></span></span></code></pre></div><p>One thing that I’d like to improve on this someday, is making it so this watch
syntax has a
<a href="https://docs.factorcode.org/content/article-prettyprint.html">prettyprint</a>
implementation that allows it to be rendered as it is typed.</p>
<p>I have added this to the latest <a href="https://github.com/factor/factor/">developer
version</a> if you’d like to update and give it
a try!</p>
John Benediktsson: Listener Font Sizes2024-11-13T15:00:00.000000Z<p><a href="https://factorcode.org">Factor</a> contains a
<a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop">REPL</a> – called the
<em>Listener</em> – available on the command-line and graphically as part of the <a href="https://docs.factorcode.org/content/article-ui-tools.html">UI
developer tools</a>.
For many users, this is their main interface to programming in the <a href="https://en.wikipedia.org/wiki/Factor_(programming_language)">Factor
programming
language</a>.</p>
<p>We sometimes get requests to better support styling the <a href="https://docs.factorcode.org/content/article-ui.html">user
interface</a>. This has led
to improvements such as support for light and dark themes, adjustable font
sizes, and other customizations. There have been a few existing ways to <a href="https://docs.factorcode.org/content/article-ui-listener-style.html">style
the UI
listener</a>
including support for keyboard commands to increase or decrease font sizes.
But, until recently this only affected new output or new Listener sessions.</p>
<p>Today, I improved this to make adjusting the font size much more dynamic, using
traditional keyboard shortcuts of <code>Ctrl</code> – or <code>Cmd</code> on
<a href="https://www.apple.com/macos">macOS</a> – combined with <code>+</code> or <code>-</code>:</p>
<video preload="" controls>
<source src="https://re.factorcode.org/videos/listener-font-sizes.mp4" type="video/mp4">
There should have been a video here but your browser does not seem
to support it.
</video>
<p>Give it a try, and please let us know other ways we can make improvements!</p>
John Benediktsson: Finding Subsequences2024-11-12T15:00:00.000000Z<p>Recently, I’ve been inspired by conversations taking place on our <a href="https://discord.gg/QxJYZx3QDf">Factor
Discord server</a>. This sometimes reflects
areas of interest from new contributors, curiousity exploring similarities
and differences between <a href="https://factorcode.org">Factor</a> and other
programming languages, or even early learning moments when exploring
<a href="https://concatenative.org/wiki/view/Concatenative%20language">concatenative
languages</a> in
general.</p>
<p>Today, someone asked about how to think about “<em>accumulation of values in an
array… to find all occurences (their position) of a subseq in a seq</em>”. The
solution to this might have this word name and stack effect:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">subseq-indices</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nv">subseq</span> <span class="nf">-- </span><span class="nv">indices</span> <span class="nf">) </span>... <span class="k">;
</span></span></span></code></pre></div><p>Before answering, I wanted to make sure they wanted to find overlapping
indices vs. non-overlapping indices, and they clarified that they expect it
to find this result – allowing overlapping subsequences:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"abcabcabc"</span> <span class="s">"abcabc"</span> subseq-indices <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span>{ <span class="m">0 3 </span>}
</span></span></code></pre></div><p>So, now that we have a reasonable specification, how do we think about
solving this problem when we are at the same time learning to solve problems
in stack languages and trying to see what features of <a href="https://docs.factorcode.org/content/article-vocab-index.html">Factor’s standard
library</a> would
help.</p>
<p>There are a lot of ways to think about this, and I often recommend one of
three approaches:</p>
<ol>
<li>starting inside-out (working on the inner part of the loop)</li>
<li>starting outside-in (modeling the outer loop and then figuring out what’s inside it)</li>
<li>using <a href="https://docs.factorcode.org/content/article-locals.html">local variables</a> (helpful when coming from an applicative language background)</li>
</ol>
<p>So let’s look at each approach in turn:</p>
<h2 id="inside-out">Inside Out</h2>
<p>The inner logic is going to require something like “<em>take an index to start
from and find the next matching subseq index</em>”, which looks an awful lot
like
<a href="https://docs.factorcode.org/content/word-subseq-index-from%2Csequences.html">subseq-index-from</a>
– except you also want to increment the found index afterwards to make sure
you are progressing through the sequence.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">next-subseq-index</span> <span class="nf">( </span><span class="nv">index</span> <span class="nv">seq</span> <span class="nv">subseq</span> <span class="nf">-- </span><span class="nv">next-index/f</span> <span class="nv">found-index/f</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> subseq-index-from [ [ <span class="m">1 </span><span class="nb">+ </span>] <span class="nb">keep </span>] [ <span class="no">f f </span>] <span class="nb">if* </span><span class="k">;
</span></span></span></code></pre></div><p>Then you could use it like so in a
<a href="https://docs.factorcode.org/content/word-loop,kernel.html">loop</a> with an
accumulator:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">subseq-indices</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nv">subseq</span> <span class="nf">-- </span><span class="nv">indices</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> [ V{ } <span class="nb">clone </span><span class="m">0 </span>] <span class="nb">2dip </span>'[
</span></span><span class="line"><span class="cl"> _ _ next-subseq-index <span class="nb">dup </span>[ [ <span class="nb">pick push </span>] <span class="nb">keep </span>] <span class="nb">when
</span></span></span><span class="line"><span class="cl"><span class="nb"></span> ] <span class="nb">loop drop </span><span class="k">;
</span></span></span></code></pre></div><p>But that feels like we had to work hard to do that, directly using an
accumulator, conditionals, and some stack shuffling. Luckily we have some
higher level words that might help, for example the <a href="https://docs.factorcode.org/content/article-namespaces-make.html">make
vocabulary</a>
which has an implicit accumulator that we can use <code>,</code> or <code>%</code> to push into:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">subseq-indices</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nv">subseq</span> <span class="nf">-- </span><span class="nv">indices</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> [ <span class="m">0 </span>] <span class="nb">2dip </span>'[
</span></span><span class="line"><span class="cl"> [ _ _ next-subseq-index <span class="nb">dup </span>[ , ] <span class="nb">when* </span>] <span class="nb">loop
</span></span></span><span class="line"><span class="cl"><span class="nb"></span> ] { } make <span class="nb">nip </span><span class="k">;
</span></span></span></code></pre></div><p>Or even using a
<a href="https://docs.factorcode.org/content/word-while__star__,kernel.html">while*</a>
loop, which is less code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">subseq-indices</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nv">subseq</span> <span class="nf">-- </span><span class="nv">indices</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> [ <span class="m">0 </span>] <span class="nb">2dip </span>'[
</span></span><span class="line"><span class="cl"> [ _ _ next-subseq-index ] [ , ] while*
</span></span><span class="line"><span class="cl"> ] { } make <span class="nb">nip </span><span class="k">;
</span></span></span></code></pre></div><p>But that feels like a lot too, simpler might be
<a href="https://docs.factorcode.org/content/word-produce,sequences.html">produce</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">subseq-indices</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nv">subseq</span> <span class="nf">-- </span><span class="nv">indices</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> [ <span class="m">0 </span>] <span class="nb">2dip </span>'[ _ _ next-subseq-index <span class="nb">dup </span>] [ ] <span class="nb">produce 2nip </span><span class="k">;
</span></span></span></code></pre></div><p>Or using
<a href="https://docs.factorcode.org/content/word-follow,sequences.html">follow</a>,
adjusting our start index and increment:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">subseq-indices</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nv">subseq</span> <span class="nf">-- </span><span class="nv">indices</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> [ <span class="m">-1 </span>] <span class="nb">2dip </span>'[ <span class="m">1 </span><span class="nb">+ </span>_ _ subseq-index-from ] <span class="nb">follow rest </span><span class="k">;
</span></span></span></code></pre></div><h2 id="outside-in">Outside In</h2>
<p>The outer logic approach would be something like “<em>we need to loop from the
start of the sequence, finding the next match, and accumulating it, until we
hit some exit condition and then return a result</em>” which you could write in a
kind of non-functional stack
<a href="https://en.wikipedia.org/wiki/Pseudocode">pseudocode</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">subseq-indices</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nv">subseq</span> <span class="nf">-- </span><span class="nv">indices</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> <span class="m">0 </span>[ find-next-match ] [ accumulate-match ] <span class="nb">while </span><span class="k">;
</span></span></span></code></pre></div><p>Then you have to kind of figure out what goes into those blocks:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">find-next-match</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nv">subseq</span> <span class="nv">n</span> <span class="nf">-- </span><span class="nv">found-index/f</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> <span class="nb">-rot </span>subseq-index-from <span class="k">;
</span></span></span></code></pre></div><p>And also something like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">accumulate-match</span> <span class="nf">( </span><span class="nv">accum</span> <span class="nv">found-index</span> <span class="nf">-- </span><span class="nv">accum</span> <span class="nv">next-index</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> [ <span class="nb">suffix! </span>] <span class="nb">keep </span><span class="m">1 </span><span class="nb">+ </span><span class="k">;
</span></span></span></code></pre></div><p>Taking those, and maybe thinking about what items should be on the stack and
in what order to reduce stack shuffling, becomes something like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">subseq-indices</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nv">subseq</span> <span class="nf">-- </span><span class="nv">indices</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> [ V{ } <span class="nb">clone </span><span class="m">0 </span>] <span class="nb">2dip
</span></span></span><span class="line"><span class="cl"><span class="nb"></span> '[ _ _ subseq-index-from ] [ [ <span class="nb">suffix! </span>] <span class="nb">keep </span><span class="m">1 </span><span class="nb">+ </span>] while* <span class="k">;
</span></span></span></code></pre></div><p>It is true that <code>[ suffix! ] keep 1 +</code> is also <code>[ suffix! ] [ 1 + ] bi</code>,
with varying aesthetics and ease of understanding, but sometimes when
learning a new language especially a stack language with
<a href="https://docs.factorcode.org/content/article-combinators.html">combinators</a>,
it is sometimes easy to start with stack shuffling and then learn about
these forms later to see if they can improve your code.</p>
<h2 id="locals">Locals</h2>
<p>Instead of those two stack approaches, we could instead use our <a href="https://docs.factorcode.org/content/article-locals.html">local
variables</a> and
write one big word in a manner similar to applicative languages, stepping
back and focusing on the result we want:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">::</span> <span class="nf">subseq-indices</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nv">subseq</span> <span class="nf">-- </span><span class="nv">indices</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> V{ } <span class="nb">clone </span>:> accum
</span></span><span class="line"><span class="cl"> <span class="m">0 </span>:> i!
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> [ i seq <span class="nb">subseq </span>subseq-index-from ]
</span></span><span class="line"><span class="cl"> [ <span class="nb">dup </span>accum <span class="nb">push </span><span class="m">1 </span><span class="nb">+ </span>i! ] while*
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> accum <span class="k">;
</span></span></span></code></pre></div><p>When working on this stuff, it’s nice to remember you can put a <code>B</code> to
<a href="https://docs.factorcode.org/content/article-breakpoints.html">set a
breakpoint</a> in
places to examine the stack at some inner point, or perhaps write a comment
showing the incoming stack and optionally the outgoing stack that a piece of
code is expected to have so that you understand what is happening in the
next few lines:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="c">! the next block of code finds the next index</span>
</span></span><span class="line"><span class="cl"><span class="c">! ( index seq subseq -- found-index )</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">! and pushes it into an accumulator</span>
</span></span><span class="line"><span class="cl"><span class="c">! ( accum found-index -- accum )</span>
</span></span></code></pre></div><p>This was <a href="https://github.com/factor/factor/commit/ae50ca8e1189b13a4a86dca72d07d19015d08961">added to the developer
branch</a>
in the <code>sequences.extras</code> vocabulary.</p>
<p>We love to hear questions and it’s even better when we can provide answers or
guidance for learning and solving problems. Feel free to join our conversations
and explore <a href="https://concatenative.org/wiki/view/Factor/Learning">learning
Factor</a>!</p>
John Benediktsson: Removing Subdomains2024-11-05T15:00:00.000000Z<p>There was an interesting question on the <a href="https://unix.stackexchange.com">Unix & Linux
StackExchange</a> asking how to <a href="https://unix.stackexchange.com/questions/774280/remove-subdomains-or-existing-domains">remove
subdomains or existing
domains</a>.
I thought it would be fun to show a few different approaches to solving this
using <a href="https://factorcode.org">Factor</a>.</p>
<p>Our first step should be to understand <a href="https://www.wix.com/blog/what-is-a-subdomain">what is a
subdomain</a>:</p>
<blockquote>
<p>A subdomain is a prefix added to a domain name to separate a section of
your website. Site owners primarily use subdomains to manage extensive
sections that require their own content hierarchy, such as online stores,
blogs, job boards or support platforms.</p>
</blockquote>
<h3 id="common-subdomains">Common Subdomains</h3>
<p>If we’re curious about what common subdomains are, we can turn to the
<a href="https://github.com/danielmiessler/SecLists">SecLists</a> project – described
as a “<em>security tester’s companion</em>” – which maintains a list of common
<a href="https://github.com/danielmiessler/SecLists/blob/master/Discovery/DNS/subdomains-top1million-5000.txt">5,000
subdomains</a>,
<a href="https://github.com/danielmiessler/SecLists/blob/master/Discovery/DNS/subdomains-top1million-20000.txt">20,000
subdomains</a>,
and <a href="https://github.com/danielmiessler/SecLists/blob/master/Discovery/DNS/subdomains-top1million-110000.txt">110,000
subdomains</a>
that were generated in 2015 as well as a <a href="https://github.com/danielmiessler/SecLists/blob/master/Discovery/DNS/combined_subdomains.txt">combined
subdomains</a>
list that has some additional ones added.</p>
<p>You can download the top 5,000 common subdomains using
<a href="https://docs.factorcode.org/content/article-memoize.html">memoization</a> to
cache the result:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">MEMO:</span> <span class="nf">top-5000-subdomains</span> <span class="nf">( -- </span><span class="nv">subdomains</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> <span class="s">"https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/DNS/subdomains-top1million-5000.txt"</span>
</span></span><span class="line"><span class="cl"> cache-directory download-once-into utf8 file-lines <span class="k">;
</span></span></span></code></pre></div><p>And then see what the “top 10” are:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> top-5000-subdomains <span class="m">10 </span><span class="nb">head </span><span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span>{
</span></span><span class="line"><span class="cl"> <span class="s">"www"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"mail"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"ftp"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"localhost"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"webmail"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"smtp"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"webdisk"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"pop"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"cpanel"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"whm"</span>
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p>You could remove “common subdomains” – adding a dot to make sure we only strip
a full subdomain – by recursively trying to clean the hostname until it stops
changing.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">remove-common-subdomains</span> <span class="nf">( </span><span class="nv">host</span> <span class="nf">-- </span><span class="nv">host'</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> top-5000-subdomains [ <span class="s">"."</span> <span class="nb">append </span>] <span class="nb">map </span>'[ _ [ ?head ] <span class="nb">any? </span>] <span class="nb">loop </span><span class="k">;
</span></span></span></code></pre></div><p>And try it out:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"www.mail.ftp.localhost.factorcode.org"</span>
</span></span><span class="line"><span class="cl"> remove-common-subdomains <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span><span class="s">"factorcode.org"</span>
</span></span></code></pre></div><p>That works pretty well, but it’s reliant on a <a href="https://en.wikipedia.org/wiki/Web_scraping">scraped
list</a> of subdomains that might not
be exhaustive, and could become stale over time as the tools and techniques
that developers use change.</p>
<h3 id="observed-subdomains">Observed Subdomains</h3>
<p>Similarly, another technique we could use would be to use our own observations
about domains, and if we observe a domain being used and then subsequently see
a subdomain of it, we can ignore the subdomain.</p>
<p>First, we write a word to remove any item that is prefixed by another, sorting
to make sure we see the prefix before the item prefixed by it:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">remove-prefixed</span> <span class="nf">( </span><span class="nv">seq</span> <span class="nf">-- </span><span class="nv">seq'</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> sort V{ } <span class="nb">clone </span>[
</span></span><span class="line"><span class="cl"> <span class="nb">dup </span>'[
</span></span><span class="line"><span class="cl"> [ _ [ <span class="nb">head? </span>] <span class="nb">with </span>none? ] _ push-when
</span></span><span class="line"><span class="cl"> ] <span class="nb">each
</span></span></span><span class="line"><span class="cl"><span class="nb"></span> ] <span class="nb">keep </span><span class="k">;
</span></span></span></code></pre></div><p>Second, we can remove the subdomains by using a kind of <a href="https://en.wikipedia.org/wiki/Schwartzian_transform">Schwartzian
transform</a>:</p>
<ol>
<li>reverse the domain names</li>
<li>remove the ones that are prefixed by another</li>
<li>un-reverse the domain names</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">remove-observed-subdomains</span> <span class="nf">( </span><span class="nv">hosts</span> <span class="nf">-- </span><span class="nv">hosts'</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> [ <span class="s">"."</span> <span class="nb">prepend reverse </span>] <span class="nb">map </span>remove-prefixed [ <span class="nb">reverse rest </span>] <span class="nb">map </span><span class="k">;
</span></span></span></code></pre></div><p>And then see it work:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> { <span class="s">"a.b.c"</span> <span class="s">"b.c"</span> <span class="s">"c.d.e"</span> <span class="s">"e.f"</span> }
</span></span><span class="line"><span class="cl"> remove-observed-subdomains <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span>V{ <span class="s">"b.c"</span> <span class="s">"c.d.e"</span> <span class="s">"e.f"</span> }
</span></span></code></pre></div><h3 id="resolving-domains">Resolving Domains</h3>
<p>And, finally, another technique might be to use the <a href="https://en.wikipedia.org/wiki/Domain_Name_System">Domain Name
System</a> to find the
<em>rootiest</em> <a href="https://en.wikipedia.org/wiki/Domain_name">domain name</a>.</p>
<p>First, we use our <a href="https://docs.factorcode.org/content/vocab-dns.html">dns
vocabulary</a> to check that a
host resolves to an IP address:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">valid-domain?</span> <span class="nf">( </span><span class="nv">host</span> <span class="nf">-- </span><span class="nv">?</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> {
</span></span><span class="line"><span class="cl"> [ dns-A-query message>a-names <span class="nb">empty? not </span>]
</span></span><span class="line"><span class="cl"> [ dns-AAAA-query message>aaaa-names <span class="nb">empty? not </span>]
</span></span><span class="line"><span class="cl"> } 1|| <span class="k">;
</span></span></span></code></pre></div><p>And try it out:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"re.factorcode.org"</span> valid-domain? <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span><span class="no">t
</span></span></span><span class="line"><span class="cl"><span class="no"></span>
</span></span><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"not-valid.factorcode.org"</span> valid-domain? <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span><span class="no">f
</span></span></span></code></pre></div><p>Second, we write a word to split a domain into chunks to be tested:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">split-domain</span> <span class="nf">( </span><span class="nv">host</span> <span class="nf">-- </span><span class="nv">hosts</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> <span class="s">"."</span> split <span class="nb">dup length </span><span class="m">1 </span>[-] <iota> [ <span class="nb">tail </span><span class="s">"."</span> <span class="nb">join </span>] <span class="nb">with map </span><span class="k">;
</span></span></span></code></pre></div><p>And try it out:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"a.b.c.com"</span> split-domain <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span>{ <span class="s">"a.b.c.com"</span> <span class="s">"b.c.com"</span> <span class="s">"c.com"</span> }
</span></span></code></pre></div><p>Third, we find the <em>rootiest</em> domain that is <em>valid</em>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="k">:</span> <span class="nf">remove-subdomains</span> <span class="nf">( </span><span class="nv">host</span> <span class="nf">-- </span><span class="nv">host'</span> <span class="nf">)
</span></span></span><span class="line"><span class="cl"><span class="nf"></span> split-domain [ valid-domain? ] <span class="nb">find-last nip </span><span class="k">;
</span></span></span></code></pre></div><p>And try it out:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-factor" data-lang="factor"><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"a.b.c.d.factorcode.org"</span> remove-subdomains <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span><span class="s">"factorcode.org"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">IN:</span> <span class="nn">scratchpad</span> <span class="s">"sorting.cr.yp.to"</span> remove-subdomains <span class="m">.
</span></span></span><span class="line"><span class="cl"><span class="m"></span><span class="s">"cr.yp.to"</span>
</span></span></code></pre></div><p>This is available on my
<a href="https://github.com/mrjbq7/re-factor/blob/master/subdomains/subdomains.factor">GitHub</a>.</p>
<p>It’s fun to explore these kinds of problems!</p>
John Benediktsson: A Language A Day2024-11-04T15:00:00.000000Z<p><a href="https://andrewshitov.com">Andrew Shitov</a> recently <a href="https://andrewshitov.com/2024/11/02/a-language-a-day/">published a
book</a> called “<em>A
Language A Day</em>”, which is a collection of brief overviews to 21 programming
languages – including <a href="https://factorcode.org">Factor</a>!</p>
<p>
<img src="https://re.factorcode.org/images/2024-11-04-a-language-a-day.jpg" alt="" width="600" height="845" />
</p>
<blockquote>
<p>This book provides a concise overview of 21 different programming languages.
Each language is introduced using the same approach: solving several
programming problems to showcase its features and capabilities. Languages
covered in the book: C++, Clojure, Crystal, D, Dart, Elixir, Factor, Go,
Hack, Hy, Io, Julia, Kotlin, Lua, Mercury, Nim, OCaml, Raku, Rust, Scala, and
TypeScript.</p>
<p>Each chapter covers the essentials of a different programming language. To make
the content more consistent and comparable, I use the same structure for each
language, focusing on the following mini projects:</p>
<ol>
<li>Creating a ‘Hello, World!’ program.</li>
<li>Implementing a Factorial function using recursion or a functional-style approach.</li>
<li>Creating a polymorphic array of objects (a ‘zoo’ of cats and dogs) and calling methods on them.</li>
<li>Implementing the Sleep Sort algorithm—while impractical for real-word use, it’s a playful demonstration of language’s concurrency capabilities.</li>
</ol>
<p>Each language description follows—where applicable—this pattern:</p>
<ol>
<li>Installing a command-line compiler and running a program.</li>
<li>Creating and using variables.</li>
<li>Defining and using functions.</li>
<li>Exploring object-oriented features.</li>
<li>Handling exception.</li>
<li>Introducing basic concurrency and parallelism.</li>
</ol>
<p>You can find all the code examples in this book on GitHub:
<a href="https://github.com/ash/a-language-a-day">https://github.com/ash/a-language-a-day</a>.</p>
<p>You can buy it on Amazon or LeanPub as an electronic or Kindle edition, or as a
paper hardcover or paperback version. <a href="https://andrewshitov.com/a-language-a-day/">More information with the links to the
shops</a>.</p>
</blockquote>
<p>Check it out!</p>