<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Posts on Irregularly Scheduled Programming</title>
    <link>https://jcarroll.com.au/post/</link>
    <description>Recent content in Posts on Irregularly Scheduled Programming</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <managingEditor>website@jcarroll.com.au (Jonathan Carroll)</managingEditor>
    <webMaster>website@jcarroll.com.au (Jonathan Carroll)</webMaster>
    <lastBuildDate>Fri, 05 Dec 2025 00:00:00 +0000</lastBuildDate>
    
        <atom:link href="https://jcarroll.com.au/post/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>Haskell IS a Great Language for Data Science</title>
      <link>https://jcarroll.com.au/2025/12/05/haskell-is-a-great-language-for-data-science/</link>
      <pubDate>Fri, 05 Dec 2025 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2025/12/05/haskell-is-a-great-language-for-data-science/</guid>
      <description>&lt;p&gt;I’ve been learning Haskell for a few years now and I am really liking a lot of
the features, not least the strong typing and functional approach. I thought it
was lacking some of the things I missed from R until I found the
&lt;a href=&#34;https://www.datahaskell.org/&#34;&gt;dataHaskell&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;There have been several attempts recently to enhance R with some strong types, e.g. 
&lt;a href=&#34;https://vapour.run/&#34;&gt;vapour&lt;/a&gt;, &lt;a href=&#34;https://github.com/we-data-ch/typr&#34;&gt;typr&lt;/a&gt;, using
&lt;a href=&#34;https://josiahparry.com/posts/2024-06-30-type-safety/&#34;&gt;{rlang}’s checks&lt;/a&gt;, and even
discussions about implementations at the core level e.g. 
&lt;a href=&#34;https://stat.ethz.ch/pipermail/r-devel/2025-September/084164.html&#34;&gt;in September 2025&lt;/a&gt;
continued &lt;a href=&#34;https://stat.ethz.ch/pipermail/r-devel/2025-November/084223.html&#34;&gt;in November 2025&lt;/a&gt;.
While these try to bend R towards types, perhaps an all-in solution makes more sense.&lt;/p&gt;
&lt;p&gt;In this post I’ll demonstrate some of the features and explain why I think it
makes for a good (great?) data science language.&lt;/p&gt;
&lt;p&gt;I’ve posted &lt;a href=&#34;https://jcarroll.com.au/tags/haskell/&#34;&gt;more than a handful of times&lt;/a&gt;
about Haskell but maybe not so much the benefits of a real-world usage, more
toy problems (e.g. I did a lot of Advent of Code using it last year). I’ve been
working towards using it more, and even managed to get a custom {knitr} engine
working - here’s the special sauce that makes a &lt;code&gt;```{haskell}&lt;/code&gt; block work:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;knitr::knit_engines$set(haskell = function(options) {
  code &amp;lt;- options$code
  codefile &amp;lt;- tempfile(fileext = &amp;quot;.hs&amp;quot;)
  codefile_brace &amp;lt;- tempfile(fileext = &amp;quot;.hs&amp;quot;)
  on.exit(file.remove(codefile, codefile_brace))
  writeLines(c(&amp;quot;:script dataframe&amp;quot;, &amp;quot;&amp;quot;, code), con = codefile)
  system2(&amp;#39;hscript&amp;#39;, codefile, stdout = codefile_brace)
  out  &amp;lt;- system2(
    file.path(path.expand(&amp;#39;~&amp;#39;), &amp;#39;.ghcup/bin/ghc&amp;#39;),
    c(&amp;#39;-e&amp;#39;,&amp;quot;&amp;#39;:script &amp;quot;, codefile_brace, &amp;quot;&amp;#39;&amp;quot;),
    stdout = TRUE
  )

  knitr::engine_output(options, code, out)
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This writes the lines of code to a temporary file, prepended with some
configuration options, then runs essentially &lt;code&gt;ghc -e &#39;:script file.txt&#39;&lt;/code&gt; and
deletes the temporary file. For the purposes of making cleaner code blocks, the
code detours through an &lt;a href=&#34;https://github.com/DataHaskell/datahaskell-starter/blob/main/hscript&#34;&gt;&lt;code&gt;awk&lt;/code&gt; script&lt;/a&gt;
which inserts some &lt;code&gt;:{&lt;/code&gt; blocks around
&lt;a href=&#34;https://sanj.ink/posts/2018-08-09-defining-a-multiline-function-in-haskell-using-ghci.html&#34;&gt;multi-line statements&lt;/a&gt;,
helping to reproduce how these look in a Jupyter notebook.
The result is then shown in the code block, so this is a “live” output&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;map (+5) [2..8]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [7,8,9,10,11,12,13]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Neat, right?&lt;/p&gt;
&lt;p&gt;Because I’m treating each code block as an independent script, it means there is
&lt;em&gt;some&lt;/em&gt; repetition between blocks. I’ll hide that away with some judicious &lt;code&gt;echo&lt;/code&gt;
options where necessary, but otherwise each block should be able to be run
as a ‘script’ with the right pre-processing.&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;syntax&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div id=&#34;a-brief-intro-to-haskell-syntax&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;A Brief intro to Haskell Syntax&lt;/h2&gt;
&lt;p&gt;Haskell &lt;em&gt;is&lt;/em&gt; a bit different if you’ve only ever seen R or Python, but it doesn’t
take too much effort to understand what’s going on. Firstly, while parentheses are
used for function calls in R, a space is used in Haskell, so instead of &lt;code&gt;sum(x)&lt;/code&gt;
you use &lt;code&gt;sum x&lt;/code&gt;. Parentheses are still used for grouping together combinations of
things that need to be evaluated together.&lt;/p&gt;
&lt;p&gt;Lists are a fundamental data type and are denoted by square brackets, e.g. &lt;code&gt;[3,4,5]&lt;/code&gt;
and they need to contain a single type. For a strongly typed language, that shouldn’t
come as a surprise. A single number might be of type &lt;code&gt;Double&lt;/code&gt; and a list of these
would be of type &lt;code&gt;[Double]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you’re worried that you’ve become too reliant on a piped workflow, fear not!
dataHaskell’s &lt;a href=&#34;https://dataframe.readthedocs.io/en/latest/&#34;&gt;dataframe&lt;/a&gt; package
adds the familiar pipe operator&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;[2,8,7,10,1,9,5,3,4,6] |&amp;gt;
  reverse |&amp;gt;
  take 5&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [6,4,3,5,9]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with the important distinction that it passes the left side to the &lt;em&gt;end&lt;/em&gt; of the
right side (not to the first argument) which flows cleaner given how Haskell
functions are typically written, e.g.&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;take 3 [1,2,3,4,5,6]

-- vs 

[1,2,3,4,5,6] |&amp;gt;
  take 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1,2,3]
## [1,2,3]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The line in the middle there demonstrates that comments start with two hyphens &lt;code&gt;--&lt;/code&gt;,
or for multi-line comments, between &lt;code&gt;{-&lt;/code&gt; and &lt;code&gt;-}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you need to write a function (for which you use camelCase) you can annotate
it with a definition, though the compiler can figure this out itself most of the
time (plus it helps for readability). The way to do this is with one extra line
above the implementation. If the type is generic, you can use a placeholder e.g. 
&lt;code&gt;a&lt;/code&gt; rather than a &lt;em&gt;specific&lt;/em&gt; type. Technically all functions take only one argument,
possibly returning another function (see &lt;a href=&#34;https://en.wikipedia.org/wiki/Currying&#34;&gt;currying&lt;/a&gt;)
but this is more explicit in the signature; e.g. &lt;code&gt;[a] -&amp;gt; a -&amp;gt; [a]&lt;/code&gt; represents a
function which takes a list and a value and returns a list&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;appendValueToList :: [a] -&amp;gt; a -&amp;gt; [a]
appendValueToList xs y = xs ++ [y]

appendValueToList [2,4,6] 8

appendValueToList [&amp;quot;f&amp;quot;, &amp;quot;o&amp;quot;, &amp;quot;o&amp;quot;] &amp;quot;t&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [2,4,6,8]
## [&#34;f&#34;,&#34;o&#34;,&#34;o&#34;,&#34;t&#34;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The period is used for function composition, i.e.&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;import Data.List (sort)

(reverse . sort) [2,8,7,10,1,9,5,3,4,6]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [10,9,8,7,6,5,4,3,2,1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;applies a composed ‘sort and reverse’ operation to the list. The &lt;code&gt;import&lt;/code&gt; is there
because the ‘base’ library (“Prelude”) doesn’t have the &lt;code&gt;sort&lt;/code&gt; function, so it’s
imported. There’s actually a few of these which need to be imported to use the
code I’m showing below, but it’s inserted into the codeblocks via the &lt;code&gt;:script dataframe&lt;/code&gt;
line in the engine definition above. That calls out to an executable which runs
the code block as if it was contained in a &lt;code&gt;main&lt;/code&gt; function in a full program,
which enables us to use &lt;code&gt;IO&lt;/code&gt; operations inline, such as reading from files and
printing results. That all gets a little trickier without this ‘scripting’ context,
but I’m here to make the point that such a scripting context &lt;em&gt;works well&lt;/em&gt; for
doing data science.&lt;/p&gt;
&lt;p&gt;So, what would one use this for?&lt;/p&gt;
&lt;p&gt;I saw &lt;a href=&#34;https://blog.genesmindsmachines.com/p/python-is-not-a-great-language-for-2e0&#34;&gt;this (follow-up) post&lt;/a&gt;
from Claus Wilke about Python not being a great language for data science and
while I concur with the points made there, I do believe some of them are
personal preference. I’m a proponent of “use the tools you’re comfortable with”
and I can’t argue with however many thousands of data scientists are
successfully using Python to do data science.&lt;/p&gt;
&lt;p&gt;The point about “what makes for a good data science language” made me pause to
think and I came to the conclusion that Haskell actually ticks the boxes, at least
with the &lt;a href=&#34;https://www.datahaskell.org/blog/2025/11/11/welcome-to-datahaskell.html&#34;&gt;dataHaskell ecosystem&lt;/a&gt;
and the dataframe package. What follows is not to
be taken as a pile-on against Python or even a complaint about R, but rather
something in the style of “if you like that, check this out!”&lt;/p&gt;
&lt;p&gt;Lots of languages seem to have some sort of dataframe these days - thanks R! - e.g. 
Python has &lt;a href=&#34;https://pandas.pydata.org/&#34;&gt;Pandas&lt;/a&gt;/&lt;a href=&#34;https://docs.pola.rs/api/python/stable/reference/index.html&#34;&gt;Polars&lt;/a&gt;,
Julia has &lt;a href=&#34;https://dataframes.juliadata.org/stable/&#34;&gt;DataFrames.jl&lt;/a&gt;,
&lt;a href=&#34;https://kotlin.github.io/dataframe/home.html&#34;&gt;even Kotlin has a DataFrame&lt;/a&gt;.
Haskell does, too with &lt;a href=&#34;https://dataframe.readthedocs.io/&#34;&gt;dataframe&lt;/a&gt; and I’ve
been learning how to use this recently.&lt;/p&gt;
&lt;p&gt;The points made in Claus’ post were that the features which make R a better language
for data science over Python are (paraphrasing):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;call-by-value semantics (non-mutability)&lt;/li&gt;
&lt;li&gt;built-in missing values&lt;/li&gt;
&lt;li&gt;built-in vectorization&lt;/li&gt;
&lt;li&gt;non-standard evaluation (NSE)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s look at how Haskell deals with each of these.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;non-mutability&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Non-mutability&lt;/h2&gt;
&lt;p&gt;Claus details how Python’s call-by-reference semantics enables one to modify
variables unintentionally, since they’re scoped across functions. Haskell certainly
doesn’t have this problem - everything is immutable, and functions are “pure” (no
side-effects, though you can interact with typed side-effect ‘instructions’). If you
want to “do” anything to a data object you pass it into a function and get a new
object out. There’s no risk of accidentally modifying a variable, but of course
the downside of this is that you &lt;em&gt;can’t&lt;/em&gt; do so without a function. While in R it’s
straightforward to do&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- c(2, 9, 6)
a[2] &amp;lt;- 4
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 4 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;in Haskell that sort of thing is off limits - you can use an operator to extract
a value from a list (0-indexed), e.g. &lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;a = [2,9,6]

a !! 1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but there’s no way to assign the second element to some other value. Instead,
you need to break the vector apart and stitch the new value inside&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;a = [2,9,6]

updateSecond :: [a] -&amp;gt; a -&amp;gt; [a]
updateSecond (x:_:z) y = x : y : z
updateSecond xs _ = xs

updateSecond a 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [2,4,6]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No risk of accidentally writing that, I’m sure.&lt;/p&gt;
&lt;p&gt;I’ve also included the type definition in this case which reads as “a function
which takes a list of some type &lt;code&gt;a&lt;/code&gt; (&lt;code&gt;[a]&lt;/code&gt;) and a single value of type &lt;code&gt;a&lt;/code&gt; and
returns a list of that same type, &lt;code&gt;[a]&lt;/code&gt;.” FYI, this is one example where you may
need the definition to be enclosed between &lt;code&gt;:{&lt;/code&gt; and &lt;code&gt;:}&lt;/code&gt;, if you’re running
interactively in &lt;code&gt;ghci&lt;/code&gt;, but here I’m using the&lt;br /&gt;
&lt;a href=&#34;https://github.com/DataHaskell/datahaskell-starter/blob/main/hscript&#34;&gt;pre-processing trick&lt;/a&gt;
mentioned above.&lt;/p&gt;
&lt;p&gt;A tick for &lt;em&gt;truly&lt;/em&gt; immutable data - the only way to “alter” a value is to operate
on it with a function and reassign it.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;built-in-missing-values&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Built-in missing values&lt;/h2&gt;
&lt;p&gt;This is somewhere that Haskell shines - if you want a value that &lt;em&gt;might&lt;/em&gt; not be
available in R you use an &lt;code&gt;NA&lt;/code&gt; (which is a shorthand for whichever flavour/class
you actually want, e.g. &lt;code&gt;NA_character_&lt;/code&gt;). Using one of these in any mathematical
calculation ‘poisons’ it and returns &lt;code&gt;NA&lt;/code&gt;, e.g.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sum(1, NA, 3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] NA
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To avoid this, most functions offer a &lt;code&gt;na.rm&lt;/code&gt; argument which instructs to remove
the missing values prior to performing the calculation&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sum(1, NA, 3, na.rm = TRUE)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What’s happening here is that R encodes a value that is &lt;em&gt;maybe&lt;/em&gt; missing. Haskell
formalises this into the &lt;code&gt;Data.Maybe&lt;/code&gt; package and you have to be explicit in
dealing with a missing value (&lt;code&gt;Nothing&lt;/code&gt;) or a definitely-not-missing value (&lt;code&gt;Just x&lt;/code&gt;)&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;non_missing = [1, 2, 3, 4]
has_missing = [Just 1,Just 2,Nothing,Just 4]

:t non_missing
:t has_missing&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## non_missing :: Num a =&gt; [a]
## has_missing :: Num a =&gt; [Maybe a]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where we see that &lt;code&gt;has_missing&lt;/code&gt; is a &lt;code&gt;Maybe&lt;/code&gt; type.&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;sum non_missing&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can’t just &lt;code&gt;sum&lt;/code&gt; the latter; it produces an error because it doesn’t have a
function which can sum a &lt;code&gt;Maybe Integer&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;sum has_missing&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-danger&#34;&gt;&lt;code&gt;s:7:1: error: [GHC-39999]
    • No instance for ‘Num (Maybe Integer)’ arising from a use of ‘it’
    • In the first argument of ‘print’, namely ‘it’
      In a stmt of an interactive GHCi command: print it
  |
7 | sum has_missing
  | ^^^^^^^^^^^^^^^&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;you need to remove any &lt;code&gt;Nothing&lt;/code&gt; first, then most likely ‘unwrap’ from the
&lt;code&gt;Maybe&lt;/code&gt; context&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;import Data.Maybe

sum $ map fromJust $ filter isJust has_missing&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or alternatively&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;sum (catMaybes has_missing) &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or you can get fancy&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;sum [x | Just x &amp;lt;- has_missing]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The point is that you &lt;em&gt;have to&lt;/em&gt; deal with the missingness if it’s there. What this
also means is that if you have a &lt;code&gt;Double&lt;/code&gt; column, it &lt;em&gt;does NOT&lt;/em&gt; have missing values,
so you can safely sum those values (plus get all sorts of performance benefits from
the compiler because it, too, knows there’s no missing values).&lt;/p&gt;
&lt;p&gt;For Claus’ example, we can produce a proper &lt;code&gt;Nothing&lt;/code&gt; at the end of this calculation&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;fmap (fmap (&amp;gt; 3)) x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [Just False,Just False,Nothing,Just True,Just True]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another tick - proper missing values.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;built-in-vectorisation&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Built-in vectorisation&lt;/h2&gt;
&lt;p&gt;Haskell is NOT an array language, so sure, it doesn’t have vectorisation built-in,
but it’s worth noting that at the end of Claus’ post he details some limitations
of R and acknowledges that “R does not have any scalar data types”. Haskell has
scalars, vectors, and arrays, and you need to be specific when you want to iterate
over those - the “type” of a variable includes the dimensionality, so &lt;code&gt;Double&lt;/code&gt; is
not the same as &lt;code&gt;[Double]&lt;/code&gt; (a list of doubles).&lt;/p&gt;
&lt;p&gt;Since Haskell is a functional programming language it has every type of &lt;code&gt;map&lt;/code&gt; you
could want, including specialities for monads and applicatives. While this means
you &lt;em&gt;do&lt;/em&gt; need to write &lt;code&gt;map&lt;/code&gt; when you want to iterate, it also means you’re never
surprised that there was more than one value there.&lt;/p&gt;
&lt;p&gt;What’s more, because it’s a compiled language, the compiler can optimise all sorts
of vector operations. One example is using “fusion” to combine a &lt;code&gt;filter&lt;/code&gt; and a
&lt;code&gt;map&lt;/code&gt; such that the
&lt;a href=&#34;https://www.tweag.io/blog/2017-10-12-vector-package/#array-fusion&#34;&gt;intermediate vector isn’t actually used at all&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This means that a stack of functions like&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;foldr (+) 0 . map (*2) . filter even&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which would naively require a full pass to filter the even values, a half pass
to double those, then anther half pass to add them up, can be done in a single
pass.&lt;/p&gt;
&lt;p&gt;You can also add &lt;a href=&#34;https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/rewrite_rules.html&#34;&gt;rewrite rules&lt;/a&gt;
if you’re sure your replacement holds (and many libraries can assert these
conditions, so implement such rules) so that some operations can be entirely
compiled away. Reversing a finite list twice is a no-op, so takes no time, so
one could add&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{-# RULES
&amp;quot;reverse.reverse/id&amp;quot; reverse . reverse = id
  #-}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which means a double reverse can be replaced with the identity function.&lt;/p&gt;
&lt;p&gt;Even without such a rule, Haskell (being a compiled language) is &lt;em&gt;fast&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;x = [1..1000000000]
:set +s
a = reverse $ reverse x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;(0.00 secs, 0 bytes)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: &lt;a href=&#34;https://functional.cafe/@prophet/115698227419709447&#34;&gt;Alice&lt;/a&gt; helpfully
explains why this runs so fast here - Haskell is lazy, so I wasn’t &lt;em&gt;actually&lt;/em&gt; evaluating
anything there. Trying to calculate the length of the result &lt;em&gt;does&lt;/em&gt; take some
time. Entirely my fault, but this comparison is unfair.&lt;/p&gt;
&lt;p&gt;This is disappointing to run inline in R&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- seq_len(1e9)
system.time(rev(rev(x)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;   user  system elapsed 
  4.596   2.543   8.824 &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ins’t just about compiling; R &lt;em&gt;does&lt;/em&gt; have just-in-time compilation of
functions, but lacks the compiler tricks that Haskell uses, so a compiled
version of this doesn’t do a lot better&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;revrev &amp;lt;- function(x) {
  rev(rev(x))
}
revrev_comp &amp;lt;- compiler::cmpfun(revrev)
system.time(revrev_comp(x))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;   user  system elapsed 
  4.035   0.739   4.777&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, no vectorisation, but possibly enough compiler tricks to make up for it - tick.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;non-standard-evaluation-nse&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Non-standard evaluation (NSE)&lt;/h2&gt;
&lt;p&gt;This is where the fun really starts - the &lt;a href=&#34;https://dataframe.readthedocs.io/en/latest/&#34;&gt;dataframe&lt;/a&gt;
package from the dataHaskell ecosystem adds the sort of slicing and dicing
you’re probably familiar with. Apart from general inspection of data frames&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;df &amp;lt;- D.readParquet &amp;quot;iris.parquet&amp;quot;

D.describeColumns df&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ---------------------------------------------------------
## Column Name  | # Non-null Values | # Null Values |  Type 
## -------------|-------------------|---------------|-------
##     Text     |        Int        |      Int      |  Text 
## -------------|-------------------|---------------|-------
## variety      | 150               | 0             | Text  
## petal.width  | 150               | 0             | Double
## petal.length | 150               | 0             | Double
## sepal.width  | 150               | 0             | Double
## sepal.length | 150               | 0             | Double
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(don’t be fooled by that &lt;code&gt;&amp;lt;-&lt;/code&gt; - that’s Haskell’s way of doing something that reaches
outside of the CPU, e.g. to the disk to read a file) we can use &lt;code&gt;D.dimensions&lt;/code&gt; to get the
overall shape, and more specific helpers like &lt;code&gt;D.nRows&lt;/code&gt; and &lt;code&gt;D.nColumns&lt;/code&gt; are available
which we can incorporate into e.g. text output&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;import Text.Printf (printf)

df &amp;lt;- D.readParquet &amp;quot;iris.parquet&amp;quot;

D.dimensions df

printf &amp;quot;%d rows, %d columns&amp;quot; (D.nRows df) (D.nColumns df)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## (150,5)
## 150 rows, 5 columns
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Many of the &lt;code&gt;dplyr&lt;/code&gt;-esqe operations are available, with a lot of thought put into
how these would interact with a strongly typed structure&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;iris &amp;lt;- D.readParquet &amp;quot;iris.parquet&amp;quot;

iris |&amp;gt; 
  D.filterWhere (F.col @Text &amp;quot;variety&amp;quot; .== &amp;quot;Setosa&amp;quot;) |&amp;gt; 
  D.filterWhere (F.col @Double &amp;quot;sepal.length&amp;quot; .&amp;gt; 5.4)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## -----------------------------------------------------------------
## sepal.length | sepal.width | petal.length | petal.width | variety
## -------------|-------------|--------------|-------------|--------
##    Double    |   Double    |    Double    |   Double    |  Text  
## -------------|-------------|--------------|-------------|--------
## 5.8          | 4.0         | 1.2          | 0.2         | Setosa 
## 5.7          | 4.4         | 1.5          | 0.4         | Setosa 
## 5.7          | 3.8         | 1.7          | 0.3         | Setosa 
## 5.5          | 4.2         | 1.4          | 0.2         | Setosa 
## 5.5          | 3.5         | 1.3          | 0.2         | Setosa
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but dataframe goes one step further via template haskell… you can expose the
columns as variables (admittedly, in the wider scope) so this works&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;iris &amp;lt;- D.readParquet &amp;quot;iris.parquet&amp;quot;

-- make columns available as expressions
:exposeColumns iris

iris |&amp;gt; 
  D.derive &amp;quot;sepal.ratio&amp;quot; (sepal_width / sepal_length) |&amp;gt;
  D.take 5 &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## sepal_length :: Expr Double
## sepal_width :: Expr Double
## petal_length :: Expr Double
## petal_width :: Expr Double
## variety :: Expr Text
## --------------------------------------------------------------------------------------
## sepal.length | sepal.width | petal.length | petal.width | variety |    sepal.ratio    
## -------------|-------------|--------------|-------------|---------|-------------------
##    Double    |   Double    |    Double    |   Double    |  Text   |       Double      
## -------------|-------------|--------------|-------------|---------|-------------------
## 5.1          | 3.5         | 1.4          | 0.2         | Setosa  | 0.6862745098039216
## 4.9          | 3.0         | 1.4          | 0.2         | Setosa  | 0.6122448979591836
## 4.7          | 3.2         | 1.3          | 0.2         | Setosa  | 0.6808510638297872
## 4.6          | 3.1         | 1.5          | 0.2         | Setosa  | 0.673913043478261 
## 5.0          | 3.6         | 1.4          | 0.2         | Setosa  | 0.72
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The info printed prior to the result is the about the exposed columns, and it’s
worth noting that the dots/periods have been replaced by underscores. That’s
because in Haskell the period is used for composition, as described &lt;a href=&#34;#syntax&#34;&gt;above&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Many verbs are supported, so we can do some more detailed transformations&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;iris &amp;lt;- D.readParquet &amp;quot;iris.parquet&amp;quot;

:exposeColumns iris

iris |&amp;gt; 
  D.filterWhere ( sepal_width .&amp;gt; 2.6 ) |&amp;gt;
  D.groupBy [&amp;quot;variety&amp;quot;] |&amp;gt; 
  D.aggregate
      [ &amp;quot;n&amp;quot;       .= F.count petal_length
      , &amp;quot;sl_mean&amp;quot; .= F.mean sepal_length
      , &amp;quot;pl_mean&amp;quot; .= F.mean petal_length
      ]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## sepal_length :: Expr Double
## sepal_width :: Expr Double
## petal_length :: Expr Double
## petal_width :: Expr Double
## variety :: Expr Text
## ---------------------------------------------------------
##  variety   |  n  |      sl_mean      |      pl_mean      
## -----------|-----|-------------------|-------------------
##    Text    | Int |      Double       |       Double      
## -----------|-----|-------------------|-------------------
## Versicolor | 34  | 6.099999999999998 | 4.435294117647058 
## Setosa     | 49  | 5.016326530612244 | 1.4653061224489798
## Virginica  | 43  | 6.651162790697675 | 5.57674418604651
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and remember, because we &lt;em&gt;know&lt;/em&gt; there’s no missing values in a column of &lt;code&gt;Double&lt;/code&gt;s
(not &lt;code&gt;Maybe Double&lt;/code&gt;s) we can take averages without worrying about any &lt;code&gt;na.rm&lt;/code&gt;
complications.&lt;/p&gt;
&lt;p&gt;The NSE bit doesn’t &lt;em&gt;quite&lt;/em&gt; work everywhere, but sometimes a string is just fine, e.g.&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;iris &amp;lt;- D.readParquet &amp;quot;iris.parquet&amp;quot;

D.plotScatter &amp;quot;sepal.length&amp;quot; &amp;quot;sepal.width&amp;quot; iris&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##    4.5│                                                            
##       │                       &lt;span style=&#39;color: #5555FF;&#39;&gt;⠈&lt;/span&gt;                                    
##       │                    &lt;span style=&#39;color: #5555FF;&#39;&gt;⠠&lt;/span&gt;                                       
##       │                &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂&lt;/span&gt;                                           
##       │                   &lt;span style=&#39;color: #5555FF;&#39;&gt;⡀&lt;/span&gt;     &lt;span style=&#39;color: #5555FF;&#39;&gt;⠁&lt;/span&gt;                                  
##       │              &lt;span style=&#39;color: #5555FF;&#39;&gt;⠠&lt;/span&gt;        &lt;span style=&#39;color: #5555FF;&#39;&gt;⠠&lt;/span&gt;                              &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;  
##       │              &lt;span style=&#39;color: #5555FF;&#39;&gt;⠐&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠐&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂&lt;/span&gt;                                        
##       │       &lt;span style=&#39;color: #5555FF;&#39;&gt;⠁&lt;/span&gt;   &lt;span style=&#39;color: #5555FF;&#39;&gt;⠈&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⡁⢀&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⡀&lt;/span&gt;   &lt;span style=&#39;color: #5555FF;&#39;&gt;⢀&lt;/span&gt;                         &lt;span style=&#39;color: #5555FF;&#39;&gt;⠈&lt;/span&gt;             
##       │       &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄⠠&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;        &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠠&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;                          
##       │    &lt;span style=&#39;color: #5555FF;&#39;&gt;⡀&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⡀⢀&lt;/span&gt;    &lt;span style=&#39;color: #5555FF;&#39;&gt;⡂⠐&lt;/span&gt;           &lt;span style=&#39;color: #5555FF;&#39;&gt;⢀&lt;/span&gt;      &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂⢀&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⡀&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂⢀&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⡀⢀&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⢀&lt;/span&gt;             
##    3.2│       &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄⠠&lt;/span&gt;                      &lt;span style=&#39;color: #5555FF;&#39;&gt;⠠&lt;/span&gt;    &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;                 
##       │  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠐&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂&lt;/span&gt;     &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂⠐&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂&lt;/span&gt;     &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂⠐&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠐&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂⠐&lt;/span&gt;      &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂⠐&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂⠐&lt;/span&gt;    &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂⠐&lt;/span&gt;     &lt;span style=&#39;color: #5555FF;&#39;&gt;⠐&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂&lt;/span&gt;     
##       │    &lt;span style=&#39;color: #5555FF;&#39;&gt;⠁&lt;/span&gt;                 &lt;span style=&#39;color: #5555FF;&#39;&gt;⡁⢈&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⡀&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠁⢈&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⢈&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⡁⢈&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⡀⠈&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⢀&lt;/span&gt;       &lt;span style=&#39;color: #5555FF;&#39;&gt;⠁⢀&lt;/span&gt;    &lt;span style=&#39;color: #5555FF;&#39;&gt;⡀&lt;/span&gt;     
##       │                &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;     &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;    &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄⠠&lt;/span&gt;                         
##       │                    &lt;span style=&#39;color: #5555FF;&#39;&gt;⠐&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠐&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂&lt;/span&gt;   &lt;span style=&#39;color: #5555FF;&#39;&gt;⠐&lt;/span&gt;                        &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂&lt;/span&gt;     
##       │           &lt;span style=&#39;color: #5555FF;&#39;&gt;⢈&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠈&lt;/span&gt;     &lt;span style=&#39;color: #5555FF;&#39;&gt;⢈&lt;/span&gt; &lt;span style=&#39;color: #5555FF;&#39;&gt;⠁⠈&lt;/span&gt;         &lt;span style=&#39;color: #5555FF;&#39;&gt;⠁&lt;/span&gt;     &lt;span style=&#39;color: #5555FF;&#39;&gt;⠁&lt;/span&gt;                    
##       │     &lt;span style=&#39;color: #5555FF;&#39;&gt;⠠&lt;/span&gt;       &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;      &lt;span style=&#39;color: #5555FF;&#39;&gt;⠠&lt;/span&gt;            &lt;span style=&#39;color: #5555FF;&#39;&gt;⠄&lt;/span&gt;                          
##       │                            &lt;span style=&#39;color: #5555FF;&#39;&gt;⠂&lt;/span&gt;  &lt;span style=&#39;color: #5555FF;&#39;&gt;⠐&lt;/span&gt;                            
##       │             &lt;span style=&#39;color: #5555FF;&#39;&gt;⡀&lt;/span&gt;                                              
##    1.9│                                                            
##       └────────────────────────────────────────────────────────────
##        4.1                           6.1                          8.1
## 
## &lt;span style=&#39;color: #5555FF;&#39;&gt;⣿&lt;/span&gt; sepal.length vs sepal.width
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(following &lt;a href=&#34;https://blog.djnavarro.net/posts/2021-04-18_pretty-little-clis/&#34; class=&#34;uri&#34;&gt;https://blog.djnavarro.net/posts/2021-04-18_pretty-little-clis/&lt;/a&gt; to get
the ANSI sequences to work in a code block).&lt;/p&gt;
&lt;p&gt;A more detailed comparison to &lt;code&gt;dplyr&lt;/code&gt; is provided in
&lt;a href=&#34;https://dataframe.readthedocs.io/en/latest/coming_from_other_implementations.html#coming-from-dplyr&#34;&gt;the dataframe documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So, NSE? Tick!&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;conclusion&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I’ve hopefully demonstrated some of the power of a strongly typed language and
a package focused on data science enabling the sort of functionality that an
R (or Python) user might be looking for. I am hopeful that Haskell (and the
dataHaskell ecosystem) can be a viable option for those of us wanting to do
data science in a strongly typed language with a very clever compiler capable
of making significant performance improvements.&lt;/p&gt;
&lt;p&gt;If you’re interested in dataHaskell then check out
&lt;a href=&#34;https://www.datahaskell.org/blog/2025/11/11/welcome-to-datahaskell.html&#34;&gt;this post&lt;/a&gt;
and consider taking it for a spin - we’re working on reducing friction to get
started via devcontainers and hosted notebook solutions, and are keen to hear from
more data scientists about what they’d like the ecosystem to be able to support.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I believe Haskell IS a great language for data science!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As always, I can be found on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; and the comment section below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &lt;span style=&#39;color: #00BBBB; font-weight: bold;&#39;&gt;─ Session info ───────────────────────────────────────────────────────────────&lt;/span&gt;
##  &lt;span style=&#39;color: #555555; font-style: italic;&#39;&gt;setting &lt;/span&gt; &lt;span style=&#39;color: #555555; font-style: italic;&#39;&gt;value&lt;/span&gt;
##  version  R version 4.4.1 (2024-06-14)
##  os       macOS 15.6.1
##  system   aarch64, darwin20
##  ui       X11
##  language (EN)
##  collate  en_US.UTF-8
##  ctype    en_US.UTF-8
##  tz       Australia/Adelaide
##  date     2025-12-16
##  pandoc   3.8.2.1 @ /opt/homebrew/bin/ (via rmarkdown)
##  quarto   1.7.31 @ /usr/local/bin/quarto
## 
## &lt;span style=&#39;color: #00BBBB; font-weight: bold;&#39;&gt;─ Packages ───────────────────────────────────────────────────────────────────&lt;/span&gt;
##  &lt;span style=&#39;color: #555555; font-style: italic;&#39;&gt;package    &lt;/span&gt; &lt;span style=&#39;color: #555555; font-style: italic;&#39;&gt;*&lt;/span&gt; &lt;span style=&#39;color: #555555; font-style: italic;&#39;&gt;version&lt;/span&gt; &lt;span style=&#39;color: #555555; font-style: italic;&#39;&gt;date (UTC)&lt;/span&gt; &lt;span style=&#39;color: #555555; font-style: italic;&#39;&gt;lib&lt;/span&gt; &lt;span style=&#39;color: #555555; font-style: italic;&#39;&gt;source&lt;/span&gt;
##  blogdown      1.21.1  &lt;span style=&#39;color: #555555;&#39;&gt;2025-06-28&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #BB00BB; font-weight: bold;&#39;&gt;Github (rstudio/blogdown@33313a5)&lt;/span&gt;
##  bookdown      0.41    &lt;span style=&#39;color: #555555;&#39;&gt;2024-10-16&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  bslib         0.9.0   &lt;span style=&#39;color: #555555;&#39;&gt;2025-01-30&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  cachem        1.1.0   &lt;span style=&#39;color: #555555;&#39;&gt;2024-05-16&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.0)&lt;/span&gt;
##  cli           3.6.5   &lt;span style=&#39;color: #555555;&#39;&gt;2025-04-23&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  devtools      2.4.6   &lt;span style=&#39;color: #555555;&#39;&gt;2025-10-03&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  digest        0.6.38  &lt;span style=&#39;color: #555555;&#39;&gt;2025-11-12&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  ellipsis      0.3.2   &lt;span style=&#39;color: #555555;&#39;&gt;2021-04-29&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.0)&lt;/span&gt;
##  evaluate      1.0.5   &lt;span style=&#39;color: #555555;&#39;&gt;2025-08-27&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  fansi         1.0.7   &lt;span style=&#39;color: #555555;&#39;&gt;2025-11-19&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.3)&lt;/span&gt;
##  fastmap       1.2.0   &lt;span style=&#39;color: #555555;&#39;&gt;2024-05-15&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.0)&lt;/span&gt;
##  fs            1.6.6   &lt;span style=&#39;color: #555555;&#39;&gt;2025-04-12&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  glue          1.8.0   &lt;span style=&#39;color: #555555;&#39;&gt;2024-09-30&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  htmltools     0.5.8.1 &lt;span style=&#39;color: #555555;&#39;&gt;2024-04-04&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.0)&lt;/span&gt;
##  jquerylib     0.1.4   &lt;span style=&#39;color: #555555;&#39;&gt;2021-04-26&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.0)&lt;/span&gt;
##  jsonlite      2.0.0   &lt;span style=&#39;color: #555555;&#39;&gt;2025-03-27&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  knitr         1.50    &lt;span style=&#39;color: #555555;&#39;&gt;2025-03-16&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  lifecycle     1.0.4   &lt;span style=&#39;color: #555555;&#39;&gt;2023-11-07&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.0)&lt;/span&gt;
##  magrittr      2.0.4   &lt;span style=&#39;color: #555555;&#39;&gt;2025-09-12&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  memoise       2.0.1   &lt;span style=&#39;color: #555555;&#39;&gt;2021-11-26&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.0)&lt;/span&gt;
##  pkgbuild      1.4.8   &lt;span style=&#39;color: #555555;&#39;&gt;2025-05-26&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  pkgload       1.4.1   &lt;span style=&#39;color: #555555;&#39;&gt;2025-09-23&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  purrr         1.2.0   &lt;span style=&#39;color: #555555;&#39;&gt;2025-11-04&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  R6            2.6.1   &lt;span style=&#39;color: #555555;&#39;&gt;2025-02-15&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  remotes       2.5.0   &lt;span style=&#39;color: #555555;&#39;&gt;2024-03-17&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  rlang         1.1.6   &lt;span style=&#39;color: #555555;&#39;&gt;2025-04-11&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  rmarkdown     2.30    &lt;span style=&#39;color: #555555;&#39;&gt;2025-09-28&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  rstudioapi    0.17.1  &lt;span style=&#39;color: #555555;&#39;&gt;2024-10-22&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  sass          0.4.10  &lt;span style=&#39;color: #555555;&#39;&gt;2025-04-11&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  sessioninfo   1.2.3   &lt;span style=&#39;color: #555555;&#39;&gt;2025-02-05&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  usethis       3.2.1   &lt;span style=&#39;color: #555555;&#39;&gt;2025-09-06&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  vctrs         0.6.5   &lt;span style=&#39;color: #555555;&#39;&gt;2023-12-01&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.0)&lt;/span&gt;
##  xfun          0.54    &lt;span style=&#39;color: #555555;&#39;&gt;2025-10-30&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.1)&lt;/span&gt;
##  yaml          2.3.10  &lt;span style=&#39;color: #555555;&#39;&gt;2024-07-26&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;[1]&lt;/span&gt; &lt;span style=&#39;color: #555555;&#39;&gt;CRAN (R 4.4.0)&lt;/span&gt;
## 
## &lt;span style=&#39;color: #555555;&#39;&gt; [1] /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/library&lt;/span&gt;
## 
## &lt;span style=&#39;color: #00BBBB; font-weight: bold;&#39;&gt;──────────────────────────────────────────────────────────────────────────────&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>I Vibe Coded an R Package</title>
      <link>https://jcarroll.com.au/2025/09/13/i-vibe-coded-an-r-package/</link>
      <pubDate>Sat, 13 Sep 2025 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2025/09/13/i-vibe-coded-an-r-package/</guid>
      <description>&lt;p&gt;Learning Japanese means memorizing thousands of characters, some of which look
nearly identical. I wanted a way to visualize which kanji are similar to each
other, and for once there wasn’t an R package for this, so I built one using
Claude Code for $20 and an afternoon’s work. I got a fully-documented package
with mocked tests, complete API coverage, caching, and graph visualizations.&lt;/p&gt;
&lt;p&gt;I won’t keep you in suspense - here’s the result:&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/network.png&#34; width=&#34;800&#34; alt=&#34;Network diagram of kanji similar to 年 (year)&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Network diagram of kanji similar to 年 (year)&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This is exactly what I wanted - a way to explore visually similar kanji in
Japanese and identify the differences between them so I could better remember
which is which. I barely wrote any of the code to make it happen, and I couldn’t
be happier with it.&lt;/p&gt;
&lt;div id=&#34;how-did-i-get-here&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;How did I get here?&lt;/h3&gt;
&lt;p&gt;I’ve been learning Japanese since my daughter took it up when starting high
school at the start of last year, and I figured we could learn together. My main
resource is &lt;a href=&#34;https://www.duolingo.com/&#34;&gt;Duolingo&lt;/a&gt;, which I think is okay, but
not brilliant. My ‘Duolingo Japanese Score’ is 72 with a 625 day streak. I’m on
Section 5 unit 27, and there’s only one Section left after this.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/duolingo1.png&#34; width=&#34;600&#34; alt=&#34;My Duolingo stats&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;My Duolingo stats&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/duolingo2.png&#34; width=&#34;400&#34; alt=&#34;My Duolingo progress&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;My Duolingo progress&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So I’m a lot of the way through the course, but it doesn’t actively &lt;em&gt;teach&lt;/em&gt; me
anything; it’s purely by example, which I suppose is how children learn their
native language, but it is pretty slow going for remembering what things mean. I
bought some grammar books which are enlightening and I frequently say “Oh,
that’s why they did that!”&lt;/p&gt;
&lt;p&gt;I was recommended to try &lt;a href=&#34;https://www.wanikani.com/&#34;&gt;WaniKani&lt;/a&gt;, which uses
spaced-repetition to teach the radicals, kanji, and vocabulary and provides
mnemonics to help remember which things mean what. I’ve found that extremely
useful for my Duolingo-based learning because now I can sometimes recognise what
a word might mean based on what I’ve learned in WaniKani and that helps me at
least get closer to which word is correct.&lt;/p&gt;
&lt;p&gt;WaniKani is free until you clear level 3 after which it’s paid, but I found it
so useful I paid for a subscription and am now on level 8. There are 60 levels,
and the first 10 are labelled “pleasant”, the next 10 “painful”, followed by
“death”, then “hell”, so I’m not nearly through even the easy bit yet.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/wanikani.png&#34; width=&#34;600&#34; alt=&#34;My WaniKani progress&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;My WaniKani progress&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;One of the complexities with Japanese language (and Chinese) is that part of the
writing system is logographic (meaning-based, rather than phonemic, based on
alphabets) and there are thousands of characters all with multiple meanings and
multiple readings. Some of them look extremely similar to each other even though
they refer to completely different things. The words for “dog” 犬 and “big” 大 and
“fat” 太 differ by one little stroke which is easy to confuse. In the end, you
just have to know which one is which, but I wanted to be able to compare which
things are similar.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;prior-art&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Prior Art&lt;/h3&gt;
&lt;p&gt;Alex Chan’s excellent 2020 post &lt;a href=&#34;https://alexwlchan.net/2020/storing-language-vocabulary-as-a-graph/&#34;&gt;Storing language vocabulary as a
graph&lt;/a&gt;
explored a cool idea about linking together words that look similar or have
similar components in Chinese, and I wanted to do something like that for
Japanese. I’ve had the idea floating in the back of my mind since I read that
post, but I had no idea how I was going to build it.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/vocab_graph_2x.avif&#34; width=&#34;600&#34; alt=&#34;Alex Chan’s network graph of Chinese text&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Alex Chan’s network graph of Chinese text&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;One option was just to ask an AI model every time I was confused about things
and get it to produce the answer, but this seemed both wasteful and potentially
just slow and annoying (or at worst, plain old wrong). I gave it a go, and I
think it does some of what I need to, but I’d rather build something I have some
faith in that I can query on demand without having to go and fetch an AI answer
every time.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/claude.png&#34; width=&#34;600&#34; alt=&#34;Claude answering a question about similar kanji&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Claude answering a question about similar kanji&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;(oh, so “dog” 犬 has an extra “dot” compared to “big” 大 … that certainly won’t
come to mind when I see “fat” 太. Also, what “additional horizontal line”???)&lt;/p&gt;
&lt;p&gt;WaniKani does give you this ‘visually similar’ information when it shows you the
kanji, and I figured maybe I can use that data to build out a graph.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/similar.png&#34; width=&#34;600&#34; alt=&#34;WaniKani’s ‘visually similar’ panel&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;WaniKani’s ‘visually similar’ panel&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;how-hard-could-it-be&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;How Hard Could It Be?&lt;/h3&gt;
&lt;p&gt;I had a look around and couldn’t find any R packages that did what I wanted. I
didn’t search other programming languages; maybe there’s something in Python?
There was &lt;a href=&#34;https://github.com/ZenBrayn/wanikanir&#34;&gt;one WaniKani API package&lt;/a&gt;
&lt;code&gt;{wanikanir}&lt;/code&gt; (on GitHub, not CRAN) that was a bit out of date from 7 years ago.
I couldn’t use that as-is and I couldn’t find another WaniKani API package.&lt;/p&gt;
&lt;p&gt;I did find Dominic Schuhmacher’s
&lt;a href=&#34;https://github.com/dschuhmacher/kanjistat/&#34;&gt;package&lt;/a&gt; for comparing or looking
up kanji. But that doesn’t do the similarity analysis that I wanted. The
WaniKani API exists and that’s what &lt;a href=&#34;https://github.com/jerryhcooke/smouldering_durtles&#34;&gt;Smouldering Durtles&lt;/a&gt; (the unofficial
Android app I occasionally use to view my progress) uses behind the scenes. All
I needed was a way to query it.&lt;/p&gt;
&lt;p&gt;I started by trying to fetch the data myself. I &lt;a href=&#34;https://www.wanikani.com/settings/personal_access_tokens&#34;&gt;got my API
key&lt;/a&gt;, looked up the
&lt;a href=&#34;https://docs.api.wanikani.com/&#34;&gt;documentation&lt;/a&gt;, figured out what I needed to
fetch, and then tweaked &lt;code&gt;{wanikanir}&lt;/code&gt; to use &lt;code&gt;{httr2}&lt;/code&gt; (with pagination) and
query the data via the up-to-date endpoint. I got the results as a giant JSON
blob, so I needed to dive into what was in there.&lt;/p&gt;
&lt;p&gt;I had to parse out the different pieces that I wanted, which was the internal
IDs, the kanji, their readings, their meanings, and then the similarities (which
just returns another list of IDs to look up). I ended up staying up until about
1am that night and &lt;em&gt;only just&lt;/em&gt; managed to get the actual data in the form of a
table that I could look at and maybe see that it would have the pieces that I
needed, but this was going to take a very long time.&lt;/p&gt;
&lt;p&gt;Here’s where I got to after an entire evening hacking away&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# get all the kanji
kanji &amp;lt;- wanikanir::get_wk_data_by_name(&amp;quot;subjects&amp;quot;, opt_arg = &amp;quot;kanji&amp;quot;)

# map meaning, readings, level, and similar ids
kanji_maps &amp;lt;- purrr::map_df(
  seq_along(kanji),
  ~ data.frame(
    id = kanji[[.x]]$id,
    type = kanji[[.x]]$object,
    kanji = kanji[[.x]]$data$characters %||% NA,
    meanings = purrr::map_chr(kanji[[.x]]$data$meanings, ~ .x$meaning),
    readings = paste(
      purrr::map(kanji[[.x]]$data$readings, ~ .x$reading),
      collapse = &amp;quot; / &amp;quot;
    ),
    level = kanji[[.x]]$data$level,
    similar = toString(unlist(
      kanji[[.x]]$data$visually_similar_subject_ids
    )) %||%
      NA
  )
) |&amp;gt;
  dplyr::arrange(id, level)
  
dplyr::slice_sample(kanji_maps[kanji_maps$level &amp;lt; 10, ], n=10)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;#      id       type kanji        meanings          readings level         similar
# 1  8664 vocabulary  番組         Program          ばんぐみ     8                
# 2  2657 vocabulary    字 Kanji Character                じ     3                
# 3   644      kanji    食            Meal  しょく / た / く     6             805
# 4   690      kanji    者        Somebody       しゃ / もの     8                
# 5   685      kanji    役            Duty       やく / えき     8 686, 2304, 2118
# 6  2795 vocabulary  空気            Mood            くうき     5                
# 7  3109 vocabulary  名物  Famous Product          めいぶつ     9                
# 8  2570 vocabulary  日本           Japan にほん / にっぽん     2                
# 9  2539 vocabulary  上手      Skilled At          じょうず     2                
# 10 2602 vocabulary  大切        Valuable          たいせつ     3         &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just in case that’s of use to anyone, I’ve updated my fork with these changes
and it now passes &lt;code&gt;devtools::check()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/jonocarroll/wanikanir&#34; class=&#34;uri&#34;&gt;https://github.com/jonocarroll/wanikanir&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This was still a long way off from what I needed it to do, though.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;get-to-work-agent&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Get To Work, Agent&lt;/h3&gt;
&lt;p&gt;A couple of days later, I’d been watching some videos on &lt;a href=&#34;https://www.anthropic.com/claude-code&#34;&gt;Claude Code&lt;/a&gt;, in particular starting it up in
the base directory of an &lt;a href=&#34;https://obsidian.md/&#34;&gt;Obsidian&lt;/a&gt; vault full of markdown
files which seems to be &lt;em&gt;very&lt;/em&gt; powerful, e.g. this video which demonstrates lots
of Claude Code’s abilities&lt;/p&gt;
&lt;div align=&#34;center&#34;&gt;
&lt;iframe width=&#34;420&#34; height=&#34;315&#34; src=&#34;https://www.youtube.com/embed/d7Pb73dbcIM&#34;&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&#34;figcaption&#34;&gt;
How to 10x your notes with AI agents
&lt;/div&gt;
&lt;p&gt;and decided to take it for a proper spin. I’ve previously tried using &lt;a href=&#34;https://ampcode.com/&#34;&gt;Amp&lt;/a&gt; to vibe code something – Geoff Huntley &lt;a href=&#34;https://ghuntley.com/agent/&#34;&gt;demonstrated that&lt;/a&gt; at &lt;a href=&#34;https://dataengbytes.com/&#34;&gt;DataEngBytes&lt;/a&gt;
and while I don’t necessarily agree with everything he said, the take-away that
“developers need to be aware of (and familiar with) these tools” really stuck
with me.&lt;/p&gt;
&lt;p&gt;The Agentic workflow works quite nicely for iterating by itself if it can run
tools (e.g. via &lt;code&gt;bash&lt;/code&gt;) so I can trust that it’ll run the tests, build the docs,
and commit all of the code only when everything passes.&lt;/p&gt;
&lt;p&gt;I loaded up Claude Code, gave it some funds, and tried to see how productive
this is going to be. The entire prompt, not even using the &lt;code&gt;/init&lt;/code&gt; setup, was
just&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Build an R package that uses this API &lt;a href=&#34;https://docs.api.wanikani.com/&#34; class=&#34;uri&#34;&gt;https://docs.api.wanikani.com/&lt;/a&gt;. Support
all the endpoints. Add documentation and tests and make sure it passes check”.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and off it went and started building. It made a plan for what it needed to do to
build the package:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It needed to query the API&lt;/li&gt;
&lt;li&gt;It needed to figure out which functions to use&lt;/li&gt;
&lt;li&gt;It needed to write documentation and tests&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;☒ Examine WaniKani API documentation to understand endpoints
☒ Create R package structure and configuration files
☒ Implement core API client functions
☒ Create functions for each API endpoint
☒ Add comprehensive documentation with roxygen2
☒ Write tests with mocking using testthat and httptest
☐ Create package vignette with usage examples&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then it just went step-by-step and ticked off things on its to-do list.&lt;/p&gt;
&lt;p&gt;I’ll point out at this point that the recent videos I’d seen — as well as
Geoff’s presentation — used voice dictation. So I installed Wispr Flow, and it
gave me two weeks of pro-level usage, which means I can just talk to my computer
about what I wanted to do. I’m pretty happy with how this is working, and in
fact I dictated most of this article as a draft. I don’t let any AI write my
blog posts for me; &lt;strong&gt;this is definitely me&lt;/strong&gt; writing all of this — even if I do
use an em-dash or two. But Wispr Flow seems pretty cool. If you want to give it
a go, here’s a referral code&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://wisprflow.ai/r?JONATHAN746&#34;&gt;wisprflow.ai/r?JONATHAN746&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;that I think gives you two weeks of full pro-level usage, and in theory if I end
up keeping on using this, gives me some free weeks too.&lt;/p&gt;
&lt;p&gt;Once it was done, Claude Code had queried the API documentation page, found all
of the endpoints, and then built an entire R package with modern approaches that
queries the endpoints using &lt;code&gt;{httr2}&lt;/code&gt;. This is exactly what I would have done
myself if I’d spent a &lt;em&gt;lot&lt;/em&gt; more time with it. It added documentation for all of
the functions and a set of mocked tests using &lt;code&gt;{httptest}&lt;/code&gt;. It confirmed that it
passed &lt;code&gt;devtools::check()&lt;/code&gt; by actually running it from the command line and
fixing any errors that came up.&lt;/p&gt;
&lt;p&gt;I wanted to make sure that it was clear when I was “doing an AI” and when I was
doing my own work, so as part of my initial instructions to Claude Code, I told
it that any time it commits, it needs to have “(claude)” in the commit message.
This might have been redundant because it adds itself as a co-author, so all of
the commits show “co-authored by Claude” in GitHub if it was involved, but I
think it’s worthwhile calling it out in the commit messages.&lt;/p&gt;
&lt;p&gt;I had everything that I needed to get started actually pulling some data, so I
gave it a subset of the JSON output that I’d manually extracted the other day
and said that I wanted to be able to reproduce this. It built a function that
queried the data according to all of the things that it had found/built so far
and built the exact same table that I’d spent my entire evening building, but
now the package could do everything else as well. It also wrote a vignette of
basic usage that keeps track of all the things it can do. Here I think it’s a
little less competent in terms of writing documentation that shows how to use
something, but these models aren’t necessarily great at knowing the intention of
what you’re trying to do.&lt;/p&gt;
&lt;p&gt;One of the problems that I found from manually inspecting the data was that the
‘visually similar’ component (the bit that I actually want) returned a list of
IDs, but I wanted to get the actual kanji that were related so that I could see
them on the network graph. So again, I just asked Claude Code to resolve those
so that we have the actual names and meanings, and that’s where it did something
a little bit wrong; it started querying the API again for each character that it
needed to look up. But Claude Code lets you interrupt and change course, so I
interrupted it and told it to use the data it already had, and it cheerfully
agreed (I’m sure we’re all sick of hearing “You’re absolutely right!”). Now, for
each kanji I get any similar kanji and their meaning.&lt;/p&gt;
&lt;p&gt;The last piece is to actually show this on a network graph. Again, I’m not going
to be writing any of the code here, so I just asked it to build me a function
that queries for any one kanji and shows all of the related ones in either
direction up to some depth. It went off and built that, and again, it works. It
added tests. It made sure that it passed check and added documentation and
examples to the README and vignette. When I started testing it out, I realised
that I had to actually paste in kanji, which isn’t the interface that I
necessarily wanted, so I asked it to modify the function to optionally use the
English word and just search for that in the meanings.&lt;/p&gt;
&lt;p&gt;At the end of this round of development it’s a fully working package with 133
passing tests and no failures&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/tests.png&#34; width=&#34;350&#34; alt=&#34;Passing 133 tests&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Passing 133 tests&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;These tests cover functions which call out to the API, and they’re all mocked so
that an API key (or network access) isn’t actually needed - this is probably the
approach I should take for other API packages, so this also serves as a useful
example for me to learn from.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;devtools::check()&lt;/code&gt; succeeds with no errors or warnings and only two NOTES
related to having a bit too large data and a &lt;code&gt;figures&lt;/code&gt; directory for the vignette&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/check.png&#34; width=&#34;500&#34; alt=&#34;Passing check() with only minor NOTES&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Passing check() with only minor NOTES&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The package is here in case anyone’s interested:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/jonocarroll/rwanikani&#34; class=&#34;uri&#34;&gt;https://github.com/jonocarroll/rwanikani&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;and if I find any new features I’ll continue to add to this.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;functionality&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Functionality&lt;/h3&gt;
&lt;p&gt;Now I can query for ‘water’ either by the kanji 水 or by the English word “water”.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/network2.png&#34; width=&#34;800&#34; alt=&#34;Searching for similar kanji to ‘water’ 水&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Searching for similar kanji to ‘water’ 水&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Looking through the vignette of what it was able to do, it had some extra
wrapper functions around the raw data that it fetched, so I asked it to
integrate them into the actual functions so that they didn’t just return raw
data. One of the things it can do now is fetch the worst mistakes that I’ve made
in WaniKani so that I can review those&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# ---8&amp;lt;--- from vignette 
analyze_progress()&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;=== Review Statistics Summary ===

Total subjects with reviews: 500 
Average meaning accuracy: 91.9% 
Average reading accuracy: 89.4% 

Meaning Accuracy Distribution:
  0-50%: 0 subjects
  51-70%: 0 subjects
  71-80%: 46 subjects
  81-90%: 161 subjects
  91-100%: 293 subjects

Subjects That Need Most Practice:
  1. 出 (Exit) - 72% [Level 2 Kanji]
  2. 少女 (Girl, Young Girl) - 72% [Level 3 Vocabulary]
  3. 年中 (Year Round, All Year, Whole Year, Throughout The Year) - 72% [Level 4 Vocabulary]
  4. 去年 (Last Year) - 72% [Level 4 Vocabulary]
  5. 村人 (Villager) - 75% [Level 4 Vocabulary]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(most of my errors are “spelling”-related; is it “しゅう” or “しょう”?)&lt;/p&gt;
&lt;p&gt;and my level progress&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;wk_print_level_progression_summary(wk_level_progressions(all_pages = TRUE))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;=== Level Progression Summary ===

Total levels tracked: 8 
Levels completed: 0 
Levels passed (not completed): 7 
Levels in progress: 1 

Passing Time Statistics:
  Average days to pass: 25.5 
  Median days to pass: 21.2 
  Fastest level passed: 10.1 days
  Slowest level passed: 48.6 days

Individual Level Progress:
   Level 1 - passed in 13 days 
   Level 2 - passed in 10.1 days 
   Level 3 - passed in 24 days 
   Level 4 - passed in 21.2 days 
   Level 5 - passed in 13.7 days 
   Level 6 - passed in 47.8 days 
   Level 7 - passed in 48.6 days 
   Level 8 - in progress &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(I’m slowing down, but it’s definitely getting harder to keep up)&lt;/p&gt;
&lt;p&gt;Since it can query all of this from WaniKani, I thought maybe I’d do something a
bit similar to what is in there and on-demand build a card for each character
(either radical, kanji, or vocab) to show the readings and the name and the
similar kanji independent of the network graph, especially for kanji containing
radicals.&lt;/p&gt;
&lt;p&gt;At this point, I realised that every time it went and fetched all of this data
it was fetching directly from the API, so I asked it to add a caching layer that
fetched all of the kanji once and stored it with the package, reloading whenever
necessary and referring to that. Again, it did it. So now it used the cache of
that data and could look up all of it, and when I checked what was actually in
that cache it was the full raw JSON processed data, so now it could fetch
everything, not just the pieces that I was interested in. It built the cards and
they look amazing - it would’ve taken me a while to figure out the CSS styling
of this; definitely not impossible but so much easier to just ask and have it
done.&lt;/p&gt;
&lt;p&gt;Just look at these!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wk_create_character_card(&amp;quot;水&amp;quot;)
wk_create_character_card(&amp;quot;氷&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/cards.png&#34; width=&#34;600&#34; alt=&#34;Character cards for ‘water’ radical 水 and ‘ice’ kanji 氷&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Character cards for ‘water’ radical 水 and ‘ice’ kanji 氷&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Oh, and is everyone using the new ‘Minimalist Async Evaluation Framework for R’
&lt;a href=&#34;https://mirai.r-lib.org/&#34;&gt;mirai&lt;/a&gt;? みらい 未来&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wk_create_character_card(&amp;quot;未来&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/mirai.png&#34; width=&#34;300&#34; alt=&#34;Character card for ‘mirai’ (future) 未来&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Character card for ‘mirai’ (future) 未来&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The package has everything that I wanted it to do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;queries all of the endpoints on WaniKani&lt;/li&gt;
&lt;li&gt;shows the meaning and definition for kanji&lt;/li&gt;
&lt;li&gt;shows how they’re related in a network graph&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’m &lt;em&gt;extremely&lt;/em&gt; happy. I let it do all the committing and pushed it to Github. I
added the &lt;code&gt;{pkgdown}&lt;/code&gt; docs to actually render things, and dealt with the issue
of having to pre-render the vignette because it needs an API key. Apart from
that, I had all of this done in a matter of hours. Now that’s not to say that
this is just free and easy for everyone; I did spend about US$20 on building
this and that included an about an hour of API time. But these things are
constantly getting better, and they’re getting cheaper. Honestly I would’ve
spent a week building these components myself, so I think that’s a pretty good
deal. A thing that didn’t exist before now exists, and all it took was one
person spending $20 and connecting up their thoughts of what they wanted to a
capable system.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Total cost:            $20.06
Total duration (API):  1h 13m 18.5s
Total code changes:    5605 lines added, 750 lines removed
Usage by model:
      claude-sonnet:  813 input, 170.6k output, 38.0m cache read, 1.6m cache write
	    claude-3-5-haiku:  284.2k input, 7.3k output, 0 cache read, 0 cache write&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;putting-it-to-use&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Putting It To Use&lt;/h3&gt;
&lt;p&gt;So does it “work”? Well, I built a shiny app that uses just this package and a
stored copy of all the cached data (so that it doesn’t need my API key) to show
the network graph for any kanji at any depth, and you can play with it here&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jcarroll.shinyapps.io/kanjiexplorer/&#34; class=&#34;uri&#34;&gt;https://jcarroll.shinyapps.io/kanjiexplorer/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I’ve hosted it on shinyapps.io, and of course I got Claude (not Code this time)
to help me build it. It takes either kanji or an English word and builds the
network graph to some maximum depth, with a limitation on the level (in case you
don’t care about words you haven’t learned yet) and some settings for layout.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/kanjiexplorer.png&#34; width=&#34;800&#34; alt=&#34;Kanji Explorer shiny app&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Kanji Explorer shiny app&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;FYI, it’s … not great on a phone screen. I haven’t spent a lot of time
refining this, and don’t plan to. Nonetheless, I’m absolutely going to use this
when I get confused between two kanji!&lt;/p&gt;
&lt;p&gt;In terms of “does it work?” I think it definitely does all of the things that I
wanted it to do. The old saying of &lt;a href=&#34;https://wiki.c2.com/?MakeItWorkMakeItRightMakeItFast&#34;&gt;“Make it work, make it right, make it fast”&lt;/a&gt; probably applies
here. I think “work” gets a tick. Is it right? I don’t know. As far as I can
see, it uses the data from the WaniKani API and gets the same results that I did
when I got it manually, but I’m relying on that data. Sure, there’s possibly
(probably) bugs in there. But this is pretty low-risk work I’m doing here. The
very worst that could happen with any of this code is it deletes my WaniKani
account, and in that case I’ll live to tell the tale. In terms of “fast”, this
is also low-risk. It doesn’t need to do anything computationally heavy;
everything here seems to work okay. I got it to add caching, so I wasn’t
being wasteful. But apart from that, what more could I want to do?&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;reflections&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Reflections&lt;/h3&gt;
&lt;p&gt;Should &lt;em&gt;you&lt;/em&gt; build one of these packages to connect to your banking app?
Probably not. I think it would probably build something that might be capable
and “look right enough” if your bank had an API, but the risk there is just too
high to actually let a system vibe code it.&lt;/p&gt;
&lt;p&gt;People used to say “ideas are free, implementing costs.” I think it was Geoff
Huntley who said in his DataEngBytes presentation (something along the lines of)
“implementing prototypes for ideas is now free” and I believe I’ve demonstrated
that here (provided you consider $20 close enough to free). If somebody wanted
to take this and create a business that made a “production ready” version of
this shiny app, go for it! You’re welcome to; I’ll maybe even subscribe to it.
But I built this entire prototype from an empty file in a day and twenty
dollars, so I have what I need to continue with that.&lt;/p&gt;
&lt;p&gt;Does this mean that R programmers can stop learning and just rely on AI now?
Absolutely not. I think the only way that I managed to get this to work the way
that I wanted it to was by querying the data manually myself first and having a
look at it. That helped me understand what was available, where things were in
the response, and when the model had trouble building around that I was able to
say or point out that oh there’s a &lt;code&gt;x$data$something&lt;/code&gt; field.&lt;/p&gt;
&lt;p&gt;In terms of business requirements, that’s always been something that you need to
have before you can start building a package. Can it speed up your iteration
process? I think absolutely. I got nowhere near actually building the first
function for a package in the night that I spent working on this, and within
about an hour with an AI agent I had something that was not only documented with
tests, but fully passing &lt;code&gt;devtools::check()&lt;/code&gt;. That’s so much faster than I could
have built it even if it is just a prototype.&lt;/p&gt;
&lt;p&gt;The old advice of “throw away your first prototype” is very likely still
applicable here, and if I went through and rewrote all of these things in my own
style, I don’t think much would change in terms of the functionality. The big
difference from doing it manually is that I now &lt;em&gt;have&lt;/em&gt; that first version, and
can see if it does what I actually want it to do (it does!).&lt;/p&gt;
&lt;p&gt;I don’t mind if no one beyond me uses this. I built it exclusively for me. It
does what I want it to do. The code and the shiny app are available if that’s
helpful to you, and if there’s something else that you’d find useful, maybe I’ll
find that useful too, so feel free to send in any pull requests or issues about
what you think it could or should do. In the meantime, I’ll be using this to
enhance my own Japanese learning.&lt;/p&gt;
&lt;p&gt;I’d love to hear what people think about this… Was this all a terrible idea?
Is there already a better tool which does this? Have I wasted $20 enjoying seeing
something come to life? As always, I can be found on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; and the comment section below.&lt;/p&gt;
&lt;p&gt;In case you missed it in the middle of the post, the link to the package is
&lt;a href=&#34;https://github.com/jonocarroll/rwanikani&#34; class=&#34;uri&#34;&gt;https://github.com/jonocarroll/rwanikani&lt;/a&gt; - happy learning!&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.4.1 (2024-06-14)
##  os       macOS 15.6.1
##  system   aarch64, darwin20
##  ui       X11
##  language (EN)
##  collate  en_US.UTF-8
##  ctype    en_US.UTF-8
##  tz       Australia/Adelaide
##  date     2025-09-22
##  pandoc   3.7.0.2 @ /opt/homebrew/bin/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version    date (UTC) lib source
##  blogdown      1.21.1     2025-06-28 [1] Github (rstudio/blogdown@33313a5)
##  bookdown      0.41       2024-10-16 [1] CRAN (R 4.4.1)
##  bslib         0.8.0      2024-07-29 [1] CRAN (R 4.4.0)
##  cachem        1.1.0      2024-05-16 [1] CRAN (R 4.4.0)
##  cli           3.6.4      2025-02-13 [1] CRAN (R 4.4.1)
##  devtools      2.4.5      2022-10-11 [1] CRAN (R 4.4.0)
##  digest        0.6.37     2024-08-19 [1] CRAN (R 4.4.1)
##  ellipsis      0.3.2      2021-04-29 [1] CRAN (R 4.4.0)
##  evaluate      1.0.3      2025-01-10 [1] CRAN (R 4.4.1)
##  fastmap       1.2.0      2024-05-15 [1] CRAN (R 4.4.0)
##  fs            1.6.5      2024-10-30 [1] CRAN (R 4.4.1)
##  glue          1.8.0      2024-09-30 [1] CRAN (R 4.4.1)
##  htmltools     0.5.8.1    2024-04-04 [1] CRAN (R 4.4.0)
##  htmlwidgets   1.6.4      2023-12-06 [1] CRAN (R 4.4.0)
##  httpuv        1.6.15     2024-03-26 [1] CRAN (R 4.4.0)
##  jquerylib     0.1.4      2021-04-26 [1] CRAN (R 4.4.0)
##  jsonlite      2.0.0      2025-03-27 [1] CRAN (R 4.4.1)
##  knitr         1.50       2025-03-16 [1] CRAN (R 4.4.1)
##  later         1.4.1      2024-11-27 [1] CRAN (R 4.4.1)
##  lifecycle     1.0.4      2023-11-07 [1] CRAN (R 4.4.0)
##  magrittr      2.0.3      2022-03-30 [1] CRAN (R 4.4.0)
##  memoise       2.0.1      2021-11-26 [1] CRAN (R 4.4.0)
##  mime          0.12       2021-09-28 [1] CRAN (R 4.4.0)
##  miniUI        0.1.1.1    2018-05-18 [1] CRAN (R 4.4.0)
##  pkgbuild      1.4.7      2025-03-24 [1] CRAN (R 4.4.1)
##  pkgload       1.4.0      2024-06-28 [1] CRAN (R 4.4.0)
##  profvis       0.4.0      2024-09-20 [1] CRAN (R 4.4.1)
##  promises      1.3.2      2024-11-28 [1] CRAN (R 4.4.1)
##  purrr         1.0.4      2025-02-05 [1] CRAN (R 4.4.1)
##  R6            2.6.1      2025-02-15 [1] CRAN (R 4.4.1)
##  Rcpp          1.0.14     2025-01-12 [1] CRAN (R 4.4.1)
##  remotes       2.5.0      2024-03-17 [1] CRAN (R 4.4.1)
##  rlang         1.1.5      2025-01-17 [1] CRAN (R 4.4.1)
##  rmarkdown     2.28       2024-08-17 [1] CRAN (R 4.4.0)
##  rstudioapi    0.17.1     2024-10-22 [1] CRAN (R 4.4.1)
##  sass          0.4.9      2024-03-15 [1] CRAN (R 4.4.0)
##  sessioninfo   1.2.2      2021-12-06 [1] CRAN (R 4.4.0)
##  shiny         1.9.1      2024-08-01 [1] CRAN (R 4.4.0)
##  urlchecker    1.0.1      2021-11-30 [1] CRAN (R 4.4.0)
##  usethis       3.1.0.9000 2025-03-31 [1] Github (r-lib/usethis@a653d6e)
##  vctrs         0.6.5      2023-12-01 [1] CRAN (R 4.4.0)
##  xfun          0.51       2025-02-19 [1] CRAN (R 4.4.1)
##  xtable        1.8-4      2019-04-21 [1] CRAN (R 4.4.0)
##  yaml          2.3.10     2024-07-26 [1] CRAN (R 4.4.0)
## 
##  [1] /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Counting Digits Quickly</title>
      <link>https://jcarroll.com.au/2025/06/29/counting-digits-quickly/</link>
      <pubDate>Sun, 29 Jun 2025 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2025/06/29/counting-digits-quickly/</guid>
      <description>&lt;p&gt;When things run slower than we’d like in R we tend to reach for another, usually
compiled, language, and move our code there. What if it “just happened”? What
started out as a silly exploration of how to count digits ended up with a race
to see which language does it fastest. Maybe some surprises here for some, maybe
some bad implementations on my part - let’s find out.&lt;/p&gt;
&lt;p&gt;I saw some recent activity on &lt;a href=&#34;https://github.com/t-kalinowski/quickr&#34;&gt;{quickr}&lt;/a&gt;;
Tomasz Kalinowski’s R to Fortran transpiler - I had starred the repo a long time
ago (and in haste, accidentally unstarred it, then re-starred it) but never
really played with it. I’m familiar with slightly older Fortran; nowadays it’s
called “modern Fortran”, but I did my PhD using Fortran95 in the late 2000’s.
I’ve even pushed some of my &lt;a href=&#34;https://github.com/jonocarroll/Dirac&#34;&gt;postdoc code to GitHub&lt;/a&gt;
after getting it working again for a recent student.&lt;/p&gt;
&lt;p&gt;I figured now was a great chance to have a proper play with the package.&lt;/p&gt;
&lt;p&gt;{quickr} “transpiles” R code which means it takes R code converts the syntax
into Fortran syntax using the same variables and equivalent functions where
available. The idea being that when R isn’t working fast enough for you, instead
of re-writing your function in something like C++ (via {Rcpp}) it can
automatically write a Fortran version of your code and compile that into a
highly performant function which can be called with the same arguments. Faster
running code with no additional effort - sounds great!&lt;/p&gt;
&lt;p&gt;The README for {quickr} has some examples highlighting how it can improve the
performance of some functions beyond what {Rcpp} can offer, in some cases
approaching C speeds. That’s not surprising to those who know Fortran - it’s
still very much used in theoretical physics partly because of the performance,
partly due to the existing support in that field, but also partly because despite
being an ‘old’ language, it’s actually pretty nice to use.&lt;/p&gt;
&lt;p&gt;One of the big advantages of Fortran I found when learning other languages
&lt;em&gt;after&lt;/em&gt; learning Fortran was that there’s no manual memory management. If you
want a vector or an array/tensor with many dimensions, you just ask for it
(specifying a size along each dimension or dynamically sizing, but never
manually freeing memory). R is known for its statistics chops, but under the
hood of some of these functions still &lt;a href=&#34;https://github.com/search?q=repo%3Awch%2Fr-source+%22.Fortran%28%22+path%3A*.R&amp;amp;type=code&#34;&gt;call out to Fortran code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I wanted some example code to try out myself and see if I even recognise the
Fortran it produces. I didn’t just want to use the example code from the package,
so what could I use?&lt;/p&gt;
&lt;p&gt;In &lt;a href=&#34;https://jcarroll.com.au/2025/05/03/rotation-with-modulo/&#34;&gt;this post&lt;/a&gt; I
celebrated the fact that Julia has a &lt;code&gt;ndigits()&lt;/code&gt; function, while in R I cheated
and used &lt;code&gt;nchar()&lt;/code&gt; which works fine provided you’re dealing with non-negative
integers up to 99999, outside of which it doesn’t do what you want&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nchar(99)       # 99    = 2 characters&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nchar(99999)    # 99999 = 5 characters&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 5&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nchar(99999+1)  # 1e+05 = 5 characters&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 5&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nchar(-99)      # -99   = 3 characters&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I had some interesting &lt;a href=&#34;https://fosstodon.org/@jonocarroll/114441466559717402&#34;&gt;discussions on Mastodon&lt;/a&gt;
about different ways to implement &lt;code&gt;ndigits()&lt;/code&gt; properly for R and in the end,
re-implementing the Julia solution seemed to work great for all edge cases. I
decided to use this for my Fortran testing with {quickr}.&lt;/p&gt;
&lt;p&gt;I got the package installed and the compiler hooked up correctly so that I could
run the example code, then tried adapting it to the &lt;code&gt;ndigits()&lt;/code&gt; problem.&lt;/p&gt;
&lt;div id=&#34;r&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;R&lt;/h2&gt;
&lt;p&gt;The R code I started with was&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nd_R &amp;lt;- function(x) {
  out &amp;lt;- integer(length(x))
  x &amp;lt;- abs(x / 10)
  for (v in seq_along(x)) {
    d &amp;lt;- 1
    m &amp;lt;- 1
    while (m &amp;lt;= x[v]) {
      m &amp;lt;- m * 10
      d &amp;lt;- d + 1
    }
    out[v] &amp;lt;- d
  }
  out
}

nd_R(c(123456L, 234L, -72L))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 6 3 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and while this looks like a moderate amount of code, in essence it’s taking the
absolute value of the input (since we want to ignore negatives, and which is
nicely vectorised in R), dividing by 10, checking if we’ve exceeded the input
yet, and if not, stepping through successive multiples of 10 until we do, which
finds the first power of 10 that is greater than our value, indicating the
number of digits. For what it’s worth, this is why in that post I noted an
alternative route to achieving this; &lt;code&gt;ceil(log10(x))&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;fortran&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Fortran&lt;/h2&gt;
&lt;p&gt;Hoping to immediately transpile this to Fortran, &lt;del&gt;I immediately hit my first
snag; {quickr} hasn’t yet implemented &lt;code&gt;while()&lt;/code&gt; so I can’t transpile this
exactly as I have it. There’s no early &lt;code&gt;return()&lt;/code&gt; or &lt;code&gt;break&lt;/code&gt; either, so I can’t
just exit an oversized loop early. Without an alternative, I’m going to cheat a
bit and just run a loop 12 times - this puts an upper limit on the input to a 12
digit number, but I can live with that.&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;Update &lt;em&gt;while writing the post&lt;/em&gt;: I suppose good things come to those who wait -
on digging through some source code for this post I saw that &lt;code&gt;while&lt;/code&gt; has been
implemented in the last week, so I’m going to pretend that was always the case.&lt;/p&gt;
&lt;p&gt;The other piece this transpiler needs is a type declaration for the input; R
is fully dynamic in that a function can take any type of object and it’s up to
the function to decide what to do with it. Fortran is a bit stricter, and
requires types to be annotated, so I need to add a &lt;code&gt;declare(type())&lt;/code&gt; to the code.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nd2f &amp;lt;- function(x) {
  declare(
    type(x = integer(NA))
  )
  out &amp;lt;- integer(length(x))
  x &amp;lt;- abs(x / 10L)
  for (v in seq_along(out)) {
    d &amp;lt;- 1L
    m &amp;lt;- 1L
    while (m &amp;lt;= x[v]) {
      m &amp;lt;- m * 10L
      d &amp;lt;- d + 1L
    }
    out[v] &amp;lt;- d
  }
  out
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NOTE: the original version of this post used &lt;code&gt;double()&lt;/code&gt; values but as
&lt;a href=&#34;https://mastodon.social/@toddixd&#34;&gt;&lt;span class=&#34;citation&#34;&gt;@toddixd&lt;/span&gt;&lt;/a&gt; noted, there’s an additional
performance improvement to be made if we restrict to integers, which the values
will actually be.&lt;/p&gt;
&lt;p&gt;Note that this is still very much R code at this point - I can even run it
in R and get the same answers as before&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nd2f(c(123456L, 234L, -72L))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 6 3 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What surprised me here is that &lt;code&gt;declare()&lt;/code&gt; is a base R function (not from
{quickr}) intended for “specifying information about R code for use by the
interpreter, compiler, and code analysis tools”. I was originally thinking it
would be neat to be able to leverage that for some type-checking on the R side
as well as being informative to the Fortran code, but it “ignores the arguments
and returns &lt;code&gt;NULL&lt;/code&gt; invisibly”, so no go on this throwing an error from R&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;int_id &amp;lt;- function(x) {
  declare(type(x = integer(NA)))
  x
}

int_id(3L)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;int_id(1.5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1.5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The magic happens when we ask {quickr} to do the transpilation.&lt;/p&gt;
&lt;p&gt;The type information is used in the Fortran code, so compiling the &lt;code&gt;id()&lt;/code&gt; example
produces something that is more restrictive on types&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;int_id_F &amp;lt;- quickr::quick(int_id)
int_id_F(3L)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;int_id_F(1.5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in int_id_F(1.5): typeof(x) must be &amp;#39;integer&amp;#39;, not &amp;#39;double&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can inspect the generated code with &lt;code&gt;r2f()&lt;/code&gt;, though one wouldn’t normally need
to - it’s interesting to see what the Fortran code looks like&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;quickr:::r2f(int_id)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## subroutine int_id(x, x__len_) bind(c)
##   use iso_c_binding, only: c_int, c_ptrdiff_t
##   implicit none
## 
##   ! manifest start
##   ! sizes
##   integer(c_ptrdiff_t), intent(in), value :: x__len_
## 
##   ! args
##   integer(c_int), intent(in out) :: x(x__len_)
##   ! manifest end
## 
## 
## end subroutine
## 
## @r: function (x)
##   {
##       declare(type(x = integer(NA)))
##       x
##   }
## @closure: function (x)
##   {
##       declare(type(x = integer(NA)))
##       x
##   }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But of course, this just returns the value and that’s not particularly
enlightening. Doing the same for the &lt;code&gt;ndigits&lt;/code&gt; code&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;quickr:::r2f(nd2f)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## subroutine nd2f(x, out, x__len_) bind(c)
##   use iso_c_binding, only: c_int, c_ptrdiff_t
##   implicit none
## 
##   ! manifest start
##   ! sizes
##   integer(c_ptrdiff_t), intent(in), value :: x__len_
## 
##   ! args
##   integer(c_int), intent(in out) :: x(x__len_)
##   integer(c_int), intent(out) :: out(x__len_)
## 
##   ! locals
##   integer(c_int) :: v
##   integer(c_int) :: d
##   integer(c_int) :: m
##   ! manifest end
## 
## 
##   out = 0
##   x = abs((x / 10_c_int))
##   do v = 1, size(out)
##     d = 1_c_int
##     m = 1_c_int
##     do while ((m &amp;lt;= x(v)))
##       m = (m * 10_c_int)
##       d = (d + 1_c_int)
##     end do
##     out(v) = d
##   end do
## end subroutine
## 
## @r: function (x)
##   {
##       declare(type(x = integer(NA)))
##       out &amp;lt;- integer(length(x))
##       x &amp;lt;- abs(x/10L)
##       for (v in seq_along(out)) {
##           d &amp;lt;- 1L
##           m &amp;lt;- 1L
##           while (m &amp;lt;= x[v]) {
##               m &amp;lt;- m * 10L
##               d &amp;lt;- d + 1L
##           }
##           out[v] &amp;lt;- d
##       }
##       out
##   }
## @closure: function (x)
##   {
##       declare(type(x = integer(NA)))
##       out &amp;lt;- integer(length(x))
##       x &amp;lt;- abs(x/10L)
##       for (v in seq_along(out)) {
##           d &amp;lt;- 1L
##           m &amp;lt;- 1L
##           while (m &amp;lt;= x[v]) {
##               m &amp;lt;- m * 10L
##               d &amp;lt;- d + 1L
##           }
##           out[v] &amp;lt;- d
##       }
##       out
##   }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The subroutine itself looks a lot like the R code; sure, some type annotations
are sprinkled around, &lt;code&gt;do v = 1, size(x)&lt;/code&gt; replaces &lt;code&gt;for v in seq_along(x)&lt;/code&gt; and
&lt;code&gt;do while&lt;/code&gt; replaces &lt;code&gt;while&lt;/code&gt;, but I don’t think it’s entirely alien.&lt;/p&gt;
&lt;p&gt;What might surprise some is the line&lt;/p&gt;
&lt;pre class=&#34;fortran&#34;&gt;&lt;code&gt;x = abs((x / 10.0_c_double))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice there’s no loop around this? Fortran is an array language…
Rank-polymorphism, baby! I covered this in
&lt;a href=&#34;https://jcarroll.com.au/2023/08/29/now-you-re-thinking-with-arrays/&#34;&gt;another post of mine&lt;/a&gt;
but thanks to this, &lt;code&gt;abs()&lt;/code&gt; is vectorised wherever needed&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;program test_abs
  implicit none
  integer, dimension(5) :: i = [-1, 2, -3, 4, -5]
  write(*,*) abs(i)
end program test_abs&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;#           1           2           3           4           5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Generating the compiled Fortran code from &lt;code&gt;nd2f&lt;/code&gt; is as easy as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nd_F &amp;lt;- quickr::quick(nd2f)
nd_F&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## function (x) 
## .External(&amp;lt;pointer: 0x156f21750&amp;gt;, x)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and we see that it’s referencing some external code. This can be called&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nd_F(c(123456L, 234L, -72L))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 6 3 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with the big benefit that now it’s a LOT faster!&lt;/p&gt;
&lt;p&gt;Generating a million random values and excluding any zero values, we can see the
50x performance increase (!!!)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;set.seed(1)
nums &amp;lt;- as.integer(runif(1e6, -1, 1) * 1e6)
nums &amp;lt;- nums[nums != 0]

b0 &amp;lt;- bench::mark(
  R = nd_R(nums),
  Fortran = nd_F(nums),
  min_iterations = 10
)

dplyr::arrange(b0[, 1:8], median)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 2 × 6
##   expression      min   median `itr/sec` mem_alloc `gc/sec`
##   &amp;lt;bch:expr&amp;gt; &amp;lt;bch:tm&amp;gt; &amp;lt;bch:tm&amp;gt;     &amp;lt;dbl&amp;gt; &amp;lt;bch:byt&amp;gt;    &amp;lt;dbl&amp;gt;
## 1 Fortran      2.62ms   2.85ms    353.      7.63MB    117. 
## 2 R             156ms    156ms      6.41   19.07MB     57.7&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plot(b0)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;unnamed-chunk-12-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;For those not familiar, this benchmark plot shows the individual times taken for
repeated executions of the code in each ‘expression’, grouped vertically by the
‘expression’ itself (annotated as the language here) with some random scatter to show
the spread of execution times. Points to the left are faster. It’s also worth
noting that &lt;code&gt;bench::mark()&lt;/code&gt; defaults to &lt;code&gt;check = TRUE&lt;/code&gt; so we can rest assured that
the results from each of the different languages we’re about to explore are
consistent and it’s not some artifact of one language doing less work.&lt;/p&gt;
&lt;p&gt;If you run these yourself you’ll get slightly different results. I’m running them
on a newish M3 Macbook Pro.&lt;/p&gt;
&lt;p&gt;All that performance increase from just adding one line to the R code and
wrapping it with one other function (resulting in an entirely different program
being written and compiled, producing the correct results).&lt;/p&gt;
&lt;p&gt;I should note that in the first iteration of this post (in which &lt;code&gt;while&lt;/code&gt; was not yet
supported) I used an excessive &lt;code&gt;for&lt;/code&gt; loop which resulted in a
not-as-impressive-but-still-very-impressive 15x performance boost.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;r-compiled&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;R (compiled)&lt;/h2&gt;
&lt;p&gt;If compiled code is so great, what about just compiling the R code with, e.g.
&lt;code&gt;compiler::cmpfun()&lt;/code&gt;?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nd_comp = compiler::cmpfun(nd_R)

nd_comp(c(123456L, 234L, -72L))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 6 3 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;b1 &amp;lt;- bench::mark(
  compiled = nd_comp(nums),
  R = nd_R(nums),
  Fortran = nd_F(nums),
  min_iterations = 10
)

dplyr::arrange(b1[, 1:8], median)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 3 × 6
##   expression      min   median `itr/sec` mem_alloc `gc/sec`
##   &amp;lt;bch:expr&amp;gt; &amp;lt;bch:tm&amp;gt; &amp;lt;bch:tm&amp;gt;     &amp;lt;dbl&amp;gt; &amp;lt;bch:byt&amp;gt;    &amp;lt;dbl&amp;gt;
## 1 Fortran      2.68ms      3ms    334.      7.63MB    86.5 
## 2 compiled   157.78ms    158ms      6.33   19.07MB    14.8 
## 3 R          157.06ms    158ms      6.33   19.07MB     9.50&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plot(b1)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;unnamed-chunk-13-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;That doesn’t help; by the time the benchmark was running the &lt;code&gt;nd_R&lt;/code&gt; function had
been called enough times for it to be JIT compiled, anyway.&lt;/p&gt;
&lt;p&gt;This did get me thinking, though - what about other compiled alternatives?&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;c&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;C&lt;/h2&gt;
&lt;p&gt;Since I’m going through Harvard’s &lt;a href=&#34;https://cs50.harvard.edu/x/2025/&#34;&gt;CS50 ‘Introduction to Computer Science’ course&lt;/a&gt;
with &lt;a href=&#34;https://contributor.r-project.org/events/c-study-group-2025/&#34;&gt;R Contributors&lt;/a&gt;
to learn a bit more structured C I figured I’d add that via coolbutuseless’
&lt;a href=&#34;https://github.com/coolbutuseless/callme&#34;&gt;{callme}&lt;/a&gt; package. This surely isn’t
the world’s greatest C code, but it compiles and runs…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;callme::compile(
  &amp;quot;
#include &amp;lt;R.h&amp;gt;
#include &amp;lt;Rinternals.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;math.h&amp;gt;

SEXP nd_C(SEXP vec) {
  int *vec_ptr = INTEGER(vec);
  SEXP res = PROTECT(allocVector(INTSXP, length(vec)));
  int *res_ptr = INTEGER(res);
  for (int i = 0; i &amp;lt; length(vec); i++) {
    int abs_x = abs(vec_ptr[i] / 10.0);
        int d = 1;
        int m = 1.0;
        while (m &amp;lt;= abs_x) {
            m *= 10.0;
            d++;
        }
        res_ptr[i] = d;
  }

  UNPROTECT(1);
  return res;
}
&amp;quot;
)

nd_C(c(123456L, 234L, -72L))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 6 3 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, how does it compare?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;b2 &amp;lt;- bench::mark(
  C = nd_C(nums),
  R = nd_R(nums),
  Fortran = nd_F(nums),
  min_iterations = 10
)

dplyr::arrange(b2[, 1:8], median)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 3 × 6
##   expression      min   median `itr/sec` mem_alloc `gc/sec`
##   &amp;lt;bch:expr&amp;gt; &amp;lt;bch:tm&amp;gt; &amp;lt;bch:tm&amp;gt;     &amp;lt;dbl&amp;gt; &amp;lt;bch:byt&amp;gt;    &amp;lt;dbl&amp;gt;
## 1 Fortran      2.74ms   3.02ms    330.      7.63MB    67.7 
## 2 C             4.3ms   4.39ms    228.      3.81MB    27.9 
## 3 R          161.01ms 161.35ms      6.06   19.07MB     6.06&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plot(b2)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;unnamed-chunk-15-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Whoa - automatically transpiled Fortran runs faster than (my) C… That’s fast.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/vince1.jpg&#34; width=&#34;400&#34; alt=&#34;Impressively fast&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Impressively fast&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;c-1&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;C++&lt;/h2&gt;
&lt;p&gt;What about C++ via {Rcpp}? Dealing with vectors is made easier by {Rcpp} having
pre-built types compatible with R, and this otherwise looks very similar to the
R code&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Sys.setenv(&amp;quot;PKG_CXXFLAGS&amp;quot; = &amp;quot;-O3&amp;quot;)
nd_Rcpp &amp;lt;- Rcpp::cppFunction(
  &amp;quot;
IntegerVector nd(const IntegerVector&amp;amp; x) {
    int n = x.size();
    IntegerVector out(n);

    for (int v = 0; v &amp;lt; n; v++) {
        int abs_x = std::abs(x[v] / 10);
        int d = 1;
        int m = 1;
        while (m &amp;lt;= abs_x) {
            m *= 10;
            d++;
        }
        out[v] = d;
    }

    return out;
}
&amp;quot;
)

nd_Rcpp(c(123456L, 234L, -72L))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 6 3 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;b3 &amp;lt;- bench::mark(
  `C++` = nd_Rcpp(nums),
  C = nd_C(nums),
  R = nd_R(nums),
  Fortran = nd_F(nums),
  min_iterations = 10
)

dplyr::arrange(b3[, 1:8], median)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 4 × 6
##   expression      min   median `itr/sec` mem_alloc `gc/sec`
##   &amp;lt;bch:expr&amp;gt; &amp;lt;bch:tm&amp;gt; &amp;lt;bch:tm&amp;gt;     &amp;lt;dbl&amp;gt; &amp;lt;bch:byt&amp;gt;    &amp;lt;dbl&amp;gt;
## 1 C++          2.71ms   2.84ms    352.      3.82MB    36.8 
## 2 Fortran      2.69ms   2.91ms    344.      7.63MB    57.7 
## 3 C            4.24ms   4.36ms    229.      3.81MB    22.5 
## 4 R          157.52ms  160.9ms      6.04   19.07MB     4.03&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plot(b3)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;unnamed-chunk-16-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;This one seems to wander around a bit; on different runs I’ve seen performance
equal or better to the C code and on others, about 3x as long, but generally
pretty fast.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;julia&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Julia&lt;/h2&gt;
&lt;p&gt;After all of this, I remembered that I was comparing the Julia implementation -
how does &lt;em&gt;that&lt;/em&gt; perform? Julia is a JIT/AOT compiled language, so maybe it’s not
too bad… I can still call that directly from R&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;JuliaCall::julia_eval(&amp;quot;ndigits.([123456, 234, -72])&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 6 3 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;keeping in mind that the Julia function &lt;code&gt;ndigits&lt;/code&gt; (&lt;a href=&#34;https://github.com/JuliaLang/julia/blob/760b2e5b7396f9cc0da5efce0cadd5d1974c4069/base/intfuncs.jl#L633&#34;&gt;the implementation for which&lt;/a&gt;
I’ve borrowed for all of the examples, so we &lt;em&gt;are&lt;/em&gt; dealing with the same
algorithm in each case) is in fact compiled, but available as &lt;code&gt;ndigits()&lt;/code&gt;. As
long as I make the vector available in a Julia session (as integers; the
function is only defined for integers) I can run this&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;JuliaCall::julia_assign(&amp;quot;nums&amp;quot;, nums)

b4 &amp;lt;- bench::mark(
  Julia = JuliaCall::julia_eval(&amp;quot;ndigits.(nums)&amp;quot;),
  `C++` = nd_Rcpp(nums),
  C = nd_C(nums),
  R = nd_R(nums),
  Fortran = nd_F(nums),
  min_iterations = 10
)

dplyr::arrange(b4[, 1:8], median)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 5 × 6
##   expression      min   median `itr/sec` mem_alloc `gc/sec`
##   &amp;lt;bch:expr&amp;gt; &amp;lt;bch:tm&amp;gt; &amp;lt;bch:tm&amp;gt;     &amp;lt;dbl&amp;gt; &amp;lt;bch:byt&amp;gt;    &amp;lt;dbl&amp;gt;
## 1 C++           2.7ms   2.82ms    353.      3.81MB    26.9 
## 2 Fortran       2.7ms   2.93ms    339.      7.63MB    48.5 
## 3 Julia        3.23ms   3.77ms    232.      3.81MB    22.6 
## 4 C            4.13ms   4.19ms    231.      3.81MB    10.7 
## 5 R          158.75ms 159.51ms      6.27   19.07MB     2.69&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plot(b4)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;unnamed-chunk-18-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Ten points to Julia - remember, this is an interpreted language.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/vince2.jpg&#34; width=&#34;400&#34; alt=&#34;That’s really fast!&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;That’s really fast!&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I should note there’s work being done towards &lt;a href=&#34;https://jbytecode.github.io/juliac/&#34;&gt;making Julia binaries out of scripts&lt;/a&gt;, but this still has a startup time
of a few dozen milliseconds for even a Hello, World example.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;rust&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Rust&lt;/h2&gt;
&lt;p&gt;One more? What about Rust? We can use {rextendr} to call Rust code inline,
making sure to target the release profile for maximum performance&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;rextendr::rust_function(
  r&amp;quot;(
  fn nd_Rust(x: &amp;amp;[i32]) -&amp;gt; Vec&amp;lt;i32&amp;gt; {
    let mut out = vec![0; x.len()];
    for v in 0..x.len() {
        let abs_x = (x[v].abs() / 10);
        let mut d = 1;
        let mut m = 1;
        while m &amp;lt;= abs_x {
            m *= 10;
            d += 1;
        }
        out[v] = d;
    }
    out
  }
)&amp;quot;,
  profile = &amp;quot;release&amp;quot;
)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ℹ build directory: &amp;#39;/private/var/folders/1h/k6c5hb4d2qx07m8kfqb54f9c0000gn/T/RtmpLMk1G9/filec1e53eb70acb&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ✔ Writing &amp;#39;/private/var/folders/1h/k6c5hb4d2qx07m8kfqb54f9c0000gn/T/RtmpLMk1G9/filec1e53eb70acb/target/extendr_wrappers.R&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nd_Rust(c(123456L, 234L, -72L))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 6 3 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;b5 &amp;lt;- bench::mark(
  Rust = nd_Rust(nums),
  Julia = JuliaCall::julia_eval(&amp;quot;ndigits.(nums)&amp;quot;),
  `C++` = nd_Rcpp(nums),
  C = nd_C(nums),
  R = nd_R(nums),
  Fortran = nd_F(nums),
  min_iterations = 10
)

dplyr::arrange(b5[, 1:8], median)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 6 × 6
##   expression      min   median `itr/sec` mem_alloc `gc/sec`
##   &amp;lt;bch:expr&amp;gt; &amp;lt;bch:tm&amp;gt; &amp;lt;bch:tm&amp;gt;     &amp;lt;dbl&amp;gt; &amp;lt;bch:byt&amp;gt;    &amp;lt;dbl&amp;gt;
## 1 C++          2.71ms   2.82ms    353.      3.81MB    27.0 
## 2 Fortran      2.65ms   2.89ms    344.      7.63MB    42.6 
## 3 Rust         2.69ms   2.99ms    323.      3.82MB    25.1 
## 4 Julia        3.25ms   3.54ms    283.      3.81MB    22.4 
## 5 C            4.09ms   4.28ms    231.      3.81MB    17.9 
## 6 R          160.23ms 160.72ms      6.22   19.07MB     4.15&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plot(b5)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;unnamed-chunk-19-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/vince3.jpg&#34; width=&#34;400&#34; alt=&#34;Ridiculous speeds!&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Ridiculous speeds!&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We are truly spoiled for choice these days - not only do we have a plethora of
languages we can call directly from R, but several languages which run faster than
even (at least my implementation of) C and count number of digits of
a million values in under 4ms.&lt;/p&gt;
&lt;p&gt;After enforcing integers in the R code which was transpiled to Fortran, we’ve
somehow managed to achieve Rust speeds with nearly 0 additional effort. I’m
very impressed!&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;python&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Python&lt;/h2&gt;
&lt;p&gt;Just for funsies, what about Python? It’s not a compiled language, but maybe if
I use numpy it will be fast … ? It’s at least another language I can call from
R that is generally considered ‘faster’. Is it?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(reticulate)
reticulate::py_run_string(&amp;#39;
import numpy as np
def nd_python(x):
    x = np.asarray(x)
    out = np.zeros(len(x), dtype=int)

    for v in range(len(x)):
        abs_x = abs(x[v] / 10)
        d = 1
        m = 1
        while m &amp;lt;= abs_x:
            m *= 10
            d += 1
        out[v] = d

    return out.tolist()
&amp;#39;)

py$nd_python(c(123456L, 234L, -72L))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 6 3 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;b6 &amp;lt;- bench::mark(
  Python = py$nd_python(nums),
  Rust = nd_Rust(nums),
  Julia = JuliaCall::julia_eval(&amp;quot;ndigits.(nums)&amp;quot;),
  `C++` = nd_Rcpp(nums),
  C = nd_C(nums),
  R = nd_R(nums),
  Fortran = nd_F(nums),
  min_iterations = 10
)

dplyr::arrange(b6[, 1:8], median)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 7 × 6
##   expression      min   median `itr/sec` mem_alloc `gc/sec`
##   &amp;lt;bch:expr&amp;gt; &amp;lt;bch:tm&amp;gt; &amp;lt;bch:tm&amp;gt;     &amp;lt;dbl&amp;gt; &amp;lt;bch:byt&amp;gt;    &amp;lt;dbl&amp;gt;
## 1 C++          2.71ms   2.81ms    354.      3.81MB    15.1 
## 2 Fortran      2.65ms   2.81ms    355.      7.63MB    35.2 
## 3 Rust         2.69ms   2.85ms    336.      3.81MB    17.9 
## 4 Julia        3.48ms   3.71ms    274.      3.81MB    10.8 
## 5 C            4.06ms   4.17ms    240.      3.81MB     8.43
## 6 R          161.01ms 161.26ms      6.20   19.07MB     2.66
## 7 Python      272.1ms 272.73ms      3.63    3.81MB     0&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plot(b6)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;unnamed-chunk-20-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;In fairness, there’s overhead here involved with calling it from R, but I think
that’s apples-to-apples considering I’m doing the same with all the compiled
languages.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;does-it-scale&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Does it scale?&lt;/h2&gt;
&lt;p&gt;I’ve been running these benchmarks for a million numbers, but how do the results
scale with that size? What if it’s just a handful of numbers? What about in
between these extremes? Running the benchmarks at various scales should show this.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;n_vals &amp;lt;- 10^(1:7)
scales &amp;lt;- purrr::map_df(n_vals, ~{
  set.seed(1)
  nums &amp;lt;- as.integer(runif(.x, -1, 1) * .x)
  nums &amp;lt;- nums[nums != 0]
  JuliaCall::julia_assign(&amp;quot;nums&amp;quot;, nums)
  b &amp;lt;- bench::mark(
    Python = py$nd_python(nums),
    Rust = nd_Rust(nums),
    Julia = JuliaCall::julia_eval(&amp;quot;ndigits.(nums)&amp;quot;),
    `C++` = nd_Rcpp(nums),
    C = nd_C(nums),
    R = nd_R(nums),
    Fortran = nd_F(nums),
    min_iterations = 10,
    check = TRUE
  )
  dplyr::bind_cols(vec_len = .x, b[, 1:8])
})&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-warning text-warning&#34;&gt;&lt;code&gt;## Warning: Some expressions had a GC in every iteration; so filtering is
## disabled.&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)
ggplot(scales,
       aes(x = vec_len,
           y = 1e6*as.numeric(median),
           col = as.character(expression)
       )) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  scale_x_log10() +
  scale_y_log10() +
  scale_color_discrete(palette = &amp;quot;Set2&amp;quot;) +
  labs(
    title = &amp;quot;Scaling of Counting ndigits Benchmarks&amp;quot;,
    x = &amp;quot;Vector Length&amp;quot;,
    y = &amp;quot;Microseconds&amp;quot;,
    color = &amp;quot;Language&amp;quot;
  ) +
  theme_bw()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;unnamed-chunk-21-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;What a nice, log-log linear result with that one exception - Julia is pretty
constant up until 1000, after which it starts to follow the same trajectory as
the other languages - presumably that’s just the overhead of starting up the
Julia runtime, which is a known bottleneck.&lt;/p&gt;
&lt;p&gt;There’s definitely a clear divide between the interpreted languages (R and Python)
and the compiled ones.&lt;/p&gt;
&lt;p&gt;At lower vector lengths there’s a little bit of a spread with Fortran really showing
off at the lowest lengths&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dplyr::arrange(scales[scales$vec_len == 10, ], median)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 7 × 7
##   vec_len expression      min   median `itr/sec` mem_alloc `gc/sec`
##     &amp;lt;dbl&amp;gt; &amp;lt;bch:expr&amp;gt; &amp;lt;bch:tm&amp;gt; &amp;lt;bch:tm&amp;gt;     &amp;lt;dbl&amp;gt; &amp;lt;bch:byt&amp;gt;    &amp;lt;dbl&amp;gt;
## 1      10 Fortran     163.9ns 205.12ns  4369885.        0B     0   
## 2      10 C++         286.8ns 369.04ns  2505953.        0B     0   
## 3      10 C             410ns 451.23ns  1955486.        0B     0   
## 4      10 Rust        532.9ns 696.86ns  1391547.        0B     0   
## 5      10 R           984.2ns   1.11µs   822195.        0B    82.2 
## 6      10 Python       20.5µs  21.89µs    44487.        0B     8.90
## 7      10 Julia        69.3µs  71.67µs    13612.        0B     0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but we’re looking at sub microsecond differences - what &lt;em&gt;will&lt;/em&gt; you do with all
that free time?&lt;/p&gt;
&lt;p&gt;By the time we’re looking at 1000 values, the compiled languages are all about
the same&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dplyr::arrange(scales[scales$vec_len == 1000, ], median)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 7 × 7
##   vec_len expression      min   median `itr/sec` mem_alloc `gc/sec`
##     &amp;lt;dbl&amp;gt; &amp;lt;bch:expr&amp;gt; &amp;lt;bch:tm&amp;gt; &amp;lt;bch:tm&amp;gt;     &amp;lt;dbl&amp;gt; &amp;lt;bch:byt&amp;gt;    &amp;lt;dbl&amp;gt;
## 1    1000 C++          1.48µs   1.76µs   533778.    3.95KB     0   
## 2    1000 Rust         1.56µs    1.8µs   487209.    3.95KB     0   
## 3    1000 Fortran      1.15µs   1.84µs   558984.    7.91KB     0   
## 4    1000 C            3.08µs    3.4µs   281578.    3.95KB     0   
## 5    1000 Julia       72.73µs  79.05µs    12351.    3.95KB     2.05
## 6    1000 R           78.23µs   85.2µs    11640.   19.66KB     2.03
## 7    1000 Python     198.32µs 216.73µs     4565.    3.95KB     0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At ten million values it’s a complete wash the compiled languages with maybe a
slight drop for C&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dplyr::arrange(scales[scales$vec_len == 1e7, ], median)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 7 × 7
##    vec_len expression      min   median `itr/sec` mem_alloc `gc/sec`
##      &amp;lt;dbl&amp;gt; &amp;lt;bch:expr&amp;gt; &amp;lt;bch:tm&amp;gt; &amp;lt;bch:tm&amp;gt;     &amp;lt;dbl&amp;gt; &amp;lt;bch:byt&amp;gt;    &amp;lt;dbl&amp;gt;
## 1 10000000 C++         30.98ms   31.1ms    31.1      38.1MB   7.77  
## 2 10000000 Rust        32.54ms  32.77ms    29.5      38.1MB   5.91  
## 3 10000000 Fortran     32.32ms   34.8ms    23.8      76.3MB  11.9   
## 4 10000000 Julia        36.4ms  39.59ms    18.2      38.1MB   3.64  
## 5 10000000 C           44.91ms  45.25ms    21.7      38.1MB   3.95  
## 6 10000000 R             1.84s    1.86s     0.536   190.7MB   0.536 
## 7 10000000 Python        3.02s    3.06s     0.327    38.1MB   0.0654&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All very interesting!&lt;/p&gt;
&lt;p&gt;It would probably be worthwhile digging into the memory usage of all of these
since there’s a big difference that likely indicates something different is
happening, but that’s beyond my understanding - feel free to let me know!&lt;/p&gt;
&lt;p&gt;So, what might be the reason for Rust and Julia to be so fast, even compared to
C? These are newer languages with a lot of focus on their compilers, and it’s
entirely possible that they’re able to make some better optimisations compared
to a very general C compiler, but more likely that’s the upper limit of what a
computer can do in that much time and my C code is non-optimal.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;conclusions&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Back to the original point, though - the transpilation does an amazing job
of improving the code &lt;em&gt;without having to write more code in a different
language&lt;/em&gt;. Sure, Julia solves this ‘two language problem’ by just being
ridiculously fast to begin with, but if I &lt;em&gt;am&lt;/em&gt; writing R code, it’s fantastic to
see there’s an option for just “making it go brrr” without actually doing
anything extra.&lt;/p&gt;
&lt;p&gt;Not all of R has been translated to Fortran so there’s a lot of code that won’t
transpile just yet, but it’s a truly inspiring project that I’ll surely be
keeping a close eye on.&lt;/p&gt;
&lt;p&gt;I’d love to hear what people think about these comparisons - are there points I’ve
overlooked? Better ways to do it? Improvements to my implementations which change
the results? Other considerations I’ve missed? As always, I can be found on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; and the comment section below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.4.1 (2024-06-14)
##  os       macOS 15.5
##  system   aarch64, darwin20
##  ui       X11
##  language (EN)
##  collate  en_US.UTF-8
##  ctype    en_US.UTF-8
##  tz       Australia/Adelaide
##  date     2025-06-29
##  pandoc   3.4 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/aarch64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package      * version    date (UTC) lib source
##  beeswarm       0.4.0      2021-06-01 [1] CRAN (R 4.4.1)
##  bench          1.1.4      2025-01-16 [1] CRAN (R 4.4.1)
##  blogdown       1.21.1     2025-06-28 [1] Github (rstudio/blogdown@33313a5)
##  bookdown       0.41       2024-10-16 [1] CRAN (R 4.4.1)
##  brio           1.1.5      2024-04-24 [1] CRAN (R 4.4.0)
##  bslib          0.8.0      2024-07-29 [1] CRAN (R 4.4.0)
##  cachem         1.1.0      2024-05-16 [1] CRAN (R 4.4.0)
##  callme         0.1.10     2024-07-27 [1] CRAN (R 4.4.0)
##  cli            3.6.4      2025-02-13 [1] CRAN (R 4.4.1)
##  codetools      0.2-20     2024-03-31 [1] CRAN (R 4.4.1)
##  devtools       2.4.5      2022-10-11 [1] CRAN (R 4.4.0)
##  dichromat      2.0-0.1    2022-05-02 [1] CRAN (R 4.4.1)
##  digest         0.6.37     2024-08-19 [1] CRAN (R 4.4.1)
##  dotty          0.1.0      2024-08-30 [1] CRAN (R 4.4.1)
##  dplyr          1.1.4      2023-11-17 [1] CRAN (R 4.4.0)
##  ellipsis       0.3.2      2021-04-29 [1] CRAN (R 4.4.0)
##  evaluate       1.0.3      2025-01-10 [1] CRAN (R 4.4.1)
##  farver         2.1.2      2024-05-13 [1] CRAN (R 4.4.0)
##  fastmap        1.2.0      2024-05-15 [1] CRAN (R 4.4.0)
##  fs             1.6.5      2024-10-30 [1] CRAN (R 4.4.1)
##  generics       0.1.3      2022-07-05 [1] CRAN (R 4.4.0)
##  ggbeeswarm     0.7.2      2023-04-29 [1] CRAN (R 4.4.0)
##  ggplot2      * 3.5.2.9001 2025-06-15 [1] Github (tidyverse/ggplot2@9f80c8c)
##  glue           1.8.0      2024-09-30 [1] CRAN (R 4.4.1)
##  gtable         0.3.6      2024-10-25 [1] CRAN (R 4.4.1)
##  here           1.0.1      2020-12-13 [1] CRAN (R 4.4.0)
##  htmltools      0.5.8.1    2024-04-04 [1] CRAN (R 4.4.0)
##  htmlwidgets    1.6.4      2023-12-06 [1] CRAN (R 4.4.0)
##  httpuv         1.6.15     2024-03-26 [1] CRAN (R 4.4.0)
##  jquerylib      0.1.4      2021-04-26 [1] CRAN (R 4.4.0)
##  jsonlite       2.0.0      2025-03-27 [1] CRAN (R 4.4.1)
##  JuliaCall      0.17.6     2024-12-07 [1] CRAN (R 4.4.1)
##  knitr          1.50       2025-03-16 [1] CRAN (R 4.4.1)
##  later          1.4.1      2024-11-27 [1] CRAN (R 4.4.1)
##  lattice        0.22-6     2024-03-20 [1] CRAN (R 4.4.1)
##  lifecycle      1.0.4      2023-11-07 [1] CRAN (R 4.4.0)
##  magrittr       2.0.3      2022-03-30 [1] CRAN (R 4.4.0)
##  Matrix         1.7-1      2024-10-18 [1] CRAN (R 4.4.1)
##  memoise        2.0.1      2021-11-26 [1] CRAN (R 4.4.0)
##  mime           0.12       2021-09-28 [1] CRAN (R 4.4.0)
##  miniUI         0.1.1.1    2018-05-18 [1] CRAN (R 4.4.0)
##  pillar         1.10.1     2025-01-07 [1] CRAN (R 4.4.1)
##  pkgbuild       1.4.7      2025-03-24 [1] CRAN (R 4.4.1)
##  pkgconfig      2.0.3      2019-09-22 [1] CRAN (R 4.4.0)
##  pkgload        1.4.0      2024-06-28 [1] CRAN (R 4.4.0)
##  png            0.1-8      2022-11-29 [1] CRAN (R 4.4.0)
##  processx       3.8.6      2025-02-21 [1] CRAN (R 4.4.1)
##  profmem        0.7.0      2025-05-02 [1] CRAN (R 4.4.1)
##  profvis        0.4.0      2024-09-20 [1] CRAN (R 4.4.1)
##  promises       1.3.2      2024-11-28 [1] CRAN (R 4.4.1)
##  ps             1.9.0      2025-02-18 [1] CRAN (R 4.4.1)
##  purrr          1.0.4      2025-02-05 [1] CRAN (R 4.4.1)
##  quickr         0.1.0.9000 2025-06-29 [1] Github (t-kalinowski/quickr@254b4d0)
##  R6             2.6.1      2025-02-15 [1] CRAN (R 4.4.1)
##  RColorBrewer   1.1-3      2022-04-03 [1] CRAN (R 4.4.0)
##  Rcpp           1.0.14     2025-01-12 [1] CRAN (R 4.4.1)
##  remotes        2.5.0      2024-03-17 [1] CRAN (R 4.4.1)
##  reticulate   * 1.42.0     2025-03-25 [1] CRAN (R 4.4.1)
##  rextendr       0.3.1      2023-06-20 [1] CRAN (R 4.4.0)
##  rlang          1.1.5      2025-01-17 [1] CRAN (R 4.4.1)
##  rmarkdown      2.28       2024-08-17 [1] CRAN (R 4.4.0)
##  rprojroot      2.0.4      2023-11-05 [1] CRAN (R 4.4.0)
##  rstudioapi     0.17.1     2024-10-22 [1] CRAN (R 4.4.1)
##  S7             0.2.0      2024-11-07 [1] CRAN (R 4.4.1)
##  sass           0.4.9      2024-03-15 [1] CRAN (R 4.4.0)
##  scales         1.4.0      2025-04-24 [1] CRAN (R 4.4.1)
##  sessioninfo    1.2.2      2021-12-06 [1] CRAN (R 4.4.0)
##  shiny          1.9.1      2024-08-01 [1] CRAN (R 4.4.0)
##  stringi        1.8.4      2024-05-06 [1] CRAN (R 4.4.0)
##  tibble         3.2.1      2023-03-20 [1] CRAN (R 4.4.0)
##  tidyr          1.3.1      2024-01-24 [1] CRAN (R 4.4.0)
##  tidyselect     1.2.1      2024-03-11 [1] CRAN (R 4.4.0)
##  urlchecker     1.0.1      2021-11-30 [1] CRAN (R 4.4.0)
##  usethis        3.1.0.9000 2025-03-31 [1] Github (r-lib/usethis@a653d6e)
##  utf8           1.2.4      2023-10-22 [1] CRAN (R 4.4.0)
##  vctrs          0.6.5      2023-12-01 [1] CRAN (R 4.4.0)
##  vipor          0.4.7      2023-12-18 [1] CRAN (R 4.4.1)
##  withr          3.0.2      2024-10-28 [1] CRAN (R 4.4.1)
##  xfun           0.51       2025-02-19 [1] CRAN (R 4.4.1)
##  xtable         1.8-4      2019-04-21 [1] CRAN (R 4.4.0)
##  yaml           2.3.10     2024-07-26 [1] CRAN (R 4.4.0)
## 
##  [1] /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/library
## 
## ─ Python configuration ───────────────────────────────────────────────────────
##  python:         /Users/jono/Library/Caches/org.R-project.R/R/reticulate/uv/cache/archive-v0/2tc-cviHm3ODucI_hIfUb/bin/python3
##  libpython:      /Users/jono/Library/Caches/org.R-project.R/R/reticulate/uv/python/cpython-3.11.12-macos-aarch64-none/lib/libpython3.11.dylib
##  pythonhome:     /Users/jono/Library/Caches/org.R-project.R/R/reticulate/uv/cache/archive-v0/2tc-cviHm3ODucI_hIfUb:/Users/jono/Library/Caches/org.R-project.R/R/reticulate/uv/cache/archive-v0/2tc-cviHm3ODucI_hIfUb
##  virtualenv:     /Users/jono/Library/Caches/org.R-project.R/R/reticulate/uv/cache/archive-v0/2tc-cviHm3ODucI_hIfUb/bin/activate_this.py
##  version:        3.11.12 (main, Apr  9 2025, 03:49:53) [Clang 20.1.0 ]
##  numpy:          /Users/jono/Library/Caches/org.R-project.R/R/reticulate/uv/cache/archive-v0/2tc-cviHm3ODucI_hIfUb/lib/python3.11/site-packages/numpy
##  numpy_version:  2.3.1
##  
##  NOTE: Python version was forced by py_require()
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Rotation with Modulo</title>
      <link>https://jcarroll.com.au/2025/05/03/rotation-with-modulo/</link>
      <pubDate>Sat, 03 May 2025 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2025/05/03/rotation-with-modulo/</guid>
      <description>&lt;p&gt;How well do you know your fundamental operators in different languages? ‘Easy’
examples help to fortify that knowledge, and comparing across languages makes
for some neat implementation detail discoveries.&lt;/p&gt;
&lt;p&gt;I saw &lt;a href=&#34;https://mathstodon.xyz/@gregeganSF/114429919995214762&#34;&gt;this toot from &lt;code&gt;@gregeganSF&lt;/code&gt;&lt;/a&gt; on Mastodon&lt;/p&gt;
&lt;blockquote class=&#34;mastodon-embed&#34; data-embed-url=&#34;https://mathstodon.xyz/@gregeganSF/114429919995214762/embed&#34; style=&#34;background: #FCF8FF; border-radius: 8px; border: 1px solid #C9C4DA; margin: 0; max-width: 540px; min-width: 270px; overflow: hidden; padding: 0;&#34;&gt;
&lt;a href=&#34;https://mathstodon.xyz/@gregeganSF/114429919995214762&#34; target=&#34;_blank&#34; style=&#34;align-items: center; color: #1C1A25; display: flex; flex-direction: column; font-family: system-ui, -apple-system, BlinkMacSystemFont, &#39;Segoe UI&#39;, Oxygen, Ubuntu, Cantarell, &#39;Fira Sans&#39;, &#39;Droid Sans&#39;, &#39;Helvetica Neue&#39;, Roboto, sans-serif; font-size: 14px; justify-content: center; letter-spacing: 0.25px; line-height: 20px; padding: 24px; text-decoration: none;&#34;&gt; &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; width=&#34;32&#34; height=&#34;32&#34; viewBox=&#34;0 0 79 75&#34;&gt;&lt;path d=&#34;M74.7135 16.6043C73.6199 8.54587 66.5351 2.19527 58.1366 0.964691C56.7196 0.756754 51.351 0 38.9148 0H38.822C26.3824 0 23.7135 0.756754 22.2966 0.964691C14.1319 2.16118 6.67571 7.86752 4.86669 16.0214C3.99657 20.0369 3.90371 24.4888 4.06535 28.5726C4.29578 34.4289 4.34049 40.275 4.877 46.1075C5.24791 49.9817 5.89495 53.8251 6.81328 57.6088C8.53288 64.5968 15.4938 70.4122 22.3138 72.7848C29.6155 75.259 37.468 75.6697 44.9919 73.971C45.8196 73.7801 46.6381 73.5586 47.4475 73.3063C49.2737 72.7302 51.4164 72.086 52.9915 70.9542C53.0131 70.9384 53.0308 70.9178 53.0433 70.8942C53.0558 70.8706 53.0628 70.8445 53.0637 70.8179V65.1661C53.0634 65.1412 53.0574 65.1167 53.0462 65.0944C53.035 65.0721 53.0189 65.0525 52.9992 65.0371C52.9794 65.0218 52.9564 65.011 52.9318 65.0056C52.9073 65.0002 52.8819 65.0003 52.8574 65.0059C48.0369 66.1472 43.0971 66.7193 38.141 66.7103C29.6118 66.7103 27.3178 62.6981 26.6609 61.0278C26.1329 59.5842 25.7976 58.0784 25.6636 56.5486C25.6622 56.5229 25.667 56.4973 25.6775 56.4738C25.688 56.4502 25.7039 56.4295 25.724 56.4132C25.7441 56.397 25.7678 56.3856 25.7931 56.3801C25.8185 56.3746 25.8448 56.3751 25.8699 56.3816C30.6101 57.5151 35.4693 58.0873 40.3455 58.086C41.5183 58.086 42.6876 58.086 43.8604 58.0553C48.7647 57.919 53.9339 57.6701 58.7591 56.7361C58.8794 56.7123 58.9998 56.6918 59.103 56.6611C66.7139 55.2124 73.9569 50.665 74.6929 39.1501C74.7204 38.6967 74.7892 34.4016 74.7892 33.9312C74.7926 32.3325 75.3085 22.5901 74.7135 16.6043ZM62.9996 45.3371H54.9966V25.9069C54.9966 21.8163 53.277 19.7302 49.7793 19.7302C45.9343 19.7302 44.0083 22.1981 44.0083 27.0727V37.7082H36.0534V27.0727C36.0534 22.1981 34.124 19.7302 30.279 19.7302C26.8019 19.7302 25.0651 21.8163 25.0617 25.9069V45.3371H17.0656V25.3172C17.0656 21.2266 18.1191 17.9769 20.2262 15.568C22.3998 13.1648 25.2509 11.9308 28.7898 11.9308C32.8859 11.9308 35.9812 13.492 38.0447 16.6111L40.036 19.9245L42.0308 16.6111C44.0943 13.492 47.1896 11.9308 51.2788 11.9308C54.8143 11.9308 57.6654 13.1648 59.8459 15.568C61.9529 17.9746 63.0065 21.2243 63.0065 25.3172L62.9996 45.3371Z&#34; fill=&#34;currentColor&#34;/&gt;&lt;/svg&gt;
&lt;div style=&#34;color: #787588; margin-top: 16px;&#34;&gt;
Post by &lt;span class=&#34;citation&#34;&gt;@gregeganSF&lt;/span&gt;&lt;span class=&#34;citation&#34;&gt;@mathstodon.xyz&lt;/span&gt;
&lt;/div&gt;
&lt;div style=&#34;font-weight: 500;&#34;&gt;
View on Mastodon
&lt;/div&gt;
&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script data-allowed-prefixes=&#34;https://mathstodon.xyz/&#34; async src=&#34;https://mathstodon.xyz/embed.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;which says&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To rotate a j-digit number n by k digits, if n≠10^j-1 there is a simple formula:&lt;/p&gt;
&lt;p&gt;rot(n,j,k) = (n*10^k) mod (10^j-1)&lt;/p&gt;
&lt;p&gt;e.g. 1234 * 100 mod 9999 = 3412&lt;/p&gt;
&lt;p&gt;Why? The mod subtracts (10^j-1) times the leftmost k digits of n*10^k, removing them from the left and adding them on the right.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and my first thought was “ooh, that’s cool”, but my second thought was “I’m
going to implement this in a bunch of languages!”. Sure, it’s a very small bit
of math to implement without any particular sharp edges of iteration/recursion,
but that means I’ll be working with some basic functionality and I believe it’s
very important to have that locked in comfortably. Let’s see how it goes!&lt;/p&gt;
&lt;p&gt;I’m not aware of a “name” for this as such. Writing it out a little more styled&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[
rot(n, j, k) = (n\times10^k)\ \%\ (10^j-1)
\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;it looks like I’ll just need a ‘power’ and a ‘modulo’. The &lt;span class=&#34;math inline&#34;&gt;\(j\)&lt;/span&gt; there is the
number of digits in &lt;span class=&#34;math inline&#34;&gt;\(n\)&lt;/span&gt; and sure, we could count that ourselves and pass it as
an argument, but even better might be to calculate it as well. That means
figuring out how many digits are in a number.&lt;/p&gt;
&lt;p&gt;As always, my go-to is R, so let’s start there.&lt;/p&gt;
&lt;div id=&#34;r&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;R&lt;/h2&gt;
&lt;p&gt;In R the power operator is &lt;code&gt;^&lt;/code&gt;. Also &lt;code&gt;**&lt;/code&gt;, but that’s almost never used -
there’s even a note about that in the documentation&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;**&lt;/code&gt; is translated in the parser to &lt;code&gt;^&lt;/code&gt;, but this was undocumented for many years.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Modulo is &lt;code&gt;%%&lt;/code&gt; which I can &lt;em&gt;never&lt;/em&gt; remember because it’s similar to integer
division which is &lt;code&gt;%/%&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To get the number of digits we can use the fact that &lt;code&gt;nchar()&lt;/code&gt; will first convert
its input into a character vector, so &lt;code&gt;12345&lt;/code&gt; becomes &lt;code&gt;&#34;12345&#34;&lt;/code&gt; and thus the
number of characters of that is the number of digits. If that wasn’t the case
I could still do&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ceiling(log10(314159))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 6&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but the &lt;code&gt;nchar()&lt;/code&gt; approach seems fine. Putting those pieces together into a
function which takes the number and how many places to move it, I get&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;rot &amp;lt;- function(n, k) {
  (n*10^k) %% (10^nchar(n)-1)
}
rot(12345, 3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 45123&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see that the values are ‘rotated’ cyclically by 3 places (to the left).&lt;/p&gt;
&lt;p&gt;R doesn’t have a built-in way to achieve this even for a vector of values
(rotating ‘digits’ of an integer is a toy problem that is unlikely to actually
come up in real situations). One solution is my
&lt;a href=&#34;https://github.com/jonocarroll/vec&#34;&gt;{vec}&lt;/a&gt; package which does implement a
ring-buffer sort of effect for vectors&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# remotes::install_github(&amp;quot;jonocarroll/vec&amp;quot;)
library(vec)
v &amp;lt;- as_vec(1:5)
rotate(v, 3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4 5 1 2 3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Under the hood this uses modulo on the &lt;em&gt;indices&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- 1:5; n &amp;lt;- 3
x[(((n - 1 + seq_along(x)) %% length(x))) + 1]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4 5 1 2 3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One extra feature of this is it also takes negative values to shift the other way&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;rotate(v, -3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3 4 5 1 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;whereas the &lt;code&gt;rot()&lt;/code&gt; implementation above can’t.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;julia&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Julia&lt;/h2&gt;
&lt;p&gt;As is almost always the case, the Julia functionality looks closer to what one
might “expect” from translating maths or stats; the power operator remains &lt;code&gt;^&lt;/code&gt;,
but the modulo operator is a more familiar &lt;code&gt;%&lt;/code&gt;. There is an actual &lt;code&gt;ndigits()&lt;/code&gt;
function to get the number of digits which, as far as I can tell from the source,
doesn’t first convert to character. The examples for that function do highlight
a failing of the R approach - if a value is negative then &lt;code&gt;as.character()&lt;/code&gt; will
produce the wrong number of digits. In R:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as.character(-1234)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;-1234&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nchar(-1234)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;while in Julia&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;ndigits(-1234)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’re not dealing with negatives here, but that’s certainly a gotcha.&lt;/p&gt;
&lt;p&gt;Implementing the Julia function can be done in a single line so no need for a
&lt;code&gt;function&lt;/code&gt; keyword&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;rot(n,k) = (n*10^k) % (10^ndigits(n)-1)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## rot (generic function with 1 method)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;rot(12345, 3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 45123&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we &lt;em&gt;were&lt;/em&gt; working with vectors, Julia also has a built-in way to do the
cyclic rotation, though it seems to shift in the opposite direction&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;x = [1, 2, 3, 4, 5]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 5-element Vector{Int64}:
##  1
##  2
##  3
##  4
##  5&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;circshift(x, -3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 5-element Vector{Int64}:
##  4
##  5
##  1
##  2
##  3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;circshift(x, 3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 5-element Vector{Int64}:
##  3
##  4
##  5
##  1
##  2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here ends the Algol-language portion of the post, and I’ll move on to some
languages where these operations are even more fundamental…&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;apl&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;APL&lt;/h2&gt;
&lt;p&gt;When I see ‘straightforward’ math operations on numbers I now think APL because
that’s what it was originally built for and it works so very well; each math
operation you could perform on an array of values has a ‘glyph’ representing it
so should be a better ‘translation’ of the math on a blackboard directly to code.&lt;/p&gt;
&lt;p&gt;One thing R users will immediately recognise is the assignment glyph &lt;code&gt;←&lt;/code&gt;; yes
that’s a single glyph, not R’s &lt;code&gt;&amp;lt;-&lt;/code&gt;, but it works the same as in R.&lt;/p&gt;
&lt;p&gt;You’re probably familiar with the multiplication glyph &lt;code&gt;×&lt;/code&gt; and addition &lt;code&gt;+&lt;/code&gt;.
The power/exponentiation glyph is &lt;code&gt;*&lt;/code&gt;. Nothing too surprising there, I hope.&lt;/p&gt;
&lt;p&gt;Because &lt;code&gt;-&lt;/code&gt; is the ‘subtract’ operation, there’s a distinct glyph for ‘negative’
&lt;code&gt;¯&lt;/code&gt; (a raised hyphen) so it isn’t confused with subtraction. Modulo takes some
more inspiration from math and is &lt;code&gt;|&lt;/code&gt;. The only other potentially confusing
glyphs are length &lt;code&gt;≢&lt;/code&gt; and format &lt;code&gt;⍕&lt;/code&gt; which, when combined, do something very
similar to R’s “how many characters does this use?”. Again the ‘negative number’
problem is here, but we’re not worried about that in this case.&lt;/p&gt;
&lt;p&gt;Putting those pieces together requires knowing that APL evaluates right-to-left,
with the argument to the right of an operator in a “function” being denoted by
omega (&lt;code&gt;⍵&lt;/code&gt;) and the one to the left being alpha (&lt;code&gt;⍺&lt;/code&gt;). The function I came up
with looks like this&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;    rot←{(¯1+10*≢⍕⍵)|⍵×10*⍺}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s entirely possible that it can be shortened or improved; I have a tendency
to overlook where parentheses are really required and opportunities for
simplification. Nonetheless, if you read from right-to-left it spells out the
calculation we want. Applying it to some value means placing it between its two
arguments&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;    3 rot 12345&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;45123&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;https://tryapl.org/?clear&amp;amp;q=rot%E2%86%90%7B(%C2%AF1%2B10*%E2%89%A2%E2%8D%95%E2%8D%B5)%7C%E2%8D%B5%C3%9710*%E2%8D%BA%7D%0A%20%20%20%20%20%203%20rot%2012345&amp;amp;run&#34;&gt;Try it out yourself!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Most of the difficulty I faced when building this was dealing with order-of-operations
which need to be right-to-left. There are ways to ‘swap’ the order of arguments
to a function (such as modulo) to make it read more similarly to the hand-written
expression, but I both couldn’t get that to produce the right answer and didn’t
feel it was necessary.&lt;/p&gt;
&lt;p&gt;In terms of working with vectors, that’s where APL shines. There is a rotate
glyph &lt;code&gt;⌽&lt;/code&gt; which when given just one argument reverses a vector, but with a second
argument does exactly what we want; rotates by that many places&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;    x←1 2 3 4 5
    3 ⌽ x
4 5 1 2 3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don’t look too closely at the &lt;em&gt;type&lt;/em&gt; of the data, we can use this to rotate
a string made of character digits by again using format &lt;code&gt;⍕&lt;/code&gt; to make a vector of
characters from the number&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;    3 ⌽ ⍕12345
45123&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(the whitespace here is purely for demonstration; &lt;code&gt;3⌽⍕12345&lt;/code&gt; works just the same).&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;uiua&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Uiua&lt;/h1&gt;
&lt;p&gt;Uiua is a much newer language that has a lot of support for operating on data,
but it behaves differently to all of the above; it’s a stack-based language so
you work with data on a stack, not as variables. I’ve played around with it and
really enjoy working with it - there’s even an
&lt;a href=&#34;https://exercism.org/tracks/uiua/&#34;&gt;Exercism track&lt;/a&gt; now - but in trying
to write this solution I realised that I’d only ever worked with one ‘thing’ on
the stack, even if that was an entire vector of values. This problem invites us
to work with a value to be rotated &lt;em&gt;and&lt;/em&gt; how many places to rotate it; that
meant I learned a &lt;em&gt;lot&lt;/em&gt; about figuring out which value from the stack I want.&lt;/p&gt;
&lt;p&gt;Entering operators into Uiua is greatly eased by having translation and
auto-complete; you don’t have to figure out how to type &lt;code&gt;◿&lt;/code&gt; you can start typing
&lt;code&gt;mod&lt;/code&gt; and as long as it’s a unique completion, Uiua will convert it to the
appropriate glyph. Additionally, there are some formatting tricks such as taking
a double-underscore suffix to a function to make a combined glyph with a preset
value; &lt;code&gt;log__10&lt;/code&gt; translates to &lt;code&gt;ₙ₁₀&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The operators I need here are modulo &lt;code&gt;◿&lt;/code&gt;, multiply &lt;code&gt;×&lt;/code&gt;, power &lt;code&gt;ⁿ&lt;/code&gt;, log10 &lt;code&gt;ₙ₁₀&lt;/code&gt;,
ceiling &lt;code&gt;⌈&lt;/code&gt;, and subtract &lt;code&gt;-&lt;/code&gt;, with the additional dip &lt;code&gt;⊙&lt;/code&gt; to use the second
value on the stack, and backward &lt;code&gt;˜&lt;/code&gt; to swap the arguments of modulo. I couldn’t
immediately think of a way to cleanly get the number of digits of a value (I did
later, which I’ll come back to) so I went the &lt;code&gt;log10&lt;/code&gt; route and my solution is
(again, right-to-left)&lt;/p&gt;
&lt;pre class=&#34;uiua&#34;&gt;&lt;code&gt;3 12345
˜◿⊙(-1˜ⁿ10⌈ₙ₁₀)⊸×˜ⁿ10&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;45123&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;https://uiua.org/pad?src=0_16_0-dev_2__MyAxMjM0NQrLnOKXv-KKmSgtMcuc4oG_MTDijIjigpnigoHigoAp4oq4w5fLnOKBvzEwCg==&#34;&gt;Try it out yourself!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Working with vectors is much cleaner here, too, and there’s a simple rotate &lt;code&gt;↻&lt;/code&gt;
that does the same as APL&lt;/p&gt;
&lt;pre class=&#34;uiua&#34;&gt;&lt;code&gt;↻ 3 [1 2 3 4 5]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[4 5 1 2 3]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reading this, the vector is placed on the stack, then the value 3 is put on the
top of the stack, then rotate takes two values from the stack and performs that
operation, leaving one value (the result) on the stack.&lt;/p&gt;
&lt;p&gt;Uiua also has a really cool feature of “undoing” an operation, where the inverse
can be calculated. If I wanted to turn a string into a number I would use parse
&lt;code&gt;⋕&lt;/code&gt; and I can do the opposite by prefixing it with un &lt;code&gt;°&lt;/code&gt; to make “unparse”
which converts a number to a string. Since a string is just a vector of
characters (in this case digits) the rotate works naturally, albeit returning a
string&lt;/p&gt;
&lt;pre class=&#34;uiua&#34;&gt;&lt;code&gt;↻ 3 °⋕ 12345&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;&amp;quot;45123&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Uiua goes one step further with an under &lt;code&gt;⍜&lt;/code&gt; which takes some value, performs
some transformation, applies a function, then &lt;em&gt;undoes&lt;/em&gt; that transformation. In my
case, I want to “unparse then re-parse” which seems like a great fit for this&lt;/p&gt;
&lt;pre class=&#34;uiua&#34;&gt;&lt;code&gt;⍜°⋕(↻ 3) 12345&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;45123&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and returns a number again, because under applies the back-transformation of parse.&lt;/p&gt;
&lt;p&gt;The unparse &lt;code&gt;°⋕&lt;/code&gt; is recognised as a compound and is passed as the first argument
to under, while I need the rotate and 3 to go together with parentheses. If I
always wanted to shift by 3 places I could use the double underscore to ‘attach’
the &lt;code&gt;3&lt;/code&gt; to the rotate producing &lt;code&gt;rotate__3&lt;/code&gt; &lt;code&gt;↻₃&lt;/code&gt; but what I have above allows for
changing that number.&lt;/p&gt;
&lt;p&gt;Looking into it this way, it’s more obvious that I could get the number of digits
with &lt;code&gt;lengthunparse&lt;/code&gt; as &lt;code&gt;⧻°⋕&lt;/code&gt;, but exploring how to go the long way around was
entirely worthwhile, and not necessarily longer with &lt;code&gt;ceilinglog__10&lt;/code&gt; as &lt;code&gt;⌈ₙ₁₀&lt;/code&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I knew I’d find lots of interesting things when I saw this and I was right - just
spending the time going through the documentation of these ‘basic’ functions
reminded me of things I’ve forgotten and some new things I don’t think I knew
before.&lt;/p&gt;
&lt;p&gt;I’d love to hear what people think about these comparisons - are there points I’ve
overlooked? Better ways to do it? Different functions in some other languages?
Considerations I’ve missed? As always, I can be found on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; and the comment section below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.4.1 (2024-06-14)
##  os       macOS 15.4.1
##  system   aarch64, darwin20
##  ui       X11
##  language (EN)
##  collate  en_US.UTF-8
##  ctype    en_US.UTF-8
##  tz       Australia/Adelaide
##  date     2025-05-03
##  pandoc   3.4 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/aarch64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version    date (UTC) lib source
##  blogdown      1.19       2024-02-01 [1] CRAN (R 4.4.0)
##  bookdown      0.41       2024-10-16 [1] CRAN (R 4.4.1)
##  bslib         0.8.0      2024-07-29 [1] CRAN (R 4.4.0)
##  cachem        1.1.0      2024-05-16 [1] CRAN (R 4.4.0)
##  cli           3.6.4      2025-02-13 [1] CRAN (R 4.4.1)
##  devtools      2.4.5      2022-10-11 [1] CRAN (R 4.4.0)
##  digest        0.6.37     2024-08-19 [1] CRAN (R 4.4.1)
##  ellipsis      0.3.2      2021-04-29 [1] CRAN (R 4.4.0)
##  evaluate      1.0.3      2025-01-10 [1] CRAN (R 4.4.1)
##  fastmap       1.2.0      2024-05-15 [1] CRAN (R 4.4.0)
##  fs            1.6.5      2024-10-30 [1] CRAN (R 4.4.1)
##  glue          1.8.0      2024-09-30 [1] CRAN (R 4.4.1)
##  htmltools     0.5.8.1    2024-04-04 [1] CRAN (R 4.4.0)
##  htmlwidgets   1.6.4      2023-12-06 [1] CRAN (R 4.4.0)
##  httpuv        1.6.15     2024-03-26 [1] CRAN (R 4.4.0)
##  jquerylib     0.1.4      2021-04-26 [1] CRAN (R 4.4.0)
##  jsonlite      2.0.0      2025-03-27 [1] CRAN (R 4.4.1)
##  JuliaCall     0.17.6     2024-12-07 [1] CRAN (R 4.4.1)
##  knitr         1.48       2024-07-07 [1] CRAN (R 4.4.0)
##  later         1.4.1      2024-11-27 [1] CRAN (R 4.4.1)
##  lifecycle     1.0.4      2023-11-07 [1] CRAN (R 4.4.0)
##  magrittr      2.0.3      2022-03-30 [1] CRAN (R 4.4.0)
##  memoise       2.0.1      2021-11-26 [1] CRAN (R 4.4.0)
##  mime          0.12       2021-09-28 [1] CRAN (R 4.4.0)
##  miniUI        0.1.1.1    2018-05-18 [1] CRAN (R 4.4.0)
##  pkgbuild      1.4.7      2025-03-24 [1] CRAN (R 4.4.1)
##  pkgload       1.4.0      2024-06-28 [1] CRAN (R 4.4.0)
##  profvis       0.4.0      2024-09-20 [1] CRAN (R 4.4.1)
##  promises      1.3.2      2024-11-28 [1] CRAN (R 4.4.1)
##  purrr         1.0.4      2025-02-05 [1] CRAN (R 4.4.1)
##  R6            2.6.1      2025-02-15 [1] CRAN (R 4.4.1)
##  Rcpp          1.0.14     2025-01-12 [1] CRAN (R 4.4.1)
##  remotes       2.5.0      2024-03-17 [1] CRAN (R 4.4.1)
##  rlang         1.1.5      2025-01-17 [1] CRAN (R 4.4.1)
##  rmarkdown     2.28       2024-08-17 [1] CRAN (R 4.4.0)
##  rstudioapi    0.17.1     2024-10-22 [1] CRAN (R 4.4.1)
##  sass          0.4.9      2024-03-15 [1] CRAN (R 4.4.0)
##  sessioninfo   1.2.2      2021-12-06 [1] CRAN (R 4.4.0)
##  shiny         1.9.1      2024-08-01 [1] CRAN (R 4.4.0)
##  urlchecker    1.0.1      2021-11-30 [1] CRAN (R 4.4.0)
##  usethis       3.1.0.9000 2025-03-31 [1] Github (r-lib/usethis@a653d6e)
##  vctrs         0.6.5      2023-12-01 [1] CRAN (R 4.4.0)
##  vec         * 0.1.0      2025-01-07 [1] Github (jonocarroll/vec@595b07e)
##  xfun          0.51       2025-02-19 [1] CRAN (R 4.4.1)
##  xtable        1.8-4      2019-04-21 [1] CRAN (R 4.4.0)
##  yaml          2.3.10     2024-07-26 [1] CRAN (R 4.4.0)
## 
##  [1] /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Function Generators vs Partial Application in R</title>
      <link>https://jcarroll.com.au/2025/04/25/function-generators-vs-partial-application-in-r/</link>
      <pubDate>Fri, 25 Apr 2025 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2025/04/25/function-generators-vs-partial-application-in-r/</guid>
      <description>&lt;p&gt;In which I confront the way I read code in different languages, and end up
wishing that R had a feature that it doesn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;This is a bit of a thought-dump as I consider some code - please don&amp;rsquo;t take it
as a criticism of any design choices; the tidyverse team have written magnitudes
more code that I have and have certainly considered their approach more than I
will. I believe it&amp;rsquo;s useful to challenge our own assumptions and dig in to how
we react to reading code.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.tidyverse.org/blog/2025/04/scales-1-4-0/&#34;&gt;The blog post&lt;/a&gt;
describing the latest updates to the tidyverse {scales} package neatly
demonstrates the usage of the new functionality, but because the examples are
written outside of actual plotting code, one feature stuck out to me in
particular&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;label_glue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;The {x} penguin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Gentoo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Chinstrap&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Adelie&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# The Gentoo penguin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# The Chinstrap penguin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# The Adelie penguin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, &lt;code&gt;label_glue&lt;/code&gt; is a function that takes a {glue} string as an argument and
returns a &amp;rsquo;labelling&amp;quot; function&amp;rsquo;. &lt;em&gt;That&lt;/em&gt; function is then passed the vector of
penguin species, which is used in the {glue} string to produce the output.&lt;/p&gt;
&lt;div class=&#34;notice&#34;&gt;
    &lt;p class=&#34;notice-title&#34;&gt;
        &lt;span class=&#34;icon-notice baseline&#34;&gt;
            📝
        &lt;/span&gt;
        Note 
    &lt;/p&gt;
    &lt;p&gt;For those coming to this post from a python background, {glue} is R&#39;s
answer to f-strings, and is used in almost the exact same way for simple cases:&lt;/p&gt;
  &lt;pre&gt;
  ## R:
  name &lt;- &#34;Jonathan&#34;
  glue::glue(&#34;My name is {name}&#34;)
  # My name is Jonathan

  ## Python:
  &gt;&gt;&gt; name = &#39;Jonathan&#39;
  &gt;&gt;&gt; f&#34;My name is {name}&#34;
  # &#39;My name is Jonathan&#39;
  &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;There&amp;rsquo;s nothing magic going on with the &lt;code&gt;label_glue()()&lt;/code&gt; call - functions are
being applied to arguments - but it&amp;rsquo;s always useful to interrogate surprise when
reading some code.&lt;/p&gt;
&lt;p&gt;Spelling out an example might be a bit clearer. A simplified version of
&lt;code&gt;label_glue&lt;/code&gt; might look like this&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;tmp_label_glue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pattern&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;{x}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;glue&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;glue_data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pattern&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This returns a function which takes one argument, so if we evaluate it we get&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;tmp_label_glue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;The {x} penguin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# function(x) {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#   glue::glue_data(list(x = x), pattern)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# }&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# &amp;lt;environment: 0x1137a72a8&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This has the benefit that we can store this result as a new named function&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;penguin_label&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;tmp_label_glue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;The {x} penguin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;penguin_label&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# function(x) {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#    glue::glue_data(list(x = x), pattern)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# }&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# &amp;lt;bytecode: 0x113914e48&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# &amp;lt;environment: 0x113ed4000&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;penguin_label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Gentoo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Chinstrap&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Adelie&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# The Gentoo penguin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# The Chinstrap penguin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# The Adelie penguin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is versatile, because different {glue} strings can produce different
functions - it&amp;rsquo;s a function generator. That&amp;rsquo;s neat if you &lt;em&gt;want&lt;/em&gt; different
functions, but if you&amp;rsquo;re only working with that one pattern, it can seem odd to
call it inline without naming it, as the earlier example&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;label_glue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;The {x} penguin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Gentoo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Chinstrap&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Adelie&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It &lt;em&gt;looks like&lt;/em&gt; we should be able to have all of these arguments in the same
function&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;label_glue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;The {x} penguin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Gentoo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Chinstrap&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Adelie&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;but apart from the fact that &lt;code&gt;label_glue&lt;/code&gt; doesn&amp;rsquo;t take the labels as an
argument, that doesn&amp;rsquo;t return a function, and the place where this will be used
&lt;em&gt;takes a function&lt;/em&gt; as the argument.&lt;/p&gt;
&lt;p&gt;So, why do the functions from {scales} take functions as arguments? The reason
would seem to be that this enables them to work &lt;em&gt;lazilly&lt;/em&gt; - we don&amp;rsquo;t necessarily
know the values we want to pass to the generated function at the call site;
maybe those are computed as part of the plotting process.&lt;/p&gt;
&lt;p&gt;We also don&amp;rsquo;t want to have to extract these labels out ourselves and compute on
them; it&amp;rsquo;s convenient to let the &lt;code&gt;scale_*&lt;/code&gt; function do that for us, if we just
provide a function for it to use when the time is right.&lt;/p&gt;
&lt;p&gt;But what &lt;em&gt;is&lt;/em&gt; passed to that generated function? That depends on where it&amp;rsquo;s
used&amp;hellip; if I used it in &lt;code&gt;scale_y_discrete&lt;/code&gt; then it might look like this&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;library&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ggplot2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;library&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;palmerpenguins&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ggplot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;penguins&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;[complete.cases&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;penguins&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;aes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bill_length_mm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;species&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;geom_point&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;scale_y_discrete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;labels&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;penguin_label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;since the &lt;code&gt;labels&lt;/code&gt; argument takes a function, and &lt;code&gt;penguin_label&lt;/code&gt; is a function
created above.&lt;/p&gt;
&lt;p&gt;I could equivalently write that as&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;scale_y_discrete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;labels&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;label_glue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;The {x} penguin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and not need the &amp;ldquo;temporary&amp;rdquo; function variable.&lt;/p&gt;
&lt;p&gt;So what gets passed in here? That&amp;rsquo;s a bit hard to dig out of the source, but one
could reasonably expect that at some point the supplied function will be called
with the available labels as an argument.&lt;/p&gt;
&lt;p&gt;I have a suspicion that the &amp;ldquo;external&amp;rdquo; use of this function, as&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;label_glue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;The {x} penguin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Gentoo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Chinstrap&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Adelie&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;is clashing with my (much more recent) understanding of Haskell and the way that
partial application works. In Haskell, &lt;em&gt;all&lt;/em&gt; functions take exactly 1 argument,
even if they look like they take more. This function&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ghci&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;do_thing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;z&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;z&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;looks like&lt;/em&gt; it takes 3 arguments, and it &lt;em&gt;looks like&lt;/em&gt; you can use it that way&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ghci&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;do_thing&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;but &lt;em&gt;really&lt;/em&gt;, each &amp;ldquo;layer&amp;rdquo; of arguments is a function with 1 argument, i.e. an
honest R equivalent would be&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;do_thing&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;z&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;z&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;do_thing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# [1] 9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What&amp;rsquo;s important here is that we can &amp;ldquo;peel off&amp;rdquo; some of the layers, and we get
back a function that takes the remaining argument(s)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;do_thing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# function(z) {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#    x + y + z&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# }&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# &amp;lt;bytecode: 0x116b72ba0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# &amp;lt;environment: 0x116ab2778&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;partial&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;do_thing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;partial&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# [1] 9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In Haskell, that looks like this&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ghci&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;partial&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;do_thing&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ghci&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;partial&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Requesting the type signature of this function shows&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ghci&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;do_thing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;do_thing&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;::&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;Num&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;so it&amp;rsquo;s a function that takes some value of type &lt;code&gt;a&lt;/code&gt; (which needs to be a &lt;code&gt;Num&lt;/code&gt;
because we&amp;rsquo;re using &lt;code&gt;+&lt;/code&gt; for addition; this is inferred by the compiler) and then
we have&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;a -&amp;gt; a -&amp;gt; a -&amp;gt; a
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This can be read as &amp;ldquo;a function that takes 3 values of a type &lt;code&gt;a&lt;/code&gt; and returns 1
value of that same type&amp;rdquo; but equivalently (literally; this is all just syntactic
sugar) we can write it as&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;a -&amp;gt; (a -&amp;gt; (a -&amp;gt; a))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;which is &amp;ldquo;takes a value of type &lt;code&gt;a&lt;/code&gt; and returns a function that takes a value of
type &lt;code&gt;a&lt;/code&gt;, which itself returns a function that takes a value of type &lt;code&gt;a&lt;/code&gt; and
returns a value of type &lt;code&gt;a&lt;/code&gt;&amp;rdquo;. With a bit of ASCII art&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;a -&amp;gt; (a -&amp;gt; (a -&amp;gt; a))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;|     |     |    |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;|     |     |_z__|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;|     |_y________|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;|_x______________|     
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we ask for the type signature when &lt;em&gt;some of&lt;/em&gt; the arguments are provided&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ghci&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;do_thing&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;do_thing&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;::&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;Num&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;we see that now it is a function of a single variable (&lt;code&gt;a -&amp;gt; a&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;With that in mind, the labelling functions look like a great candidate for
partially applied functions! If we had&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;label_glue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pattern&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;labels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;then&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;label_glue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pattern&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;would be a function &amp;ldquo;waiting&amp;rdquo; for a &lt;code&gt;labels&lt;/code&gt; argument. Isn&amp;rsquo;t that the same as
what we have? Almost, but not quite. &lt;code&gt;label_glue&lt;/code&gt; doesn&amp;rsquo;t take a &lt;code&gt;labels&lt;/code&gt;
argument, it returns a function which will use them, so the lack of the &lt;code&gt;labels&lt;/code&gt;
argument isn&amp;rsquo;t a signal for this. &lt;code&gt;label_glue(pattern)&lt;/code&gt; still returns a
function, but that&amp;rsquo;s not obvious, especially when used inline as&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;scale_y_discrete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;labels&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;label_glue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;The {x} penguin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When I read R code like that I see the parentheses at the end of &lt;code&gt;label_glue&lt;/code&gt;
and read it as &amp;ldquo;this is a function invocation; the return value will be used
here&amp;rdquo;. That&amp;rsquo;s correct, but in this case the return value is another function.
There&amp;rsquo;s nothing here that says &amp;ldquo;this will return a function&amp;rdquo;. There&amp;rsquo;s no
convention in R for signalling this (and being dynamically typed, all one can do
is read the documentation) but one could imagine one, e.g. &lt;code&gt;label_glue_F&lt;/code&gt; in a
similar fashion to how Julia uses an exclamation mark to signify an in-place
mutating function; &lt;code&gt;sort!&lt;/code&gt; vs &lt;code&gt;sort&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Passing around functions is all the rage in functional programming, and it&amp;rsquo;s how
you can do things like this&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sapply&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mtcars[&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mean&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#      mpg       cyl      disp        hp &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 20.09062   6.18750 230.72188 146.68750 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here I&amp;rsquo;m passing a list (the first four columns of the &lt;code&gt;mtcars&lt;/code&gt; dataset) and a
&lt;em&gt;function&lt;/em&gt; (&lt;code&gt;mean&lt;/code&gt;, by name) to &lt;code&gt;sapply&lt;/code&gt; which essentially does a &lt;code&gt;map(l, f)&lt;/code&gt;
and produces the mean of each of these columns, returning a named vector of the
means.&lt;/p&gt;
&lt;p&gt;That becomes very powerful where partial application is allowed, enabling things
like&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-haskell&#34; data-lang=&#34;haskell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ghci&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add_5&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ghci&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add_5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;13&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In R, we would need to create a new function more explicitly, i.e. referring to
an arbitrary argument&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;add_5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sapply&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add_5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# [1]  6  7  8  9 10 11 12 13 14 15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Maybe my pattern-recognition has become a bit too overfitted on the idea that in
R &amp;ldquo;no parentheses = function, not result; parentheses = result&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;This reads weirdly to me&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;calc_mean&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;mean&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sapply&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mtcars[&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;calc_mean&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;but it&amp;rsquo;s exactly the same as the earlier example, since &lt;code&gt;calc_mean()&lt;/code&gt;
essentially returns a &lt;code&gt;mean&lt;/code&gt; function&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;calc_mean&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;[1]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;5.5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For that reason, I like the idea of naming the labelling function, since I read
this&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;scale_y_discrete&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;labels&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;penguin_label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;as passing a &lt;em&gt;function&lt;/em&gt;. The parentheses get used in the right place - where the
function has been called.&lt;/p&gt;
&lt;p&gt;Now, having to define that variable just to use it in the &lt;code&gt;scale_y_discrete&lt;/code&gt;
call is probably a bit much, so yeah, inlining it makes sense, with the caveat
that &lt;em&gt;you have to know it&amp;rsquo;s a function&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;None of this was meant to say that the {scales} approach is wrong in any way - I
just wanted to address my own perceptions of the &lt;code&gt;arg = fun()&lt;/code&gt; design. It &lt;em&gt;does&lt;/em&gt;
make sense, but it looks different. Am I alone on this?&lt;/p&gt;
&lt;p&gt;Let me know on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; and/or the comment
section below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
  &lt;summary&gt;
    &lt;tt&gt;devtools::session_info()&lt;/tt&gt;
  &lt;/summary&gt;
```{r sessionInfo, echo = FALSE}
devtools::session_info()
```
&lt;/details&gt;
&lt;br /&gt;</description>
    </item>
    
    <item>
      <title>Book Review - Pandas Workout</title>
      <link>https://jcarroll.com.au/2025/02/13/book-review-pandas-workout/</link>
      <pubDate>Thu, 13 Feb 2025 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2025/02/13/book-review-pandas-workout/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;images/snakes.jpg&#34; width=&#34;600&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Python seems to be everywhere these days, and I’m really into learning languages,
so it should come as no surprise that I’m learning a lot of Python. This post
serves as a review of &lt;a href=&#34;https://mng.bz/0GVW&#34;&gt;Pandas Workout&lt;/a&gt; as well as a
‘first impression’ review of the Pandas approach to data.&lt;/p&gt;
&lt;p&gt;I am not entirely unfamiliar with Python, but I haven’t really had to do anything
serious with a lot of data in the way that I do with R. {dplyr} and friends make
working with rectangular data so clean and simple; why would I want anything else?&lt;/p&gt;
&lt;p&gt;I recently needed to work with an API that would return some tabular data - it
enables programmatic communication with a system containing a lot of data, and the
only wrapper I could find for it was in Python (and not all that well documented).
I’ve built &lt;a href=&#34;https://github.com/HIBio/benchlingapi&#34;&gt;a wrapper&lt;/a&gt; for a very similar
system myself using {httr} in R but I didn’t necessarily want to go through all
of that again. “Fine, I’ll use Python” I said, and promptly realised that I wasn’t
familiar with how to rectangle the resulting data.&lt;/p&gt;
&lt;p&gt;Around the same time as the API needed wrapping I was fortunate enough to be asked
to review the book &lt;a href=&#34;https://mng.bz/0GVW&#34;&gt;Pandas Workout&lt;/a&gt; written by
Reuven Lerner, from Manning Publications. I really enjoy books from Manning - I
published my own book
&lt;a href=&#34;https://www.manning.com/books/beyond-spreadsheets-with-r&#34;&gt;Beyond Spreadsheets with R&lt;/a&gt;
with them and I’m grateful for their DRM-free offerings across a wide range of
tech topics. What a perfect opportunity! I will note that apart from receiving a
digital copy of the book to review, I was not otherwise paid or compensated for
this review. If I’m reviewing a book, it’s an honest review.&lt;/p&gt;
&lt;p&gt;As I’m entirely unfamiliar with Pandas but know enough Python to keep my head above
water, this seemed like a good chance to review both at the same time; how well
does this book provide an introduction to Pandas for a newcomer?&lt;/p&gt;
&lt;p&gt;The subtitle of the book is “200 Exercises to Strengthen Your Data Analysis Skills”
and it delivers on the ‘exercises’ part, providing real-world data import/cleaning
tasks that go well beyond a &lt;code&gt;mtcars&lt;/code&gt; dataset.&lt;/p&gt;
&lt;p&gt;I’m halfway through the book, and I’m actually following the exercises by typing out
my own solutions in a python file and/or the REPL - “you learn with your hands, not
your eyes”.&lt;/p&gt;
&lt;p&gt;The first problem, since this is python, is getting Pandas to work with a script,
which means dealing with environments, since &lt;a href=&#34;https://jvns.ca/til/pip-install---user-can-override-system-libraries/&#34;&gt;&lt;code&gt;pip&lt;/code&gt; now tries&lt;/a&gt;
to prevent us from &lt;a href=&#34;https://gist.github.com/jvns/3f3da9a557bfff478f6f0145f1b6b52f&#34;&gt;messing up our global package availability&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I figured this was a good time to try out &lt;a href=&#34;https://docs.astral.sh/uv/&#34;&gt;&lt;code&gt;uv&lt;/code&gt; as an alternative to &lt;code&gt;pip&lt;/code&gt;&lt;/a&gt; and as far as I can tell, this worked well. I
don’t have expectations that Pandas Workout should have guided me through any of
the “get Python environments working” parts as it does assume Python knowledge,
but the author mentions using &lt;code&gt;pip install pandas&lt;/code&gt; which doesn’t really cut it
(though plausibly did at the time of writing, April 2024).
Apart from that, it’s just a matter of&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;import pandas as pd&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(and all of the Python code in this post is generated from the code blocks thanks
to {reticulate} and its virtualenv support).&lt;/p&gt;
&lt;p&gt;There’s a joke to be made here about my home city Adelaide and the fact that we
have once again &lt;a href=&#34;https://www.adelaidezoo.com.au/giant-panda-debut/&#34;&gt;imported some pandas&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/pandas.jpg&#34; width=&#34;600&#34; alt=&#34;import pandas&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;import pandas&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Chapter 1 walks through using the &lt;code&gt;Series&lt;/code&gt; data type, which for an R user is most
similar to a regular vector, except that there isn’t a strict restriction on the
‘singular’ type of the elements; if you provide a mixture of types the resulting
&lt;code&gt;Series&lt;/code&gt; will have &lt;code&gt;dtype: object&lt;/code&gt;. This is, I suspect, a necessity, given that
Python doesn’t have the ‘classed NA’ values that R uses - all of the elements of&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- c(1L, NA, 3L)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;are the same class (‘type’); integer, including the missing value&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x[2]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] NA&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;class(x[2])&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;integer&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is actually &lt;code&gt;NA_integer_&lt;/code&gt;. &lt;code&gt;pd.Series([1, pd.NA, 3])&lt;/code&gt; still produces
&lt;code&gt;dtype: object&lt;/code&gt;, and can’t be converted to &lt;code&gt;np.int8&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The first real annoyance comes when describing how indexing works in Pandas vs
regular Python; the endpoint of the &lt;code&gt;s.loc[]&lt;/code&gt; syntax is “up to and including”
whereas Python would usually use “up to and &lt;strong&gt;not&lt;/strong&gt; including”. There’s reasons,
but things like this are good to keep in the back of one’s mind whenever someone
complains that “R is confusing/inconsistent”. With that said, it’s called out in
Pandas Workout with some concrete examples, so it shouldn’t be a gotcha.&lt;/p&gt;
&lt;p&gt;Where an inconsistency isn’t so well handled is when mentioning rounding of values;
Pandas Workout suggests&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Be sure to read the documentation for the round method (&lt;a href=&#34;http://mng.bz/8rzg&#34; class=&#34;uri&#34;&gt;http://mng.bz/8rzg&lt;/a&gt;)
to understand its arguments and how it handles numbers like 15 and 75.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;which points to the
&lt;a href=&#34;https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.round.html&#34;&gt;documentation for &lt;code&gt;pd.Series.round&lt;/code&gt;&lt;/a&gt;
but that makes no mention of how these halfway values are handled - I dug up the
&lt;a href=&#34;https://note.nkmk.me/en/python-pandas-round-decimal/&#34;&gt;answer myself&lt;/a&gt; and Pandas
does “banker’s rounding” taking half-values to evens. Trying this out myself
also demonstrates this&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;pd.Series([0.2, 0.5, 1.5, 2.5, 3.5]).round()&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 0    0.0
## 1    0.0
## 2    2.0
## 3    2.0
## 4    4.0
## dtype: float64&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Incidentally, this is the same for R&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;round(c(0.2, 0.5, 1.5, 2.5, 3.5))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 0 0 2 2 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some additional &lt;code&gt;Series&lt;/code&gt; gotchas are detailed, including the fact that while this
monstrosity works in Python&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;&amp;#39;1&amp;#39; + &amp;#39;2&amp;#39; + &amp;#39;3&amp;#39; + &amp;#39;4&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;#39;1234&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and this does not&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;sum([&amp;#39;1&amp;#39;, &amp;#39;2&amp;#39;, &amp;#39;3&amp;#39;, &amp;#39;4&amp;#39;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-danger&#34;&gt;&lt;code&gt;## TypeError: unsupported operand type(s) for +: &amp;#39;int&amp;#39; and &amp;#39;str&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;this one does in fact work&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;pd.Series([&amp;#39;1&amp;#39;, &amp;#39;2&amp;#39;, &amp;#39;3&amp;#39;, &amp;#39;4&amp;#39;]).sum()&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;#39;1234&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The similarities between R’s (named) vectors and Pandas’ &lt;code&gt;Series&lt;/code&gt; help me to grasp
what I might want to do with these, but there are some distinct differences in
how the ‘index’/‘name’ part is handled; In R the names &lt;em&gt;can&lt;/em&gt; be repeated, although
that makes it very difficult to extract elements based on names&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- c(a = 1, b = 2, a = 3, d = 4)
x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## a b a d 
## 1 2 3 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;names(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;a&amp;quot; &amp;quot;b&amp;quot; &amp;quot;a&amp;quot; &amp;quot;d&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x[&amp;quot;a&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## a 
## 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;whereas in Pandas the index can be repeated and extracting with a repeated value
actually returns all the relevant values&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;x = pd.Series([1, 2, 3, 4], index=list(&amp;#39;abad&amp;#39;))
x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## a    1
## b    2
## a    3
## d    4
## dtype: int64&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;x.loc[&amp;#39;a&amp;#39;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## a    1
## a    3
## dtype: int64&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which means that &lt;code&gt;x.loc[z]&lt;/code&gt; is essentially &lt;code&gt;x[names(x) == z]&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x[names(x) == &amp;quot;a&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## a a 
## 1 3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As a sidenote, that “use a list as a series of characters” bit is going to take
me a while to get used to, but I see the value of it. One of my big regrets about
R is that strings are &lt;em&gt;not&lt;/em&gt; vectors of characters; something I worked around by
making &lt;a href=&#34;https://github.com/jonocarroll/charcuterie&#34;&gt;my own “character vector” class&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What really blew my mind was the behaviour around adding two &lt;code&gt;Series&lt;/code&gt; with overlapping
indexes; the comparison is explicitly based on the index, so &lt;code&gt;&#39;a&#39;&lt;/code&gt; matches to &lt;code&gt;&#39;a&#39;&lt;/code&gt; and
&lt;code&gt;&#39;d&#39;&lt;/code&gt; matches to &lt;code&gt;&#39;d&#39;&lt;/code&gt; regardless of where they appear in the &lt;code&gt;Series&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;s1 = pd.Series([10, 20, 30, 40], index=list(&amp;#39;abcd&amp;#39;))
s1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## a    10
## b    20
## c    30
## d    40
## dtype: int64&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;s2 = pd.Series([100, 200, 300, 400], index=list(&amp;#39;dcba&amp;#39;))
s2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## d    100
## c    200
## b    300
## a    400
## dtype: int64&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;s1+s2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## a    410
## b    320
## c    230
## d    140
## dtype: int64&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This seems like such an obvious choice - I had to double check what happens in R
and a worried look started to creep across my face&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;s1 = c(a = 10, b = 20, c = 30, d = 40)
s1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  a  b  c  d 
## 10 20 30 40&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;s2 = c(d = 100, c = 200, b = 300, a = 400)
s2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   d   c   b   a 
## 100 200 300 400&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;s1 + s2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   a   b   c   d 
## 110 220 330 440&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/ohno.jpg&#34; width=&#34;300&#34; alt=&#34;oh no!&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;oh no!&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;R just ignores the names entirely. If I &lt;em&gt;wanted&lt;/em&gt; the same behaviour, I’d need to
do the aligning myself&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;s1[order(names(s1))] + s2[order(names(s2))]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   a   b   c   d 
## 410 320 230 140&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Closing out the chapter is a set of exercises using some real data. There is a
link to that data on the book website, but that location is not mentioned in the
book itself, which isn’t ideal. There is a hyperlink in the PDF version&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The data is in the file &lt;a href=&#34;https://github.com/reuven/pandas-workout&#34;&gt;taxi-passenger-count.csv&lt;/a&gt;, available along with the other data files used in this course.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;but that points to a repository of the &lt;em&gt;exercises&lt;/em&gt;, not the data. I presume the
print version lacks a way for the reader to find this data. These sort of
mistakes happen - I noted some of them on &lt;a href=&#34;https://livebook.manning.com/forum?product=lerner2&amp;amp;p=1&amp;amp;page=1&#34;&gt;Manning’s discussion forum&lt;/a&gt; but did not
hear back from the author about any of them yet.&lt;/p&gt;
&lt;p&gt;It’s worth mentioning that while the data is from the real world and has genuine
‘problems’ that one would experience when performing an analysis, the data is a
single zip file comprising a whopping 852MB download, which might be a bit much
for some people.&lt;/p&gt;
&lt;p&gt;Chapter 2 naturally moves on to &lt;code&gt;DataFrame&lt;/code&gt;s; rectangular structures constructed
as a combination of multiple &lt;code&gt;Series&lt;/code&gt; (though the only mention along those lines
seems to be a throwaway comment to that effect).&lt;/p&gt;
&lt;p&gt;The humble ‘Data Frame’ (&lt;code&gt;data.frame&lt;/code&gt;) in R is a core data type. I’m not entirely
clear on the history, but they were present in R’s predecessor language &lt;a href=&#34;https://archive.org/details/statisticalmodel00john/page/n13/mode/2up&#34;&gt;S in 1992&lt;/a&gt; and
likely even earlier. Nowadays, lots of Data Frame implementations exist for the
purpose of rectangling - and slicing thereof - including &lt;a href=&#34;https://docs.rs/polars/latest/polars/&#34;&gt;Polars in Rust&lt;/a&gt;, &lt;a href=&#34;https://tidierorg.github.io/TidierData.jl/latest/&#34;&gt;Tidier.jl in Julia&lt;/a&gt;, &lt;a href=&#34;https://github.com/mchav/dataframe&#34;&gt;dataframe in Haskell&lt;/a&gt;, &lt;a href=&#34;https://github.com/alex-hhh/data-frame&#34;&gt;data-frame in Racket&lt;/a&gt;, and I’m sure many others. This
structure resembles a database table and operations on these tend to mimic SQL
syntax - think filter, select, join, etc…&lt;/p&gt;
&lt;p&gt;In R, I know that &lt;code&gt;data.frame&lt;/code&gt; is &lt;em&gt;explicitly&lt;/em&gt; a “list of vectors all of the
same length” but that seems to be glossed over here in favor of “you know about
tables - this is similar”. The constructor examples show either a list of lists
or a list of dicts, and that’s perhaps because a list of &lt;code&gt;Series&lt;/code&gt; objects doesn’t
do what I expect&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;a = pd.Series([1, 2, 3])
b = pd.Series([4, 5, 6])
pd.DataFrame([a, b])&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##    0  1  2
## 0  1  2  3
## 1  4  5  6&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The resulting &lt;code&gt;DataFrame&lt;/code&gt; is created row-wise, which is enough of a headache in R,
let alone the differences here depending on how the object is created.&lt;/p&gt;
&lt;p&gt;There are apparently a handful of ways one &lt;em&gt;can&lt;/em&gt; do this, but they’re not
mentioned in the book&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;a = pd.Series([1, 2, 3])
b = pd.Series([4, 5, 6])

pd.DataFrame({&amp;#39;a&amp;#39;:a, &amp;#39;b&amp;#39;:b})&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##    a  b
## 0  1  4
## 1  2  5
## 2  3  6&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;pd.DataFrame(dict(a=a, b=b))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##    a  b
## 0  1  4
## 1  2  5
## 2  3  6&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;pd.concat([a, b], axis=1, keys=list(&amp;#39;ab&amp;#39;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##    a  b
## 0  1  4
## 1  2  5
## 2  3  6&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I was also curious about what happens if they &lt;em&gt;aren’t&lt;/em&gt; the same length&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;a = pd.Series([1, 2, 3])
b = pd.Series([4, 5, 6, 7])

pd.DataFrame({&amp;#39;a&amp;#39;:a, &amp;#39;b&amp;#39;:b})&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      a  b
## 0  1.0  4
## 1  2.0  5
## 2  3.0  6
## 3  NaN  7&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The inserted &lt;code&gt;NaN&lt;/code&gt; is perhaps potentially surprising; R bails out of trying to
construct such an object&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- c(1, 2, 3)
b &amp;lt;- c(4, 5, 6, 7)

data.frame(a, b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in data.frame(a, b): arguments imply differing number of rows: 3, 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;except when it tries to be clever by recycling some values, with often
surprising results…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- 1:3
b &amp;lt;- 4:9

data.frame(a, b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   a b
## 1 1 4
## 2 2 5
## 3 3 6
## 4 1 7
## 5 2 8
## 6 3 9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The various methods for subsetting rows and columns mostly makes sense coming from
R, although it will still take me some time to get used to seeing things like&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;df[list(&amp;#39;bcd&amp;#39;)]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to extract the columns labelled &lt;code&gt;&#39;b&#39;&lt;/code&gt;, &lt;code&gt;&#39;c&#39;&lt;/code&gt;, and &lt;code&gt;&#39;d&#39;&lt;/code&gt;. One thing I noticed here
was that there was only one axis specified for extraction here (column) and while
the same thing works in R, e.g.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m &amp;lt;- head(mtcars)
m[c(&amp;quot;cyl&amp;quot;, &amp;quot;mpg&amp;quot;, &amp;quot;wt&amp;quot;)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##                   cyl  mpg    wt
## Mazda RX4           6 21.0 2.620
## Mazda RX4 Wag       6 21.0 2.875
## Datsun 710          4 22.8 2.320
## Hornet 4 Drive      6 21.4 3.215
## Hornet Sportabout   8 18.7 3.440
## Valiant             6 18.1 3.460&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;the absence of a note about it was probably an oversight. In R, if the vector
specifying the selection contains any missing values (NA) then an error is
triggered&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m[c(&amp;quot;cyl&amp;quot;, NA, &amp;quot;wt&amp;quot;)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in `[.data.frame`(m, c(&amp;quot;cyl&amp;quot;, NA, &amp;quot;wt&amp;quot;)): undefined columns selected&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is confusing, for sure. R is fine with us selecting missing rows&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m[c(1, NA, 3), ]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##             mpg cyl disp  hp drat   wt  qsec vs am gear carb
## Mazda RX4  21.0   6  160 110 3.90 2.62 16.46  0  1    4    4
## NA           NA  NA   NA  NA   NA   NA    NA NA NA   NA   NA
## Datsun 710 22.8   4  108  93 3.85 2.32 18.61  1  1    4    1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but not missing columns&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m[1:3, c(1, NA, 3)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in `[.data.frame`(m, 1:3, c(1, NA, 3)): undefined columns selected&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, what about Pandas? The fact that &lt;code&gt;x[cols]&lt;/code&gt; works to select columns, but
selecting rows requires &lt;code&gt;x.loc[rows, cols]&lt;/code&gt; is a bit ugly, in my opinion, and
there are parallels here with the mess of R’s &lt;code&gt;drop=TRUE&lt;/code&gt; argument which results in
a vector rather than a &lt;code&gt;data.frame&lt;/code&gt; when only a single dimension is selected.&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;x = pd.DataFrame({&amp;#39;a&amp;#39;:a, &amp;#39;b&amp;#39;:b})
x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      a  b
## 0  1.0  4
## 1  2.0  5
## 2  3.0  6
## 3  NaN  7&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;x[&amp;#39;a&amp;#39;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 0    1.0
## 1    2.0
## 2    3.0
## 3    NaN
## Name: a, dtype: float64&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;x.loc[:, &amp;#39;a&amp;#39;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 0    1.0
## 1    2.0
## 2    3.0
## 3    NaN
## Name: a, dtype: float64&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;x.loc[1:2, [&amp;#39;a&amp;#39;, &amp;#39;b&amp;#39;]]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      a  b
## 1  2.0  5
## 2  3.0  6&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;x.loc[1:2, [&amp;#39;a&amp;#39;, pd.NA]]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## KeyError: &amp;#39;[&amp;lt;NA&amp;gt;] not in index&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One powerful but dangerous feature of {dplyr} (and some parts of base R) is
Non-Standard Evaluation (NSE) which enables a ‘shortcut’ in writing out expressions
for filtering or selecting data in a &lt;code&gt;data.frame&lt;/code&gt;. Essentially, the user can
use column names as variables and they are translated as such within the function,
so rather than writing out&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;filter(mydataframe, mydataframe$a &amp;gt; 300 &amp;amp; mydataframe$w %% 2 == 1)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;one can use the column names ‘a’ and ‘w’ as if they were defined as variables&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;filter(mydataframe, a &amp;gt; 300 &amp;amp; w %% 2 == 1)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is handy, but of course has some sharp edges. I have mixed feelings about
finding the equivalent in Pandas in the form of &lt;code&gt;df.query&lt;/code&gt;. This takes an SQL-like
statement and similarly treats columns as variables, but in this case the entire
thing is provided as a string&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;df.query(&amp;#39;v &amp;gt; 300 &amp;amp; w % 2 == 1&amp;#39;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I imagine this is incompatible with any language-server features, though the
metaprogramming-enjoying part of me does wonder if it makes building up these
expressions programatically a little easier.&lt;/p&gt;
&lt;p&gt;Another gotcha mentioned in this section is the fact that Pandas makes internal
copies of data, and produces an interesting warning&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;df = pd.DataFrame(
    {&amp;#39;a&amp;#39;: [10, 50, 90],
     &amp;#39;b&amp;#39;: [20, 60, 100],
     &amp;#39;c&amp;#39;: [30, 70, 110],
     &amp;#39;d&amp;#39;: [40, 80, 120]},
     index = list(&amp;#39;xyz&amp;#39;))
df[df[&amp;#39;b&amp;#39;] &amp;gt; 30][&amp;#39;b&amp;#39;] = 0
df&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-warning&#34;&gt;&lt;code&gt;## &amp;lt;string&amp;gt;:1: SettingWithCopyWarning: 
## A value is trying to be set on a copy of a slice from a DataFrame.
## Try using .loc[row_indexer,col_indexer] = value instead
## 
## See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(with the value not being set to 0).&lt;/p&gt;
&lt;p&gt;This is reminiscent of SQL ‘views’ into data - and not being able to modify
those - and that seems like a useful feature, but it again makes me wonder what
happens in R…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;df &amp;lt;- data.frame(a = c(10, 50, 90),
                 b = c(20, 60, 100),
                 c = c(30, 70, 110), 
                 d = c(40, 80, 120), 
                 row.names = c(&amp;quot;x&amp;quot;, &amp;quot;y&amp;quot;, &amp;quot;z&amp;quot;))
dfo &amp;lt;- df
df&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##    a   b   c   d
## x 10  20  30  40
## y 50  60  70  80
## z 90 100 110 120&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following updates all of the &lt;code&gt;b&lt;/code&gt; column because as we saw above, just
specifying a single selector restricts the columns, so since &lt;code&gt;df$b &amp;gt; 30&lt;/code&gt; is
&lt;code&gt;c(FALSE, TRUE, TRUE)&lt;/code&gt; the intermediate subset is just the second and third
columns (“b” and “c”) after which we select the “b” column and assign the value
of &lt;code&gt;0&lt;/code&gt; to all elements. No actual filtering of rows has occurred here, and the
entire column in the full data is updated&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;df[df$b &amp;gt; 30][&amp;quot;b&amp;quot;] &amp;lt;- 0 
df&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##    a b   c   d
## x 10 0  30  40
## y 50 0  70  80
## z 90 0 110 120&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Equivalently, &lt;code&gt;[][[&#34;b&#34;]]&lt;/code&gt; or &lt;code&gt;[]$b&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In order to select rows for which &lt;code&gt;b &amp;gt; 30&lt;/code&gt; this needs to &lt;code&gt;df[df$b &amp;gt; 30, ]&lt;/code&gt; (with
a comma), and this updates just the relevant slice (again in the full data)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;df &amp;lt;- dfo
df[df$b &amp;gt; 30, ]$b &amp;lt;- 0 
df&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##    a  b   c   d
## x 10 20  30  40
## y 50  0  70  80
## z 90  0 110 120&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and this works just fine in R, despite the fact that we have explicitly subset
the data prior to selecting a column, and assigned a value to that subset.&lt;/p&gt;
&lt;p&gt;Maybe that warning isn’t a bad thing at all - such subsets are done regularly in
R, and there’s no memory issues with doing so (it’s well-defined in terms of &lt;code&gt;[.&amp;lt;-&lt;/code&gt;)
but I can see why it’s confusing.&lt;/p&gt;
&lt;p&gt;Chapter 3 details importing and exporting data, and it’s here that I start to see
how much has been rolled into Pandas - things that are spread across several R
packages.&lt;/p&gt;
&lt;p&gt;I’m familiar with scraping HTML tables from websites in R - there are many base
packages which can read from a URL, and several ways to convert the resulting
data into a rectangle such as a &lt;code&gt;data.frame&lt;/code&gt;, but Pandas surprises me with
&lt;code&gt;pd.read_html(url)&lt;/code&gt; which returns a list of &lt;code&gt;DataFrame&lt;/code&gt;s, one for each table on a
webpage. Trying this out, it works quite nicely&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;url = &amp;#39;https://en.wikipedia.org/wiki/R_(programming_language)#Version_names&amp;#39;
tabs = pd.read_html(url)[1]
x=tabs.loc[:,[&amp;#39;Version&amp;#39;, &amp;#39;Name&amp;#39;, &amp;#39;Release date&amp;#39;]]
x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##     Version                      Name Release date
## 0     4.4.2            Pile of Leaves   2024-10-31
## 1     4.4.1        Race for Your Life   2024-06-14
## 2     4.4.0                 Puppy Cup   2024-04-24
## 3     4.3.3           Angel Food Cake   2024-02-29
## 4     4.3.2                 Eye Holes   2023-10-31
## 5     4.3.1             Beagle Scouts   2023-06-16
## 6     4.3.0          Already Tomorrow   2023-04-21
## 7     4.2.3          Shortstop Beagle   2023-03-15
## 8     4.2.2     Innocent and Trusting   2022-10-31
## 9     4.2.1         Funny-Looking Kid   2022-06-23
## 10    4.2.0     Vigorous Calisthenics   2022-04-22
## 11    4.1.3               One Push-Up   2022-03-10
## 12    4.1.2               Bird Hippie   2021-11-01
## 13    4.1.1               Kick Things   2021-08-10
## 14    4.1.0           Camp Pontanezen   2021-05-18
## 15    4.0.5           Shake and Throw   2021-03-31
## 16    4.0.4         Lost Library Book   2021-02-15
## 17    4.0.3   Bunny-Wunnies Freak Out   2020-10-10
## 18    4.0.2          Taking Off Again   2020-06-22
## 19    4.0.1            See Things Now   2020-06-06
## 20    4.0.0                 Arbor Day   2020-04-24
## 21    3.6.3      Holding the Windsock   2020-02-29
## 22    3.6.2     Dark and Stormy Night   2019-12-12
## 23    3.6.1        Action of the Toes   2019-07-05
## 24    3.6.0        Planting of a Tree   2019-04-26
## 25    3.5.3               Great Truth   2019-03-11
## 26    3.5.2           Eggshell Igloos   2018-12-20
## 27    3.5.1             Feather Spray   2018-07-02
## 28    3.5.0            Joy in Playing   2018-04-23
## 29    3.4.4        Someone to Lean On   2018-03-15
## 30    3.4.3          Kite-Eating Tree   2017-11-30
## 31    3.4.2              Short Summer   2017-09-28
## 32    3.4.1             Single Candle   2017-06-30
## 33    3.4.0       You Stupid Darkness   2017-04-21
## 34    3.3.3             Another Canoe   2017-03-06
## 35    3.3.2     Sincere Pumpkin Patch   2016-10-31
## 36    3.3.1          Bug in Your Hair   2016-06-21
## 37    3.3.0    Supposedly Educational   2016-05-03
## 38    3.2.5  Very, Very Secure Dishes   2016-04-11
## 39    3.2.4        Very Secure Dishes   2016-03-11
## 40    3.2.3     Wooden Christmas-Tree   2015-12-10
## 41    3.2.2               Fire Safety   2015-08-14
## 42    3.2.1    World-Famous Astronaut   2015-06-18
## 43    3.2.0       Full of Ingredients   2015-04-16
## 44    3.1.3           Smooth Sidewalk   2015-03-09
## 45    3.1.2            Pumpkin Helmet   2014-10-31
## 46    3.1.1             Sock it to Me   2014-07-10
## 47    3.1.0              Spring Dance   2014-04-10
## 48    3.0.3                Warm Puppy   2014-03-06
## 49    3.0.2           Frisbee Sailing   2013-09-25
## 50    3.0.1                Good Sport   2013-05-16
## 51    3.0.0             Masked Marvel   2013-04-03
## 52   2.15.3          Security Blanket   2013-03-01
## 53   2.15.2            Trick or Treat   2012-10-26
## 54   2.15.1      Roasted Marshmallows   2012-06-22
## 55   2.15.0             Easter Beagle   2012-03-30
## 56   2.14.2       Gift-Getting Season   2012-02-29
## 57   2.14.1       December Snowflakes   2011-12-22
## 58   2.14.0             Great Pumpkin   2011-10-31
## 59  r-devel   Unsuffered Consequences          NaN&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m all too familiar with issues of nested tables and data that doesn’t rectangle
so easily, but for this simple example it worked well, I think.&lt;/p&gt;
&lt;p&gt;Chapter 4 covers indexes and again the idea of repeated values comes into play. The
long-standing issue that the {tibble} team have with rownames comes to mind - I
like being able to name both axes of the data and hate that {tibble} is opposed
to them - so it’s extra surprising to have a Data Frame where the ‘row’ labels
can repeat. What’s more, the index can be hierarchical as a multi-index. With the
example from above, splitting the version into a multi-index is interesting&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;v=x.Version.str.split(&amp;#39;.&amp;#39;, expand=True)
v.columns=[&amp;#39;major&amp;#39;, &amp;#39;minor&amp;#39;, &amp;#39;patch&amp;#39;]
xv=pd.concat([x, v], axis=1)
xv=xv.set_index([&amp;#39;major&amp;#39;,&amp;#39;minor&amp;#39;,&amp;#39;patch&amp;#39;])
xv.head(25)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##                   Version                     Name Release date
## major minor patch                                              
## 4     4     2       4.4.2           Pile of Leaves   2024-10-31
##             1       4.4.1       Race for Your Life   2024-06-14
##             0       4.4.0                Puppy Cup   2024-04-24
##       3     3       4.3.3          Angel Food Cake   2024-02-29
##             2       4.3.2                Eye Holes   2023-10-31
##             1       4.3.1            Beagle Scouts   2023-06-16
##             0       4.3.0         Already Tomorrow   2023-04-21
##       2     3       4.2.3         Shortstop Beagle   2023-03-15
##             2       4.2.2    Innocent and Trusting   2022-10-31
##             1       4.2.1        Funny-Looking Kid   2022-06-23
##             0       4.2.0    Vigorous Calisthenics   2022-04-22
##       1     3       4.1.3              One Push-Up   2022-03-10
##             2       4.1.2              Bird Hippie   2021-11-01
##             1       4.1.1              Kick Things   2021-08-10
##             0       4.1.0          Camp Pontanezen   2021-05-18
##       0     5       4.0.5          Shake and Throw   2021-03-31
##             4       4.0.4        Lost Library Book   2021-02-15
##             3       4.0.3  Bunny-Wunnies Freak Out   2020-10-10
##             2       4.0.2         Taking Off Again   2020-06-22
##             1       4.0.1           See Things Now   2020-06-06
##             0       4.0.0                Arbor Day   2020-04-24
## 3     6     3       3.6.3     Holding the Windsock   2020-02-29
##             2       3.6.2    Dark and Stormy Night   2019-12-12
##             1       3.6.1       Action of the Toes   2019-07-05
##             0       3.6.0       Planting of a Tree   2019-04-26&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This does mean that I can extract all of the 4.3.x series releases&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;xv.loc[(&amp;#39;4&amp;#39;, &amp;#39;3&amp;#39;)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;lt;string&amp;gt;:1: PerformanceWarning: indexing past lexsort depth may impact performance.
##       Version              Name Release date
## patch                                       
## 3       4.3.3   Angel Food Cake   2024-02-29
## 2       4.3.2         Eye Holes   2023-10-31
## 1       4.3.1     Beagle Scouts   2023-06-16
## 0       4.3.0  Already Tomorrow   2023-04-21&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Getting the x.x.0 releases is a little messier, requiring &lt;code&gt;slice(None)&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;xv.loc[(slice(None), slice(None), &amp;#39;0&amp;#39;)] &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##             Version                    Name Release date
## major minor                                             
## 4     4       4.4.0               Puppy Cup   2024-04-24
##       3       4.3.0        Already Tomorrow   2023-04-21
##       2       4.2.0   Vigorous Calisthenics   2022-04-22
##       1       4.1.0         Camp Pontanezen   2021-05-18
##       0       4.0.0               Arbor Day   2020-04-24
## 3     6       3.6.0      Planting of a Tree   2019-04-26
##       5       3.5.0          Joy in Playing   2018-04-23
##       4       3.4.0     You Stupid Darkness   2017-04-21
##       3       3.3.0  Supposedly Educational   2016-05-03
##       2       3.2.0     Full of Ingredients   2015-04-16
##       1       3.1.0            Spring Dance   2014-04-10
##       0       3.0.0           Masked Marvel   2013-04-03
## 2     15     2.15.0           Easter Beagle   2012-03-30
##       14     2.14.0           Great Pumpkin   2011-10-31&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and while this was interesting to achieve, a filter would probably be better&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;xv=pd.concat([x, v], axis=1)
xv.query(&amp;#39;patch == &amp;quot;0&amp;quot;&amp;#39;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##    Version                    Name Release date major minor patch
## 2    4.4.0               Puppy Cup   2024-04-24     4     4     0
## 6    4.3.0        Already Tomorrow   2023-04-21     4     3     0
## 10   4.2.0   Vigorous Calisthenics   2022-04-22     4     2     0
## 14   4.1.0         Camp Pontanezen   2021-05-18     4     1     0
## 20   4.0.0               Arbor Day   2020-04-24     4     0     0
## 24   3.6.0      Planting of a Tree   2019-04-26     3     6     0
## 28   3.5.0          Joy in Playing   2018-04-23     3     5     0
## 33   3.4.0     You Stupid Darkness   2017-04-21     3     4     0
## 37   3.3.0  Supposedly Educational   2016-05-03     3     3     0
## 43   3.2.0     Full of Ingredients   2015-04-16     3     2     0
## 47   3.1.0            Spring Dance   2014-04-10     3     1     0
## 51   3.0.0           Masked Marvel   2013-04-03     3     0     0
## 55  2.15.0           Easter Beagle   2012-03-30     2    15     0
## 58  2.14.0           Great Pumpkin   2011-10-31     2    14     0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I believe &lt;em&gt;that&lt;/em&gt; is the {tibble} team’s argument - that a filter is more suitable,
but I stand by the fact that selecting rows with names which don’t need to be
&lt;em&gt;in&lt;/em&gt; the data itself is a useful approach.&lt;/p&gt;
&lt;p&gt;This chapter also introduces pivot tables in the form of&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;df.pivot_table(index, columns, values, aggfunc)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;the equivalent of which in {dplyr} is &lt;code&gt;dplyr::summarise()&lt;/code&gt; or &lt;code&gt;dplyr::count()&lt;/code&gt;.
Way back when I started learning R I recall finding it odd that the (often useful)
name “pivot table” rarely came up in R documentation, which is a bit of a shame.
I used them &lt;em&gt;all the time&lt;/em&gt; in Excel.&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;xv.pivot_table(index=&amp;#39;major&amp;#39;, 
               columns=&amp;#39;minor&amp;#39;, 
               values=&amp;#39;patch&amp;#39;, 
               aggfunc=&amp;#39;count&amp;#39;, 
               fill_value=0)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## minor  0  1  14  15  2  3  4  5  6
## major                             
## 2      0  0   3   4  0  0  0  0  0
## 3      4  4   0   0  6  4  5  4  4
## 4      6  4   0   0  4  4  3  0  0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My major complaint here is that the function is passed as a string - Y U NO use
first class functions???&lt;/p&gt;
&lt;p&gt;My notes for Chapter 5 (Cleaning Data) only involve the fact that &lt;code&gt;pd.isna&lt;/code&gt; and
&lt;code&gt;pd.isnull&lt;/code&gt; are apparently the exact same thing, which is vastly different from R.&lt;/p&gt;
&lt;p&gt;For Chapter 6 (Grouping, joining, and sorting) I have a rekindled annoyance at the
mixing of methods and attributes driven by the fact that &lt;code&gt;df.transpose()&lt;/code&gt; (a method)
has an alias &lt;code&gt;df.T&lt;/code&gt;. I have enough of a hard time trying to remember whether
it’s &lt;code&gt;x.len&lt;/code&gt; or &lt;code&gt;x.len()&lt;/code&gt; or &lt;code&gt;length(x)&lt;/code&gt; or whatever.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I will continue to make my way through the rest of the book, but figured this
was a good point to take stock of how I feel about it and how much I’ve learned.
I’m already able to work with the API I was trying to and can rectangle the
results into something useful, including being able to save those as a CSV or
even Excel sheet(s).&lt;/p&gt;
&lt;p&gt;Pandas Workout is, in my opinion, a good resource for learning Pandas providing
you already know your way around Python and perhaps data analysis in another
language as well. The minor issues of typos and omissions happen in any book and
I wouldn’t say any of them are dealbreakers. The book covers a lot of the questions
I had as I was working through problems - one of the hardest things when trying
to follow along is having a ‘simple’ question that’s hard to answer yourself. I’ve
abandoned learning other languages (or at least using specific resources) when I’ve
hit that point.&lt;/p&gt;
&lt;p&gt;Pandas itself seems like it makes some good choices in terms of &lt;code&gt;Series&lt;/code&gt; and &lt;code&gt;DataFrame&lt;/code&gt;
structures, and when I’m using Python I’ll be sure to load this library and make
use of them.&lt;/p&gt;
&lt;p&gt;Comments, improvements, or sharing your experiences are most welcome. I can be found
on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; or use the comments below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.4.1 (2024-06-14)
##  os       macOS Sonoma 14.6
##  system   aarch64, darwin20
##  ui       X11
##  language (EN)
##  collate  en_US.UTF-8
##  ctype    en_US.UTF-8
##  tz       Australia/Adelaide
##  date     2025-02-13
##  pandoc   3.2 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/aarch64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version    date (UTC) lib source
##  blogdown      1.19       2024-02-01 [1] CRAN (R 4.4.0)
##  bookdown      0.41       2024-10-16 [1] CRAN (R 4.4.1)
##  bslib         0.8.0      2024-07-29 [1] CRAN (R 4.4.0)
##  cachem        1.1.0      2024-05-16 [1] CRAN (R 4.4.0)
##  cli           3.6.3      2024-06-21 [1] CRAN (R 4.4.0)
##  devtools      2.4.5      2022-10-11 [1] CRAN (R 4.4.0)
##  digest        0.6.37     2024-08-19 [1] CRAN (R 4.4.1)
##  ellipsis      0.3.2      2021-04-29 [1] CRAN (R 4.4.0)
##  evaluate      1.0.1      2024-10-10 [1] CRAN (R 4.4.1)
##  fansi         1.0.6      2023-12-08 [1] CRAN (R 4.4.0)
##  fastmap       1.2.0      2024-05-15 [1] CRAN (R 4.4.0)
##  fs            1.6.5      2024-10-30 [1] CRAN (R 4.4.1)
##  glue          1.8.0      2024-09-30 [1] CRAN (R 4.4.1)
##  htmltools     0.5.8.1    2024-04-04 [1] CRAN (R 4.4.0)
##  htmlwidgets   1.6.4      2023-12-06 [1] CRAN (R 4.4.0)
##  httpuv        1.6.15     2024-03-26 [1] CRAN (R 4.4.0)
##  jquerylib     0.1.4      2021-04-26 [1] CRAN (R 4.4.0)
##  jsonlite      1.8.9      2024-09-20 [1] CRAN (R 4.4.1)
##  knitr         1.48       2024-07-07 [1] CRAN (R 4.4.0)
##  later         1.4.1      2024-11-27 [1] CRAN (R 4.4.1)
##  lattice       0.22-6     2024-03-20 [1] CRAN (R 4.4.1)
##  lifecycle     1.0.4      2023-11-07 [1] CRAN (R 4.4.0)
##  magrittr      2.0.3      2022-03-30 [1] CRAN (R 4.4.0)
##  Matrix        1.7-1      2024-10-18 [1] CRAN (R 4.4.1)
##  memoise       2.0.1      2021-11-26 [1] CRAN (R 4.4.0)
##  mime          0.12       2021-09-28 [1] CRAN (R 4.4.0)
##  miniUI        0.1.1.1    2018-05-18 [1] CRAN (R 4.4.0)
##  pillar        1.9.0      2023-03-22 [1] CRAN (R 4.4.0)
##  pkgbuild      1.4.5      2024-10-28 [1] CRAN (R 4.4.1)
##  pkgload       1.4.0      2024-06-28 [1] CRAN (R 4.4.0)
##  png           0.1-8      2022-11-29 [1] CRAN (R 4.4.0)
##  profvis       0.4.0      2024-09-20 [1] CRAN (R 4.4.1)
##  promises      1.3.2      2024-11-28 [1] CRAN (R 4.4.1)
##  purrr         1.0.2      2023-08-10 [1] CRAN (R 4.4.0)
##  R6            2.5.1      2021-08-19 [1] CRAN (R 4.4.0)
##  Rcpp          1.0.13-1   2024-11-02 [1] CRAN (R 4.4.1)
##  remotes       2.5.0.9000 2024-11-03 [1] Github (r-lib/remotes@5b7eb08)
##  reticulate    1.40.0     2024-11-15 [1] CRAN (R 4.4.1)
##  rlang         1.1.4      2024-06-04 [1] CRAN (R 4.4.0)
##  rmarkdown     2.28       2024-08-17 [1] CRAN (R 4.4.0)
##  rstudioapi    0.17.1     2024-10-22 [1] CRAN (R 4.4.1)
##  sass          0.4.9      2024-03-15 [1] CRAN (R 4.4.0)
##  sessioninfo   1.2.2      2021-12-06 [1] CRAN (R 4.4.0)
##  shiny         1.9.1      2024-08-01 [1] CRAN (R 4.4.0)
##  urlchecker    1.0.1      2021-11-30 [1] CRAN (R 4.4.0)
##  usethis       3.0.0      2024-07-29 [1] CRAN (R 4.4.0)
##  utf8          1.2.4      2023-10-22 [1] CRAN (R 4.4.0)
##  vctrs         0.6.5      2023-12-01 [1] CRAN (R 4.4.0)
##  xfun          0.50.5     2025-01-23 [1] Github (yihui/xfun@116d689)
##  xtable        1.8-4      2019-04-21 [1] CRAN (R 4.4.0)
##  yaml          2.3.10     2024-07-26 [1] CRAN (R 4.4.0)
## 
##  [1] /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/library
## 
## ─ Python configuration ───────────────────────────────────────────────────────
##  python:         /Users/jono/.virtualenvs/r-reticulate/bin/python
##  libpython:      /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/config-3.9-darwin/libpython3.9.dylib
##  pythonhome:     /Users/jono/.virtualenvs/r-reticulate:/Users/jono/.virtualenvs/r-reticulate
##  version:        3.9.6 (default, Oct  4 2024, 08:01:31)  [Clang 16.0.0 (clang-1600.0.26.4)]
##  numpy:          /Users/jono/.virtualenvs/r-reticulate/lib/python3.9/site-packages/numpy
##  numpy_version:  2.0.2
##  
##  NOTE: Python version was forced by use_python() function
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>These Languages are Accumulating</title>
      <link>https://jcarroll.com.au/2024/11/28/these-languages-are-accumulating/</link>
      <pubDate>Thu, 28 Nov 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/11/28/these-languages-are-accumulating/</guid>
      <description>&lt;p&gt;I keep saying that the more programming languages you know, the more you will
understand all the others you know - I’m now at the point where I want to solve
every problem I see in a handful of different languages. They all offer
different functionality, and some are certainly more suited to particular
problems than others, but there’s a world of difference between two characters
and importing from two libraries.&lt;/p&gt;
&lt;p&gt;A newsletter I follow (and can’t find online copies of) that demonstrates neat
things in python (gotta learn it, despite not loving it) recently covered
&lt;code&gt;accumulate&lt;/code&gt;, showing that &lt;code&gt;sum&lt;/code&gt; and &lt;code&gt;accumulate&lt;/code&gt; were sort of related&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; my_list = [42, 73, 0, 16, 10]
&amp;gt;&amp;gt;&amp;gt; sum(my_list)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;141&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from itertools import accumulate
&amp;gt;&amp;gt;&amp;gt; list(accumulate(my_list))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[42, 115, 115, 131, 141]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sum&lt;/code&gt; adds up all the elements of the list, while &lt;code&gt;accumulate&lt;/code&gt; does the same but
keeps each successive partial sum.&lt;/p&gt;
&lt;p&gt;It rounds out the demo with an alternative function being used in &lt;code&gt;accumulate&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from itertools import accumulate
&amp;gt;&amp;gt;&amp;gt; from operator import mul  # mul(2, 3) == 6
&amp;gt;&amp;gt;&amp;gt; initial_investment = 1000
&amp;gt;&amp;gt;&amp;gt; rates = [1.01, 1.01, 1.02, 1.025, 1.035, 1.035, 1.06]
&amp;gt;&amp;gt;&amp;gt; list(
...     accumulate(rates, mul, initial=initial_investment)
... )&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[1000, 1010.0, 1020.1, 1040.502, 1066.515, 1103.843, 1142.477, 1211.026]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, firstly… &lt;code&gt;from operator import mul&lt;/code&gt;??? It looks like there’s no way to
pass &lt;code&gt;*&lt;/code&gt; as an argument to a function. I &lt;em&gt;could&lt;/em&gt; define a function that performs
the same on known arguments, e.g. &lt;code&gt;lambda x, y: x * y&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; list(accumulate(rates, lambda x, y: x*y, initial=initial_investment))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[1000, 1010.0, 1020.1, 1040.502, 1066.5145499999999, 1103.8425592499998, 1142.4770488237498, 1211.0256717531747]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but… ew.&lt;/p&gt;
&lt;p&gt;It’s possible that there’s a different way to approach this. A list
comprehension comes to mind, e.g. something like&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; [sum(my_list[0:i]) for i in range(1, len(my_list)+1)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[42, 115, 115, 131, 141]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but that requires performing a sum for each sub-interval, so performance would
not scale well (admittedly, that was not a consideration here at all). I also
don’t believe there’s a built-in &lt;code&gt;prod&lt;/code&gt; so one must &lt;code&gt;import math&lt;/code&gt; in order to do
similar&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import math
&amp;gt;&amp;gt;&amp;gt; x = [initial_investment] + rates
&amp;gt;&amp;gt;&amp;gt; [math.prod(x[0:i]) for i in range(1, len(x)+1)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[1000, 1010.0, 1020.1, 1040.502, 1066.5145499999999, 1103.8425592499998, 1142.4770488237498, 1211.0256717531747]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In R that could use the built-in &lt;code&gt;cumprod&lt;/code&gt; for the cumulative product&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;initial_investment &amp;lt;- 1000
rates = c(1.01, 1.01, 1.02, 1.025, 1.035, 1.035, 1.06)

cumprod(c(initial_investment, rates))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1000.000 1010.000 1020.100 1040.502 1066.515 1103.843 1142.477 1211.026&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but that has the ‘multiply’ operation hardcoded. &lt;code&gt;cumsum&lt;/code&gt; uses &lt;code&gt;+&lt;/code&gt; as the
function… hmmm. &lt;del&gt;Maybe R doesn’t have a generalised &lt;code&gt;accumulate&lt;/code&gt;?&lt;/del&gt;
&lt;strong&gt;UPDATE&lt;/strong&gt; I entirely forgot that &lt;code&gt;Reduce&lt;/code&gt; takes an &lt;code&gt;accumulate&lt;/code&gt; argument which
does what I need here&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Reduce(`+`, 1:6)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 21&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Reduce(`+`, 1:6, accumulate = TRUE)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]  1  3  6 10 15 21&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Reduce(`*`, 1:6)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 720&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Reduce(`*`, 1:6, accumulate = TRUE)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]   1   2   6  24 120 720&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nonetheless, building my own version is a worthwhile exercise, so the rest of
the post remains as is.&lt;/p&gt;
&lt;p&gt;I’ve been playing around with Haskell lately, so recursive functions to the
rescue! One feature of recursive functions in R that I really like is &lt;code&gt;Recall&lt;/code&gt;
which calls the function &lt;em&gt;in which it is defined&lt;/em&gt; with a new set of arguments -
perfect for recursion!&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;accumulate_recall &amp;lt;- function(x, f, i=x[1]) {
  if (!length(x)) return(NULL)
  c(i, Recall(tail(x, -1), f, f(i, x[2])))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s also robust against renaming the function; the body doesn’t actually call
&lt;code&gt;accumulate_recall&lt;/code&gt; by name at all.&lt;/p&gt;
&lt;p&gt;This might be inefficient, though - it’s not uncommon to blow out the stack, so
a new &lt;code&gt;Tailcall&lt;/code&gt; function (which doesn’t have the same elegance of being robust
against renaming) helps with flagging this as something that can be optimised&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;accumulate &amp;lt;- function(x, f, i=x[1]) {
  if (!length(x)) return(NULL)
  c(i, Tailcall(accumulate, tail(x, -1), f, f(i, x[2])))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this, I can emulate the &lt;code&gt;cumsum()&lt;/code&gt; and &lt;code&gt;cumprod()&lt;/code&gt; functions&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cumprod(1:6)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]   1   2   6  24 120 720&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;accumulate(1:6, `*`)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]   1   2   6  24 120 720&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cumsum(2:6)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]  2  5  9 14 20&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;accumulate(2:6, `+`)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]  2  5  9 14 20&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;unless I try to calculate something too big…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cumprod(5:15)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1]           5          30         210        1680       15120      151200
##  [7]     1663200    19958400   259459200  3632428800 54486432000&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;accumulate(5:15, `*`)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-warning text-warning&#34;&gt;&lt;code&gt;## Warning in f(i, x[2]): NAs produced by integer overflow&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1]         5        30       210      1680     15120    151200   1663200
##  [8]  19958400 259459200        NA        NA&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It appears that the built-in functions convert to numeric. That’s easily fixed
on input&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;accumulate(as.numeric(5:15), `*`)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1]           5          30         210        1680       15120      151200
##  [7]     1663200    19958400   259459200  3632428800 54486432000&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In any case, there’s a generalised &lt;code&gt;accumulate&lt;/code&gt; that takes the bare functions as
arguments.&lt;/p&gt;
&lt;p&gt;But it can be so much cleaner than this!&lt;/p&gt;
&lt;p&gt;In APL you won’t find any function named “sum” because it is just a reduction
(&lt;code&gt;Reduce&lt;/code&gt; in R) with the function &lt;code&gt;+&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      sum←+/
      
      sum ⍳6 ⍝ sum the values 1:6
21

      sum 1↓⍳6 ⍝ sum the values 2:6
20&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which in R is&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sum(1:6)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 21&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sum(2:6)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 20&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Why would you write &lt;code&gt;sum&lt;/code&gt; if you can just use &lt;code&gt;+/&lt;/code&gt;? It’s fewer
characters to write out the implementation than the name!&lt;/p&gt;
&lt;p&gt;For &lt;code&gt;accumulate&lt;/code&gt; the terminology in APL is &lt;code&gt;scan&lt;/code&gt; which uses a very similar
glyph because the operation itself is very similar; a &lt;code&gt;reduce&lt;/code&gt; (&lt;code&gt;/&lt;/code&gt;) is just the
last value of a &lt;code&gt;scan&lt;/code&gt; (&lt;code&gt;\&lt;/code&gt;) which keeps the progressive values. In both cases,
the operator (either slash) takes a binary function as the left argument and
produces a modified function - in these examples, effectively &lt;code&gt;sum&lt;/code&gt; and &lt;code&gt;prod&lt;/code&gt; -
which is then applied to values on the right. The &lt;code&gt;scan&lt;/code&gt; version does the same&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      +\⍳6
1 3 6 10 15 21

      ×\⍳6
1 2 6 24 120 720&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;accumulate(1:6, `+`)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]  1  3  6 10 15 21&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;accumulate(1:6, `*`)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]   1   2   6  24 120 720&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As for the rates example above, we concatenate the initial value with &lt;code&gt;catenate&lt;/code&gt;
(&lt;code&gt;,&lt;/code&gt;) just like the R example, but otherwise this works fine&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      rates ← 1.01 1.01 1.02 1.025 1.035 1.035 1.06
      inv ← 1000
      
      ×/inv, rates
1211.025672

      ×\inv, rates
1000 1010 1020.1 1040.502 1066.51455 1103.842559 1142.477049 1211.025672&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So all of that recursive R code I wrote to generalise the cumulative application
of a function provided as an argument is boiled down to just the single glyph
&lt;code&gt;\&lt;/code&gt;. Outstanding!&lt;/p&gt;
&lt;p&gt;What’s more, there are &lt;em&gt;lots&lt;/em&gt; of binary functions one would use this with, all
of which have spelled-out names in other languages&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      +/ ⍝ sum (add)
      ×/ ⍝ prod (multiply)
      ∧/ ⍝ all (and)
      ∨/ ⍝ any (or)
      ⌈/ ⍝ maximum (max)
      ⌊/ ⍝ minimum (min)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In summary, it seems that looking across these languages, the available options
range from a single glyph for &lt;code&gt;scan&lt;/code&gt; along with the bare binary operator, e.g.
&lt;code&gt;×/&lt;/code&gt;; a &lt;code&gt;cumprod()&lt;/code&gt; function which isn’t well-generalised but works out of the
box; an &lt;code&gt;accumulate=TRUE&lt;/code&gt; argument to &lt;code&gt;Reduce&lt;/code&gt;; and then there’s whatever mess
this is (once you’ve &lt;em&gt;installed&lt;/em&gt; these)&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from itertools import accumulate
&amp;gt;&amp;gt;&amp;gt; from operator import mul
&amp;gt;&amp;gt;&amp;gt; list(accumulate(rates, mul, initial=initial_investment))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where did we go so wrong?&lt;/p&gt;
&lt;p&gt;For what it’s worth, Julia has a &lt;code&gt;reduce&lt;/code&gt; and an &lt;code&gt;accumulate&lt;/code&gt; that behave very
nicely; generalised for the binary function as an argument&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;julia&amp;gt; reduce(+, 1:6)
21

julia&amp;gt; reduce(*, 1:6)
720

julia&amp;gt; accumulate(+, 1:6)
6-element Vector{Int64}:
  1
  3
  6
 10
 15
 21

julia&amp;gt; accumulate(*, 1:6)
6-element Vector{Int64}:
   1
   2
   6
  24
 120
 720&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is extremely close to the APL approach, but with longer worded names for
the &lt;code&gt;reduce&lt;/code&gt; and &lt;code&gt;scan&lt;/code&gt; operators. It also defines the more convenient &lt;code&gt;sum&lt;/code&gt;,
&lt;code&gt;prod&lt;/code&gt;, &lt;code&gt;cumsum&lt;/code&gt;, and &lt;code&gt;cumprod&lt;/code&gt;; no shortage of ways to do this in Julia!&lt;/p&gt;
&lt;p&gt;In Haskell, &lt;code&gt;foldl&lt;/code&gt; and &lt;code&gt;scanl&lt;/code&gt; are the (left-associative) version of &lt;code&gt;reduce&lt;/code&gt;
and &lt;code&gt;accumulate&lt;/code&gt;, and passing an infix as an argument necessitates wrapping it
in parentheses&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;ghci&amp;gt; foldl (+) 0 [1..6]
21

ghci&amp;gt; scanl (+) 0 [1..6]
[0,1,3,6,10,15,21]

ghci&amp;gt; foldl (*) 1 [1..6]
720

ghci&amp;gt; scanl (*) 1 [1..6]
[1,1,2,6,24,120,720]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This requires an explicit starting value, unless one uses the specialised
versions which use the first value as an initial value&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;ghci&amp;gt; foldl1 (+) [1..6]
21

ghci&amp;gt; scanl1 (+) [1..6]
[1,3,6,10,15,21]

ghci&amp;gt; foldl1 (*) [1..6]
720

ghci&amp;gt; scanl1 (*) [1..6]
[1,2,6,24,120,720]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I started this post hoping to demonstrate how nice the APL syntax was for this,
but the detour through generalising the R function was a lot of unexpected fun
as well.&lt;/p&gt;
&lt;p&gt;Comments, improvements, or your own solutions are most welcome. I can be found
on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; or use the comments below.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Addendums&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It should probably be noted that R &lt;em&gt;does&lt;/em&gt; have a function &lt;code&gt;scan&lt;/code&gt; but it’s for
reading data into a vector - if you ever spot someone using it for that… run.
I have war stories about that function.&lt;/p&gt;
&lt;p&gt;I’d love to hear how this is accomplished in some other languages, too - does it
have a built-in &lt;code&gt;accumulate&lt;/code&gt; that takes a binary function?&lt;/p&gt;
&lt;p&gt;Many thanks to commenters on Mastodon for reminding me that &lt;code&gt;Reduce(f, x, accumulate=TRUE)&lt;/code&gt; is the base R way to achieve the &lt;code&gt;scan&lt;/code&gt;. I feel that still
counts as points against R because of the poor discoverability of gating the
&lt;em&gt;opposite&lt;/em&gt; behaviour behind a boolean flag.&lt;/p&gt;
&lt;p&gt;We also have&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;purrr::accumulate(1:6, `*`)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]   1   2   6  24 120 720&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is probably even more ergnomic, but I feel that takes away from my
complaints about needing to do an import in python.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.4.1 (2024-06-14)
##  os       macOS Sonoma 14.6
##  system   aarch64, darwin20
##  ui       X11
##  language (EN)
##  collate  en_US.UTF-8
##  ctype    en_US.UTF-8
##  tz       Australia/Adelaide
##  date     2024-11-28
##  pandoc   3.5 @ /opt/homebrew/bin/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version    date (UTC) lib source
##  blogdown      1.19       2024-02-01 [1] CRAN (R 4.4.0)
##  bookdown      0.41       2024-10-16 [1] CRAN (R 4.4.1)
##  bslib         0.8.0      2024-07-29 [1] CRAN (R 4.4.0)
##  cachem        1.1.0      2024-05-16 [1] CRAN (R 4.4.0)
##  cli           3.6.3      2024-06-21 [1] CRAN (R 4.4.0)
##  devtools      2.4.5      2022-10-11 [1] CRAN (R 4.4.0)
##  digest        0.6.37     2024-08-19 [1] CRAN (R 4.4.1)
##  ellipsis      0.3.2      2021-04-29 [1] CRAN (R 4.4.0)
##  evaluate      1.0.1      2024-10-10 [1] CRAN (R 4.4.1)
##  fastmap       1.2.0      2024-05-15 [1] CRAN (R 4.4.0)
##  fs            1.6.5      2024-10-30 [1] CRAN (R 4.4.1)
##  glue          1.8.0      2024-09-30 [1] CRAN (R 4.4.1)
##  htmltools     0.5.8.1    2024-04-04 [1] CRAN (R 4.4.0)
##  htmlwidgets   1.6.4      2023-12-06 [1] CRAN (R 4.4.0)
##  httpuv        1.6.15     2024-03-26 [1] CRAN (R 4.4.0)
##  jquerylib     0.1.4      2021-04-26 [1] CRAN (R 4.4.0)
##  jsonlite      1.8.9      2024-09-20 [1] CRAN (R 4.4.1)
##  knitr         1.48       2024-07-07 [1] CRAN (R 4.4.0)
##  later         1.3.2      2023-12-06 [1] CRAN (R 4.4.0)
##  lifecycle     1.0.4      2023-11-07 [1] CRAN (R 4.4.0)
##  magrittr      2.0.3      2022-03-30 [1] CRAN (R 4.4.0)
##  memoise       2.0.1      2021-11-26 [1] CRAN (R 4.4.0)
##  mime          0.12       2021-09-28 [1] CRAN (R 4.4.0)
##  miniUI        0.1.1.1    2018-05-18 [1] CRAN (R 4.4.0)
##  pkgbuild      1.4.5      2024-10-28 [1] CRAN (R 4.4.1)
##  pkgload       1.4.0      2024-06-28 [1] CRAN (R 4.4.0)
##  profvis       0.4.0      2024-09-20 [1] CRAN (R 4.4.1)
##  promises      1.3.0      2024-04-05 [1] CRAN (R 4.4.0)
##  purrr         1.0.2      2023-08-10 [1] CRAN (R 4.4.0)
##  R6            2.5.1      2021-08-19 [1] CRAN (R 4.4.0)
##  Rcpp          1.0.13-1   2024-11-02 [1] CRAN (R 4.4.1)
##  remotes       2.5.0.9000 2024-11-03 [1] Github (r-lib/remotes@5b7eb08)
##  rlang         1.1.4      2024-06-04 [1] CRAN (R 4.4.0)
##  rmarkdown     2.28       2024-08-17 [1] CRAN (R 4.4.0)
##  rstudioapi    0.17.1     2024-10-22 [1] CRAN (R 4.4.1)
##  sass          0.4.9      2024-03-15 [1] CRAN (R 4.4.0)
##  sessioninfo   1.2.2      2021-12-06 [1] CRAN (R 4.4.0)
##  shiny         1.9.1      2024-08-01 [1] CRAN (R 4.4.0)
##  urlchecker    1.0.1      2021-11-30 [1] CRAN (R 4.4.0)
##  usethis       3.0.0      2024-07-29 [1] CRAN (R 4.4.0)
##  vctrs         0.6.5      2023-12-01 [1] CRAN (R 4.4.0)
##  xfun          0.49       2024-10-31 [1] CRAN (R 4.4.1)
##  xtable        1.8-4      2019-04-21 [1] CRAN (R 4.4.0)
##  yaml          2.3.10     2024-07-26 [1] CRAN (R 4.4.0)
## 
##  [1] /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Polyglot Maxxie and Minnie</title>
      <link>https://jcarroll.com.au/2024/10/26/polyglot-maxxie-and-minnie/</link>
      <pubDate>Sat, 26 Oct 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/10/26/polyglot-maxxie-and-minnie/</guid>
      <description>&lt;p&gt;Continuing my theme of learning all the languages, I took the opportunity of a
programming puzzle to try out the same approach in a handful of different
languages to compare how they work.&lt;/p&gt;
&lt;p&gt;For an upcoming APL’ers meetup the challenge was set as posed at the end of
&lt;a href=&#34;https://ericnormand.me/issues/468&#34;&gt;in this post&lt;/a&gt;, namely&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Maxxie and Minnie&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The maxxie of a number n is the largest number you can achieve by swapping two
of its digits (in decimal) (or choosing not to swap if it is already the largest
possible). The minnie is the smallest with one swap (though you can’t swap a
zero digit into the most significant position).&lt;/p&gt;
&lt;p&gt;Your task is to write a function that takes an integer and returns a tuple of
the maxxie and minnie.&lt;/p&gt;
&lt;p&gt;Notes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Swap any two decimal digits&lt;/li&gt;
&lt;li&gt;No leading zeroes&lt;/li&gt;
&lt;li&gt;Don’t swap if you can’t make it bigger/smaller&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;with the example solutions given in Clojure&lt;/p&gt;
&lt;pre class=&#34;clojure&#34;&gt;&lt;code&gt;(swapmaxmin 213) ;=&amp;gt; [312, 123]
(swapmaxmin 12345) ;=&amp;gt; [52341, 12345] ;; the number was already the smallest
(swapmaxmin 100) ;=&amp;gt; [100, 100] ;; no swap possible because of zeroes&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This seems like fun - and I wanted to see how solutions might look across some
of the different languages I know (including an APL, for the sake of the upcoming
meetup).&lt;/p&gt;
&lt;p&gt;I ended up using R, (Dyalog) APL, Julia, Haskell, Python, and Rust; someone
provided a J solution; and I’ll add in any others shared with me. The site
linked above collected Clojure solutions in
&lt;a href=&#34;https://gist.github.com/ericnormand/4ca47720a954307739aaeb12682de98a&#34;&gt;this gist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The common approach I used in all of these cases was:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;split the number into a vector of digits&lt;/li&gt;
&lt;li&gt;generate all possible combinations of indices to be swapped&lt;/li&gt;
&lt;li&gt;apply a swap function to perform all of those swaps&lt;/li&gt;
&lt;li&gt;append the unswapped vector, if not already included&lt;/li&gt;
&lt;li&gt;filter out any vectors which start with a &lt;code&gt;0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;recombine each vector into a single number&lt;/li&gt;
&lt;li&gt;return the maximum and minimum numbers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are my solutions in each language; it’s not so much for side-by-side
comparison, but you can switch between the different ones. The full set of files
is &lt;a href=&#34;https://github.com/jonocarroll/MaxxieAndMinnie&#34;&gt;here&lt;/a&gt; if you’re interested.&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;div class=&#34;tabset&#34;&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;R&lt;br&gt;&lt;img src=&#34;images/r.png&#34; height=&#34;40px&#34;&gt;&lt;/p&gt;
&lt;p&gt;I’m most familiar with R, so I like to start there. I created a &lt;code&gt;swap&lt;/code&gt;
function that swaps a vector at some indices, along with some helpers
so that I could use &lt;code&gt;pmap_int()&lt;/code&gt; really cleanly.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;swap &amp;lt;- function(x, y, v) {
   xx &amp;lt;- v[x]
   yy &amp;lt;- v[y]
   v[x] &amp;lt;- yy
   v[y] &amp;lt;- xx
   v
}

chr_swap &amp;lt;- function(x, y, v) {
   paste0(swap(x, y, v), collapse = &amp;quot;&amp;quot;)
}

toInt_swap &amp;lt;- function(x, y, v) {
   as.integer(chr_swap(x, y, v))
}

maxmin &amp;lt;- function(num) {
  chars &amp;lt;- strsplit(as.character(num), &amp;quot;&amp;quot;)[[1]]
  n &amp;lt;- nchar(num)
  s &amp;lt;- seq_len(n)
  opts &amp;lt;- expand.grid(x = s, y = s)
  opts$v &amp;lt;- list(chars)
  vals &amp;lt;- purrr::pmap_int(opts, toInt_swap)
  keeps &amp;lt;- vals[nchar(vals) == n]
  c(max(keeps), min(keeps))
}

maxmin(213)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[1] 312 123  &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;maxmin(12345)  &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[1] 52341 12345  &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;maxmin(100)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[1] 100 100  &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;maxmin(11321)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[1] 31121 11123 &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;expand.grid()&lt;/code&gt; does create some redundant combinations, but these fall
out naturally so I didn’t bother filtering them out. Also, since this
includes no-op swaps (e.g. swapping index &lt;code&gt;2&lt;/code&gt; and &lt;code&gt;2&lt;/code&gt;) it already contains
the original vector. Rather than filtering to the vectors of integers &lt;em&gt;not&lt;/em&gt;
starting with 0, I filtered to those which contain the right number of digits
after converting back to integer, which is equivalent.&lt;/p&gt;
&lt;p&gt;Try pasting the code into the
&lt;a href=&#34;https://webr.r-wasm.org/latest/&#34;&gt;{webr} online editor here&lt;/a&gt;; I’m not sure
if it’s possible to link to an existing state, but when it asks if you want
to install {purrr} to the interface, respond that you do.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;APL&lt;br&gt;&lt;img src=&#34;images/apl.png&#34; height=&#34;40px&#34;&gt;&lt;/p&gt;
&lt;p&gt;In Dyalog APL it’s easier to define a swap function; the &lt;code&gt;@&lt;/code&gt; operator takes a
function (reverse) so &lt;code&gt;s&lt;/code&gt; here performs a swap. The outer product is super
handy for finding all the combinations of &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;: &lt;code&gt;x ∘., y&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;maxmin←{
  ⎕IO←1  ⍝ so that x[1] is subset not x[0]
  n←⍎¨⍕⍵  ⍝ convert int to vec 
  s←{⌽@⍵⊢⍺}  ⍝ swap two elements
  swaps←{n s ⍵}  ⍝ apply swaps to a vec n
  opts←,(⍳≢n)∘.,⍳≢n ⍝ combinations of 1..n
  new←swaps¨opts  ⍝ perform the swaps
  keep←(~0=⊃¨new)/new  ⍝ filter out values starting with 0
  (⌈/,⌊/)10⊥¨keep  ⍝ max and min of ints
}

     maxmin 213 &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;312 123&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;     maxmin 12345 &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;52341 12345&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;     maxmin 100 &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;100 100&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;     maxmin 11321&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;31121 11123&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m quite pleased with this solution; performing a &lt;code&gt;map&lt;/code&gt; is as simple as
using each (&lt;code&gt;¨&lt;/code&gt;) and performing both &lt;code&gt;max&lt;/code&gt; and &lt;code&gt;min&lt;/code&gt; concatenated together
with a fork (&lt;code&gt;(⌈/,⌊/)&lt;/code&gt;) is just so aesthetic. Conversion from a vector of
numbers to a single number uses a base-10 decode (&lt;code&gt;10⊥&lt;/code&gt;) which is how one
might need to do that in other languages, but with a loop.&lt;/p&gt;
&lt;p&gt;If I was to take some liberties with what one calls a ‘line’, I could say
that this is a 1-line solution&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;maxmin←{⎕IO←1 ⋄ n←⍎¨⍕⍵ ⋄ s←{⌽@⍵⊢⍺} ⋄ swaps←{n s ⍵} ⋄ opts←,(⍳≢n)∘.,⍳≢n ⋄ new←swaps¨opts ⋄ keep←(~0=⊃¨new)/new ⋄ (⌈/,⌊/)10⊥¨keep }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can
&lt;a href=&#34;https://tryapl.org/?clear&amp;amp;q=maxmin%E2%86%90%7B%0A%20%20%E2%8E%95IO%E2%86%901%20%20%E2%8D%9D%20so%20that%20x%5B1%5D%20is%20subset%20not%20x%5B0%5D%0A%20%20n%E2%86%90%E2%8D%8E%C2%A8%E2%8D%95%E2%8D%B5%20%20%E2%8D%9D%20convert%20int%20to%20vec%20%0A%20%20s%E2%86%90%7B%E2%8C%BD%40%E2%8D%B5%E2%8A%A2%E2%8D%BA%7D%20%20%E2%8D%9D%20swap%20two%20elements%0A%20%20swaps%E2%86%90%7Bn%20s%20%E2%8D%B5%7D%20%20%E2%8D%9D%20apply%20swaps%20to%20a%20vec%20n%0A%20%20opts%E2%86%90%2C(%E2%8D%B3%E2%89%A2n)%E2%88%98.%2C%E2%8D%B3%E2%89%A2n%20%E2%8D%9D%20combinations%20of%201..n%0A%20%20new%E2%86%90swaps%C2%A8opts%20%20%E2%8D%9D%20perform%20the%20swaps%0A%20%20keep%E2%86%90(~0%3D%E2%8A%83%C2%A8new)%2Fnew%20%20%E2%8D%9D%20filter%20out%20values%20starting%20with%200%0A%20%20(%E2%8C%88%2F%2C%E2%8C%8A%2F)10%E2%8A%A5%C2%A8keep%20%20%E2%8D%9D%20max%20and%20min%20of%20ints%0A%20%20%7D%0A%0A%20%20%20%20%20%20maxmin%2012345%0A52341%2012345%0A%20%20%20%20%20%20maxmin%20213%0A312%20123%0A%20%20%20%20%20%20maxmin%20100%0A100%20100%0A%20%20%20%20%20%20maxmin%2011321%0A31121%2011123&amp;amp;run&#34;&gt;try this out yourself at tryapl.org&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Julia&lt;br&gt;&lt;img src=&#34;images/julia.png&#34; height=&#34;40px&#34;&gt;&lt;/p&gt;
&lt;p&gt;In Julia the &lt;code&gt;swap&lt;/code&gt; function can use destructuring which is nice, but since
the language uses pass-by-reference semantics, I need to make a copy of the
vector being swapped, otherwise I’ll just keep swapping it over and over.
Note: &lt;a href=&#34;https://jcarroll.com.au/2024/09/25/in-place-modifications/&#34;&gt;this recent post of mine&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;using Combinatorics

function swap(x, i, j)
  y = copy(x)
  y[i], y[j] = y[j], y[i]
  y
end

function maxmin(x)
    nvec = parse.(Int64, split(string(x), &amp;quot;&amp;quot;))
    opts = collect(combinations(1:length(nvec), 2))
    new = [[nvec]; map(x -&amp;gt; swap(nvec, x...), opts)]
    keep = filter(x -&amp;gt; x[1] != 0, new)
    vals = parse.(Int64, join.(keep))
    (maximum(vals), minimum(vals))
end

maxmin(213)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;(312, 123)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;maxmin(12345)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;(52341, 12345)  &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;maxmin(100)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;(100, 100)  &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;maxmin(11321)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;(31121, 11123)    &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The part I probably had the most trouble with here was concatenating together
the original vector with its swapped versions; it looks clean now, but
figuring out how to get those all into the same vector-of-vectors took me a
while.&lt;/p&gt;
&lt;p&gt;The splatting of &lt;code&gt;opts&lt;/code&gt; variants in the &lt;code&gt;map&lt;/code&gt; was nice; no need to define the
swap in terms of a tuple. Overall, this is a very clean solution, in my
opinion - Julia really does make for a lovely language.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Haskell&lt;br&gt;&lt;img src=&#34;images/haskell.png&#34; height=&#34;40px&#34;&gt;&lt;/p&gt;
&lt;p&gt;Continuing my Haskell-learning journey, I figured it would be best to have a
go at this. As a heavily functional language, one doesn’t do a lot of
defining of variables, instead one writes a lot of functions which will pass
data around. This makes it a bit tricky for testing, but I got there
eventually. I did have to borrow the &lt;code&gt;swapElts&lt;/code&gt; function, and &lt;code&gt;nub&lt;/code&gt; was a new
one for me (essentially &lt;code&gt;unique()&lt;/code&gt;).&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;import Data.List
import Data.Digits

uniq_pairs l = nub [(x,y) | x &amp;lt;- l, y &amp;lt;- l, x &amp;lt; y]
opts n = uniq_pairs [0..n-1]
-- https://gist.github.com/ijt/2010183
swapElts i j ls = [get k x | (k, x) &amp;lt;- zip [0..length ls - 1] ls]
    where get k x | k == i = ls !! j
                  | k == j = ls !! i
                  | otherwise = x
doswap t v = swapElts (fst t) (snd t) v
newlist v = v : map (\x -&amp;gt;  doswap x v) (opts (length v))
keep v = filter (\x -&amp;gt; (head x /= 0)) (newlist v)
maxmin n = (maximum(x), minimum(x)) where 
  x = map (unDigits 10) (keep (digits 10 n))

maxmin 213&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;(312,123)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;maxmin 12345&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;(52341,12345)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;maxmin 100&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;(100,100)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;maxmin 11321&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;(31121,11123)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Data.Digits&lt;/code&gt; package was very helpful here - having &lt;code&gt;digits&lt;/code&gt; and
&lt;code&gt;unDigits&lt;/code&gt;, though if I was going to use these more I would have curried
the required base 10 into something like &lt;code&gt;digits10&lt;/code&gt; and &lt;code&gt;unDigits10&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There are likely improvements to be made here, and I’m interested in any you
can spot!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Python&lt;br&gt;&lt;img src=&#34;images/python.png&#34; height=&#34;40px&#34;&gt;&lt;/p&gt;
&lt;p&gt;“Everyone” uses it, so I gotta learn it… is what I keep telling myself. I’m
no stranger to the quirks of different languages, but every time I try
to do something functional in python I end up angry that the print method for
generators shows the memory address instead of, say, the first few elements.
Printing a value and seeing &lt;code&gt;&amp;lt;map at 0x7fb928d4a2c0&amp;gt;&lt;/code&gt; gets me every. single.
time. Yes, yes, &lt;code&gt;list(value)&lt;/code&gt; “collects” it, but grrr…&lt;/p&gt;
&lt;p&gt;Python has the destructuring syntax which is nice in the &lt;code&gt;swap&lt;/code&gt; function, but
again it’s pass-by-reference so I need to make a copy first.&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;import itertools

def swap(x, t):
    y = x.copy()
    i, j = t
    y[i], y[j] = y[j], y[i]
    return y

def minmax(num): 
    nums = [int(i) for i in str(num)]
    opts = itertools.combinations(range(len(nums)), 2)
    new = map(lambda x: swap(nums, x), list(opts))
    keeps = list(filter(lambda x: x[0] != 0, new))
    keeps.append(nums)
    vals = list(map(lambda x: int(&amp;#39;&amp;#39;.join(map(str, x))), keeps))
    return (max(vals), min(vals))

minmax(213)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;(312, 123)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;minmax(12345)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;(52341, 12345)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;minmax(100)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;(100, 100)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;minmax(11321)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;(31121, 11123)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Aside from my grumbles while writing it, the solution is still pretty clean.
The calls to &lt;code&gt;list()&lt;/code&gt; interspersed throughout might be avoidable, but the
need to do that while developing at least slowed me down.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rust&lt;br&gt;&lt;img src=&#34;images/rust.png&#34; height=&#34;40px&#34;&gt;&lt;/p&gt;
&lt;p&gt;I almost didn’t do a Rust solution because I thought I’d done enough. It
ended up being the most complicated, though - I’m not sure if that’s because
of me, or Rust.&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;use itertools::Itertools;

fn swap(v: Vec&amp;lt;u32&amp;gt;, t1: usize, t2: usize) -&amp;gt; Vec&amp;lt;u32&amp;gt; {
    let mut vv = v;
    let tmp1 = vv[t1];
    let tmp2 = vv[t2];
    vv[t1] = tmp2;
    vv[t2] = tmp1;
    return vv;
}

fn maxmin(num: u32) -&amp;gt; (u32, u32) {
    let numc = num.to_string();
    let n = numc.len();
    let numv: Vec&amp;lt;u32&amp;gt; = numc
        .to_string()
        .chars()
        .map(|c| c.to_digit(10).unwrap())
        .collect();
    let mut opts = Vec::new();
    for (a, b) in (0..n).tuple_combinations() {
        opts.push((a, b));
    }
    let mut new: Vec&amp;lt;Vec&amp;lt;u32&amp;gt;&amp;gt; = Vec::new();
    new.push(numv.clone());
    for o in opts {
        new.push(swap(numv.clone(), o.0, o.1));
    }
    let keeps: Vec&amp;lt;Vec&amp;lt;u32&amp;gt;&amp;gt; = new.into_iter().filter(|x| x[0] != 0).collect();
    let mut vals = Vec::new();
    for v in keeps {
        let tmp: u32 = v
            .clone()
            .into_iter()
            .map(|x| x.to_string())
            .collect::&amp;lt;String&amp;gt;()
            .parse()
            .unwrap();
        vals.push(tmp);
    }
    let min = *vals.iter().min().unwrap();
    let max = *vals.iter().max().unwrap();
    (max, min)
}

fn main() {
    println!(&amp;quot;{:?}&amp;quot;, maxmin(213));
    println!(&amp;quot;{:?}&amp;quot;, maxmin(12345));
    println!(&amp;quot;{:?}&amp;quot;, maxmin(100));
    println!(&amp;quot;{:?}&amp;quot;, maxmin(11321))
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;(312, 123)
(52341, 12345)
(100, 100)
(31121, 11123)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This solution reminded me why I like working with array (or
at least vector-supporting) languages; not needing to explicitly loop over
every element of a vector to do something. I had to write a lot of &lt;code&gt;push()&lt;/code&gt;
loops to move data around. &lt;code&gt;max()&lt;/code&gt; doesn’t work on a vector (in the sense of
finding the maximum of n elements); it works that way on an iterator, and may
fail, hence the longer &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; lines.&lt;/p&gt;
&lt;p&gt;Having to &lt;code&gt;clone()&lt;/code&gt; various values explicitly because they can’t be re-used
was a bit annoying, but I understand &lt;em&gt;why&lt;/em&gt; it complains about those.&lt;/p&gt;
&lt;p&gt;This took longer than I would have liked, but of course I learned more by
doing it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;J&lt;br&gt;&lt;img src=&#34;images/j.png&#34; height=&#34;40px&#34;&gt;&lt;/p&gt;
&lt;p&gt;At the APL meetup we discussed one partial J solution which used a slightly
different approach to the ‘swap’ algorithm. I’m not sure that there &lt;em&gt;is&lt;/em&gt; a
way in J that’s as elegant as the APL solution, but I’d be interested if
there is.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.justusperlwitz.com/&#34;&gt;Justus Perlwitz&lt;/a&gt; offered
&lt;a href=&#34;https://gist.github.com/justuswilhelm/e5b5898d12f9ddb69d5ab85c8e8ec32c&#34;&gt;this&lt;/a&gt;
solution, the essence of which is&lt;/p&gt;
&lt;pre class=&#34;j&#34;&gt;&lt;code&gt;digits =: 10&amp;amp;#.^:_1

sd =: {{
  amend =. (|.y)}
  swap =. (y { ]) amend ]
  swap &amp;amp;.: digits x
}}

cart =: {{
  all =. ,/ (,&amp;quot;0)/~ y
  uniq =. ~. /:~&amp;quot;1 all
  l =. 0{&amp;quot;1 uniq
  r =. 1{&amp;quot;1 uniq
  (l ~: r) # uniq
}}

swapmaxmin =: {{
  ndigits =. [: # digits
  combs =. cart i. ndigits y
  constr =. ((ndigits y) &amp;lt;: [: ndigits&amp;quot;0 ]) # ]
  swaps =. constr y, y sd&amp;quot;1 combs
  (&amp;gt;./ , &amp;lt;./) swaps
}}

swapmaxmin 213&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;312 123&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;j&#34;&gt;&lt;code&gt;swapmaxmin 12345&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;52341 12345&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;j&#34;&gt;&lt;code&gt;swapmaxmin 100&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;100 100&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;j&#34;&gt;&lt;code&gt;swapmaxmin 11321&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;31121 11123&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and which you can run in
&lt;a href=&#34;https://jsoftware.github.io/j-playground/bin/html/index.html#code=digits%20%3D%3A%2010%26%23.%5E%3A_1%0Asd%20%3D%3A%20%7B%7B%0A%20%20amend%20%3D.%20(%7C.y)%7D%0A%20%20swap%20%3D.%20(y%20%7B%20%5D)%20amend%20%5D%0A%20%20swap%20%26.%3A%20digits%20x%0A%7D%7D%0A%0Acart%20%3D%3A%20%7B%7B%0A%20%20all%20%3D.%20%2C%2F%20(%2C%220)%2F~%20y%0A%20%20uniq%20%3D.%20~.%20%2F%3A~%221%20all%0A%20%20l%20%3D.%200%7B%221%20uniq%0A%20%20r%20%3D.%201%7B%221%20uniq%0A%20%20(l%20~%3A%20r)%20%23%20uniq%0A%7D%7D%0A%0Aswapmaxmin%20%3D%3A%20%7B%7B%0A%20%20ndigits%20%3D.%20%5B%3A%20%23%20digits%0A%20%20combs%20%3D.%20cart%20i.%20ndigits%20y%0A%20%20constr%20%3D.%20((ndigits%20y)%20%3C%3A%20%5B%3A%20ndigits%220%20%5D)%20%23%20%5D%0A%20%20swaps%20%3D.%20constr%20y%2C%20y%20sd%221%20combs%0A%20%20(%3E.%2F%20%2C%20%3C.%2F)%20swaps%0A%7D%7D%0A%0Aswapmaxmin%20213%0Aswapmaxmin%2012345%0Aswapmaxmin%20100%0Aswapmaxmin%2011321&#34;&gt;the J playground&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There’s a lot I want to learn about J, so I’ll be digging through this
solution myself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go&lt;br&gt;&lt;img src=&#34;images/go.png&#34; height=&#34;40px&#34;&gt;&lt;/p&gt;
&lt;p&gt;Andrew Gray in my local Functional Programming meetup offered
&lt;a href=&#34;https://github.com/ayjaygee/go-swapMaxMin/blob/main/main.go&#34;&gt;a Go solution&lt;/a&gt;
which I pared down to the following&lt;/p&gt;
&lt;pre class=&#34;go&#34;&gt;&lt;code&gt;package main

import (
	&amp;quot;fmt&amp;quot;
	&amp;quot;slices&amp;quot;
	&amp;quot;strconv&amp;quot;
)

func MaxMin(n int) (max, min int) {
	s := strconv.Itoa(n)
	digits := []rune(s)
	max, min = n, n
	for i := range digits {
		for j := i + 1; j &amp;lt; len(digits); j++ {
			if i == 0 &amp;amp;&amp;amp; digits[j] == &amp;#39;0&amp;#39; {
				continue
			}
			swapped := slices.Clone(digits)
			swapped[i], swapped[j] = swapped[j], swapped[i]
			curr, _ := strconv.Atoi(string(swapped))
			if curr &amp;gt; max {
				max = curr
			}
			if curr &amp;lt; min {
				min = curr
			}
		}
	}
	return max, min
}

func main() {
	fmt.Println(MaxMin(213))
	fmt.Println(MaxMin(12345))
	fmt.Println(MaxMin(100))
	fmt.Println(MaxMin(11321))
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;312 123
52341 12345
100 100
31121 11123&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go also has the handy destructuring syntax, but has a slightly different way
to convert between digits and strings. Go also offers a playground in which
you can &lt;a href=&#34;https://go.dev/play/p/KtI68uMJifL&#34;&gt;run this code&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div id=&#34;summary&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;I was most pleased with the APL solution; it does what it says on the box
without ambiguity because it’s constructed entirely from primitives (or utility
functions defined in terms of those). The Julia solution also feels very clean,
while the Haskell solution, defined entirely from functions, nicely demonstrates
the functional principle.&lt;/p&gt;
&lt;p&gt;I found it to be an interesting example of where pass-by-reference is &lt;em&gt;not&lt;/em&gt; so
helpful. For packaged Julia functions that distinction is made clear with the
&lt;code&gt;!&lt;/code&gt; suffix to denote mutating functions, and it’s common to write both a
mutating and non-mutating version wherever possible.&lt;/p&gt;
&lt;p&gt;Writing these taught me more and more about using each of these languages, and
I’m of the opinion that just reading solutions is no substitute for getting your
hands dirty in some actual code.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Comments, improvements, or your own solutions are most welcome. I can be found on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; or use the comments below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.4.1 (2024-06-14)
##  os       macOS Sonoma 14.6
##  system   aarch64, darwin20
##  ui       X11
##  language (EN)
##  collate  en_US.UTF-8
##  ctype    en_US.UTF-8
##  tz       Australia/Adelaide
##  date     2024-10-29
##  pandoc   3.2 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/aarch64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.19    2024-02-01 [1] CRAN (R 4.4.0)
##  bookdown      0.41    2024-10-16 [1] CRAN (R 4.4.1)
##  bslib         0.8.0   2024-07-29 [1] CRAN (R 4.4.0)
##  cachem        1.1.0   2024-05-16 [1] CRAN (R 4.4.0)
##  cli           3.6.3   2024-06-21 [1] CRAN (R 4.4.0)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.4.0)
##  digest        0.6.37  2024-08-19 [1] CRAN (R 4.4.1)
##  ellipsis      0.3.2   2021-04-29 [1] CRAN (R 4.4.0)
##  evaluate      1.0.1   2024-10-10 [1] CRAN (R 4.4.1)
##  fastmap       1.2.0   2024-05-15 [1] CRAN (R 4.4.0)
##  fs            1.6.4   2024-04-25 [1] CRAN (R 4.4.0)
##  glue          1.8.0   2024-09-30 [1] CRAN (R 4.4.1)
##  htmltools     0.5.8.1 2024-04-04 [1] CRAN (R 4.4.0)
##  htmlwidgets   1.6.4   2023-12-06 [1] CRAN (R 4.4.0)
##  httpuv        1.6.15  2024-03-26 [1] CRAN (R 4.4.0)
##  jquerylib     0.1.4   2021-04-26 [1] CRAN (R 4.4.0)
##  jsonlite      1.8.9   2024-09-20 [1] CRAN (R 4.4.1)
##  knitr         1.48    2024-07-07 [1] CRAN (R 4.4.0)
##  later         1.3.2   2023-12-06 [1] CRAN (R 4.4.0)
##  lifecycle     1.0.4   2023-11-07 [1] CRAN (R 4.4.0)
##  magrittr      2.0.3   2022-03-30 [1] CRAN (R 4.4.0)
##  memoise       2.0.1   2021-11-26 [1] CRAN (R 4.4.0)
##  mime          0.12    2021-09-28 [1] CRAN (R 4.4.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.4.0)
##  pkgbuild      1.4.4   2024-03-17 [1] CRAN (R 4.4.0)
##  pkgload       1.4.0   2024-06-28 [1] CRAN (R 4.4.0)
##  profvis       0.4.0   2024-09-20 [1] CRAN (R 4.4.1)
##  promises      1.3.0   2024-04-05 [1] CRAN (R 4.4.0)
##  purrr         1.0.2   2023-08-10 [1] CRAN (R 4.4.0)
##  R6            2.5.1   2021-08-19 [1] CRAN (R 4.4.0)
##  Rcpp          1.0.13  2024-07-17 [1] CRAN (R 4.4.0)
##  remotes       2.5.0   2024-03-17 [1] CRAN (R 4.4.0)
##  rlang         1.1.4   2024-06-04 [1] CRAN (R 4.4.0)
##  rmarkdown     2.28    2024-08-17 [1] CRAN (R 4.4.0)
##  rstudioapi    0.17.0  2024-10-16 [1] CRAN (R 4.4.1)
##  sass          0.4.9   2024-03-15 [1] CRAN (R 4.4.0)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.4.0)
##  shiny         1.9.1   2024-08-01 [1] CRAN (R 4.4.0)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.4.0)
##  usethis       3.0.0   2024-07-29 [1] CRAN (R 4.4.0)
##  vctrs         0.6.5   2023-12-01 [1] CRAN (R 4.4.0)
##  xfun          0.48    2024-10-03 [1] CRAN (R 4.4.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.4.0)
##  yaml          2.3.10  2024-07-26 [1] CRAN (R 4.4.0)
## 
##  [1] /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Monads in R</title>
      <link>https://jcarroll.com.au/2024/10/18/monads-in-r/</link>
      <pubDate>Fri, 18 Oct 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/10/18/monads-in-r/</guid>
      <description>&lt;p&gt;In this post I describe a useful programming pattern that I implemented, and
hopefully provide a gentle introduction to the idea of monads.&lt;/p&gt;
&lt;p&gt;The motivation for all of this was that I had a {dplyr} pipeline as part of a
{shiny} app that queries a database and I wanted to “record” what steps were in
that pipeline so that I could offer them as a way to ‘reproduce’ the query. Some
of the steps might be user-defined via the UI, so it was a little more
complicated than just a hardcoded query.&lt;/p&gt;
&lt;p&gt;One quick-and-dirty solution that might come to mind would be to make a
&lt;code&gt;with_logging()&lt;/code&gt; function that takes an expression, writes a text-representation
of it to a file or a global, then evaluates the expression. This would probably
work, but it means that every step of the pipeline needs to be wrapped in that.
Not the worst, but I had a feeling I knew of something more suitable. I’ve been
trying to learn Haskell this year, and so far it’s going sort of okay, but I’m
taking a detour through Elm which has most of the same syntax but less of the
hardcore ‘maths’ constructs.&lt;/p&gt;
&lt;p&gt;Returning readers may have seen me use the term ‘monadic’ in the context of APL
where it means that a function ‘takes one argument’ (as compared to ‘dyadic’
which takes two) and I believe this definition predates the mathematical one I’m
going to use for the rest of this post.&lt;/p&gt;
&lt;p&gt;‘Monad’ is a term often best avoided in conversation, and is often described in
overly mathematical terms, the “meme” definition being the category theory
version which states&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“a monad is just a monoid in the category of endofunctors”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;which is mostly true, but also unnecessary. Nonetheless, it’s an extremely
useful pattern that comes up a lot in functional programming.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html&#34;&gt;This blog post&lt;/a&gt;
does a great job of walking through the more practical definition, and it has
“translations” into several programming languages including &lt;a href=&#34;https://medium.com/@tzehsiang/javascript-functor-applicative-monads-in-pictures-b567c6415221#.rdwll124i&#34;&gt;JavaScript&lt;/a&gt; and &lt;a href=&#34;https://github.com/dbrattli/OSlash/wiki/Functors,-Applicatives,-And-Monads-In-Pictures&#34;&gt;Python&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Basically, &lt;code&gt;map&lt;/code&gt; applies some function to some values. &lt;code&gt;flatMap&lt;/code&gt; does the same,
but first “reaches inside” a context to extract some inner values, and after
applying the function, re-wraps the result in the original context.&lt;/p&gt;
&lt;p&gt;One big advantage to this is that the ‘purity’ of the function remains; you
always get the same output for the same input, but as well as that you can have
some input/output operation be requested to be performed, which is how ‘pure’
languages still manage to communicate with the outside world and not just heat
up the CPU for no reason.&lt;/p&gt;
&lt;p&gt;The enlightening example for me is a &lt;code&gt;List&lt;/code&gt; - if we have some values and want to
apply some function to them, we can do that with, e.g.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f &amp;lt;- function(x) x^2
Map(f, c(2, 4, 6))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [[1]]
## [1] 4
## 
## [[2]]
## [1] 16
## 
## [[3]]
## [1] 36&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and if we have a ‘flat’ list, this still works&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Map(f, list(2, 4, 6))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [[1]]
## [1] 4
## 
## [[2]]
## [1] 16
## 
## [[3]]
## [1] 36&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but what if we have an ‘outer context’ list?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Map(f, list(c(2, 3), c(4, 5, 6)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [[1]]
## [1] 4 9
## 
## [[2]]
## [1] 16 25 36&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, because &lt;code&gt;f&lt;/code&gt; is vectorised, &lt;code&gt;Map&lt;/code&gt; sends each vector to &lt;code&gt;f&lt;/code&gt; and gets
a result for each list. What if we have a list in the inner context?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Map(f, list(list(2, 3), list(4, 5, 6)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in x^2: non-numeric argument to binary operator&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This fails because &lt;code&gt;f(list(2, 3))&lt;/code&gt; fails (it doesn’t know how to deal with an
argument which is a list).&lt;/p&gt;
&lt;p&gt;Instead, we can use a version of ‘map’ that first reaches inside the outer
&lt;code&gt;list&lt;/code&gt; context, concatenates what’s inside, applies the function, then re-wraps
the result in a new, flat list&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fmap &amp;lt;- function(x, f) {
  list(f(unlist(x)))
}
fmap(list(list(2, 3), list(4, 5, 6)), f)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [[1]]
## [1]  4  9 16 25 36&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the essence of a monad - something that supports such a &lt;code&gt;fmap&lt;/code&gt; operation
that performs the mapping inside the context (and potentially some other
operations, which we’ll get to). There are various patterns which benefit from
such a context, and this vignette describes an implementation of several of
these via the &lt;a href=&#34;https://jonocarroll.github.io/monads/index.html&#34;&gt;{monads}&lt;/a&gt;
package.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;fmap&lt;/code&gt; operation is so common that it’s typical to find it presented as an
infix function, similar to how pipes work in R&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;list(list(2, 3), list(4, 5, 6)) |&amp;gt; fmap(f)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [[1]]
## [1]  4  9 16 25 36&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and we can go one step further by defining a new pipe which is just a different
syntax for this&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;x |&amp;gt; fmap(f)

x %&amp;gt;&amp;gt;=% f&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This infix function borrows from Haskell’s &lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt; (pronounced “bind”) which is
so fundamental that forms part of the language’s logo&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/haskell_logo.png&#34; width=&#34;400&#34; alt=&#34;The Haskell logo&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;The Haskell logo&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With all that in mind, here’s how it looks in my (perhaps simplistic)
implementation which you can
&lt;a href=&#34;https://github.com/jonocarroll/monads&#34;&gt;get from GitHub here&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(monads)&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/logo.png&#34; alt=&#34;{monads} hex logo&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;{monads} hex logo&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Additionally, some toy helper functions are defined in this package for
demonstrating application of functions, e.g.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;timestwo(4)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 8&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;square(5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 25&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;add_n(3, 4)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 7&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#34;list&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;List&lt;/h2&gt;
&lt;p&gt;As per the example above, the &lt;code&gt;List&lt;/code&gt; monad wraps values (which may be additional
&lt;code&gt;list&lt;/code&gt;s) and when &lt;code&gt;flatMap&lt;/code&gt;ed the results are ‘flattened’ into a single &lt;code&gt;List&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# identical to a regular Map
x &amp;lt;- listM(1, 2, 3) %&amp;gt;&amp;gt;=%
  timestwo()
x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [[1]]
## [1] 2 4 6&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# only possible with the flatMap approach
y &amp;lt;- listM(list(1, 2), list(3, 4, 5)) %&amp;gt;&amp;gt;=% 
  timestwo()
y&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [[1]]
## [1]  2  4  6  8 10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that while &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; print as regular lists, they remain &lt;code&gt;List&lt;/code&gt; monads;
a &lt;code&gt;print&lt;/code&gt; method is defined which essentially extracts &lt;code&gt;value(x)&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;logger&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Logger&lt;/h2&gt;
&lt;p&gt;As I alluded to earlier, additional operations can happen while the context is
unwrapped, including IO. What if I just kept a log of the operations and
appended each step to it? The wrapping context can include additional
components, and a stored ‘log’ of the expressions used at each step is entirely
possible.&lt;/p&gt;
&lt;p&gt;All that is required is to wrap the value at the start of the pipeline in a
&lt;code&gt;Logger&lt;/code&gt; context for which there is a constructor helper, &lt;code&gt;loggerM()&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(dplyr, warn.conflicts = FALSE)

result &amp;lt;- loggerM(mtcars) %&amp;gt;&amp;gt;=%
  filter(mpg &amp;gt; 10) %&amp;gt;&amp;gt;=%
  select(mpg, cyl, disp) %&amp;gt;&amp;gt;=%
  arrange(desc(mpg)) %&amp;gt;&amp;gt;=%
  head()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This result is still a &lt;code&gt;Logger&lt;/code&gt; instance, not a value. To extract the value from
this we can use &lt;code&gt;value()&lt;/code&gt;. To extract the log of each step, use &lt;code&gt;logger_log()&lt;/code&gt;
(to avoid conflict with &lt;code&gt;base::log&lt;/code&gt;)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;value(result)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##                 mpg cyl  disp
## Toyota Corolla 33.9   4  71.1
## Fiat 128       32.4   4  78.7
## Honda Civic    30.4   4  75.7
## Lotus Europa   30.4   4  95.1
## Fiat X1-9      27.3   4  79.0
## Porsche 914-2  26.0   4 120.3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;logger_log(result)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ✔ Log of 4 operations:&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 
##  mtcars %&amp;gt;%
##    filter(mpg &amp;gt; 10) %&amp;gt;%
##    select(mpg, cyl, disp) %&amp;gt;%
##    arrange(desc(mpg)) %&amp;gt;%
##    head()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works with any data value, so we could just as easily use an in-memory
SQLite database (or external)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mem &amp;lt;- DBI::dbConnect(RSQLite::SQLite(), &amp;quot;:memory:&amp;quot;)
dplyr::copy_to(mem, mtcars)

res &amp;lt;- loggerM(mem) %&amp;gt;&amp;gt;=%
  tbl(&amp;quot;mtcars&amp;quot;) %&amp;gt;&amp;gt;=%
  filter(mpg &amp;gt; 10) %&amp;gt;&amp;gt;=%
  select(mpg, cyl, disp) %&amp;gt;&amp;gt;=%
  arrange(desc(mpg)) %&amp;gt;&amp;gt;=%
  head()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, extracting the components from this&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;value(res)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # Source:     SQL [6 x 3]
## # Database:   sqlite 3.46.0 [:memory:]
## # Ordered by: desc(mpg)
##     mpg   cyl  disp
##   &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt;
## 1  33.9     4  71.1
## 2  32.4     4  78.7
## 3  30.4     4  75.7
## 4  30.4     4  95.1
## 5  27.3     4  79  
## 6  26       4 120.&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;logger_log(res)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ✔ Log of 5 operations:&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 
##  mem %&amp;gt;%
##    tbl(&amp;quot;mtcars&amp;quot;) %&amp;gt;%
##    filter(mpg &amp;gt; 10) %&amp;gt;%
##    select(mpg, cyl, disp) %&amp;gt;%
##    arrange(desc(mpg)) %&amp;gt;%
##    head()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since the log captures what operations were performed, we could re-run this
expression, and a helper is available for that&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;rerun(res)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # Source:     SQL [6 x 3]
## # Database:   sqlite 3.46.0 [:memory:]
## # Ordered by: desc(mpg)
##     mpg   cyl  disp
##   &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt;
## 1  33.9     4  71.1
## 2  32.4     4  78.7
## 3  30.4     4  75.7
## 4  30.4     4  95.1
## 5  27.3     4  79  
## 6  26       4 120.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some similar functionality is present in the {magrittr} package which provides
the ‘classic’ R pipe &lt;code&gt;%&amp;gt;%&lt;/code&gt;; a ‘functional sequence’ starts with a &lt;code&gt;.&lt;/code&gt; and
similarly tracks which functions are to be applied to an arbitrary input once
evaluated - in this way, this is similar to defining a new function.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(magrittr)

# define a functional sequence
fs &amp;lt;- . %&amp;gt;%
  tbl(&amp;quot;mtcars&amp;quot;) %&amp;gt;%
  select(cyl, mpg)

# evaluate the functional sequence with some input data
fs(mem)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # Source:   SQL [?? x 2]
## # Database: sqlite 3.46.0 [:memory:]
##      cyl   mpg
##    &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt;
##  1     6  21  
##  2     6  21  
##  3     4  22.8
##  4     6  21.4
##  5     8  18.7
##  6     6  18.1
##  7     8  14.3
##  8     4  24.4
##  9     4  22.8
## 10     6  19.2
## # ℹ more rows&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# identify the function calls at each step of the pipeline
magrittr::functions(fs)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [[1]]
## function (.) 
## tbl(., &amp;quot;mtcars&amp;quot;)
## 
## [[2]]
## function (.) 
## select(., cyl, mpg)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since the functional sequence is unevaluated, errors can be present and not
triggered&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;errfs &amp;lt;- . %&amp;gt;%
  sqrt() %&amp;gt;%
  stop(&amp;quot;oops&amp;quot;) %&amp;gt;%
  add_n(3)

x &amp;lt;- 1:10

errfs(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in function_list[[i]](value): 11.41421356237311.7320508075688822.236067977499792.449489742783182.645751311064592.8284271247461933.16227766016838oops&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;magrittr::functions(errfs)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [[1]]
## function (.) 
## sqrt(.)
## 
## [[2]]
## function (.) 
## stop(., &amp;quot;oops&amp;quot;)
## 
## [[3]]
## function (.) 
## add_n(., 3)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the monad context, steps which do raise an error nullify the value and a
signifier is added to the log to prevent re-running the error&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;resx &amp;lt;- loggerM(x) %&amp;gt;&amp;gt;=%
  sqrt() %&amp;gt;&amp;gt;=%
  add_n(4)

value(resx)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] 5.000000 5.414214 5.732051 6.000000 6.236068 6.449490 6.645751 6.828427
##  [9] 7.000000 7.162278&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;logger_log(resx)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ✔ Log of 2 operations:&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 
##  x %&amp;gt;%
##    sqrt() %&amp;gt;%
##    add_n(4)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;err &amp;lt;- loggerM(x) %&amp;gt;&amp;gt;=%
  sqrt() %&amp;gt;&amp;gt;=%
  stop(&amp;quot;oops&amp;quot;) %&amp;gt;&amp;gt;=%
  add_n(3)

value(err)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## NULL&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;logger_log(err)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ✖ Log of 3 operations: [ERROR]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 
##  x %&amp;gt;%
##    sqrt() %&amp;gt;%
##    [E] stop(&amp;quot;oops&amp;quot;) %&amp;gt;%
##    [E] add_n(3)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Aside from an error destroying the value, returning a &lt;code&gt;NULL&lt;/code&gt; result will also
produce this effect&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nullify &amp;lt;- loggerM(x) %&amp;gt;&amp;gt;=%
  sqrt() %&amp;gt;&amp;gt;=%
  ret_null() %&amp;gt;&amp;gt;=%
  add_n(7)

value(nullify)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## NULL&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;logger_log(nullify)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ✖ Log of 3 operations: [ERROR]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 
##  x %&amp;gt;%
##    sqrt() %&amp;gt;%
##    [E] ret_null() %&amp;gt;%
##    [E] add_n(7)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One downside to the functional sequence approach is chaining these - since the
first term must be &lt;code&gt;.&lt;/code&gt;, that is always the first entry, and chaining multiple
sequences is not clean.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- . %&amp;gt;% sqrt()
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## Functional sequence with the following components:
## 
##  1. sqrt(.)
## 
## Use &amp;#39;functions&amp;#39; to extract the individual functions.&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;b &amp;lt;- . %&amp;gt;% a %&amp;gt;% add_n(1)
b&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## Functional sequence with the following components:
## 
##  1. a(.)
##  2. add_n(., 1)
## 
## Use &amp;#39;functions&amp;#39; to extract the individual functions.&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;b(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] 2.000000 2.414214 2.732051 3.000000 3.236068 3.449490 3.645751 3.828427
##  [9] 4.000000 4.162278&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because the monad context is recreated at every step, chaining these is not a
problem&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- loggerM(x) %&amp;gt;&amp;gt;=%
  sqrt()

value(a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] 1.000000 1.414214 1.732051 2.000000 2.236068 2.449490 2.645751 2.828427
##  [9] 3.000000 3.162278&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;logger_log(a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ✔ Log of 1 operations:&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 
##  x %&amp;gt;%
##    sqrt()&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;b &amp;lt;- a %&amp;gt;&amp;gt;=%
  add_n(1)

value(b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] 2.000000 2.414214 2.732051 3.000000 3.236068 3.449490 3.645751 3.828427
##  [9] 4.000000 4.162278&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;logger_log(b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ✔ Log of 2 operations:&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 
##  x %&amp;gt;%
##    sqrt() %&amp;gt;%
##    add_n(1)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This achieves what I wanted in terms of ‘recording’ the steps of the pipeline,
and it only requires wrapping the initial value and using a different pipe.&lt;/p&gt;
&lt;p&gt;But there are other monads I could also implement… so I did.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;timer&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Timer&lt;/h2&gt;
&lt;p&gt;In addition to capturing the expressions in a log, the &lt;code&gt;Timer&lt;/code&gt; monad also
captures the evaluation timing for each step, storing these alongside the
expressions themselves in a &lt;code&gt;data.frame&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- timerM(5) %&amp;gt;&amp;gt;=%
  sleep_for(3) %&amp;gt;&amp;gt;=%
  timestwo() %&amp;gt;&amp;gt;=%
  sleep_for(1.3)

value(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 10&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;times(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##             expr  time
## 1              5 0.000
## 2   sleep_for(3) 3.014
## 3     timestwo() 0.000
## 4 sleep_for(1.3) 1.306&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;y &amp;lt;- timerM(5) %&amp;gt;&amp;gt;=%
  sleep_for(2) %&amp;gt;&amp;gt;=%
  ret_null() %&amp;gt;&amp;gt;=%
  sleep_for(0.3)

value(y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## NULL&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;times(y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##             expr  time
## 1              5 0.000
## 2   sleep_for(2) 2.002
## 3     ret_null() 0.000
## 4 sleep_for(0.3) 0.302&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;maybe&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Maybe&lt;/h2&gt;
&lt;p&gt;In some languages it is preferrable to return &lt;em&gt;something&lt;/em&gt; rather than raising
an error, particularly if you want to ensure that errors are handled. The
&lt;code&gt;Maybe&lt;/code&gt; pattern consists of either a &lt;code&gt;Nothing&lt;/code&gt; (which is empty) or a &lt;code&gt;Just&lt;/code&gt;
containing some value; all functions applied to a &lt;code&gt;Maybe&lt;/code&gt; will be one of these.&lt;/p&gt;
&lt;p&gt;For testing the result, some helpers &lt;code&gt;is_nothing()&lt;/code&gt; and &lt;code&gt;is_just()&lt;/code&gt; are defined.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- maybeM(9) %&amp;gt;&amp;gt;=% 
  sqrt() %&amp;gt;&amp;gt;=%
  timestwo()

value(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## Just:
## [1] 6&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_just(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_nothing(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;y &amp;lt;- maybeM(Nothing()) %&amp;gt;&amp;gt;=%
  sqrt()

value(y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## Nothing&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_just(y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_nothing(y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;z &amp;lt;- maybeM(10) %&amp;gt;&amp;gt;=%
  timestwo() %&amp;gt;&amp;gt;=%
  add_n(Nothing())

value(z)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## Nothing&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_just(z)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_nothing(z)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For what is likely a much more robust implementation, see
&lt;a href=&#34;https://armcn.github.io/maybe/&#34;&gt;{maybe}&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;result&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Result&lt;/h2&gt;
&lt;p&gt;Similar to a &lt;code&gt;Maybe&lt;/code&gt;, a &lt;code&gt;Result&lt;/code&gt; can contain either a successful &lt;code&gt;Ok&lt;/code&gt; wrapped
value or an &lt;code&gt;Err&lt;/code&gt; wrapped message, but it will be one of these. This pattern
resembles (and internally, uses) the &lt;code&gt;tryCatch()&lt;/code&gt; approach where the evaluation
will not fail, but requires testing what is produced to determine success, for
which &lt;code&gt;is_ok()&lt;/code&gt; and &lt;code&gt;is_err()&lt;/code&gt; are defined.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- resultM(9) %&amp;gt;&amp;gt;=% 
  sqrt() %&amp;gt;&amp;gt;=%
  timestwo()

value(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## OK:
## [1] 6&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_err(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_ok(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the evaluation fails, the error is reported, along with the value &lt;em&gt;prior&lt;/em&gt;
to the error&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;y &amp;lt;- resultM(9) %&amp;gt;&amp;gt;=%
  sqrt() %&amp;gt;&amp;gt;=%
  ret_err(&amp;quot;this threw an error&amp;quot;)

value(y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## Error:
## [1] &amp;quot;this threw an error; previously: 3&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_err(y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_ok(y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;z &amp;lt;- resultM(10) %&amp;gt;&amp;gt;=%
  timestwo() %&amp;gt;&amp;gt;=%
  add_n(&amp;quot;banana&amp;quot;)

value(z)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## Error:
## [1] &amp;quot;n should be numeric; previously: 20&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_err(z)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_ok(z)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;extensions&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Extensions&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;flatMap&lt;/code&gt;/“bind” operator defined here as &lt;code&gt;%&amp;gt;&amp;gt;=%&lt;/code&gt; is applicable to any monad
which has a &lt;code&gt;bind()&lt;/code&gt; method defined. The monads defined in this package are all
&lt;code&gt;R6Class&lt;/code&gt; objects exposing such a method of the form &lt;code&gt;m$bind(.call, .quo)&lt;/code&gt; which
expects a function and a quosure. You can add your own extensions to these by
defining such a class (and probably a constructor helper and a &lt;code&gt;print()&lt;/code&gt; method)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# a Reporter monad which reports unpiped function calls
Reporter &amp;lt;- R6::R6Class(
  c(&amp;quot;ReporterMonad&amp;quot;),
  public = list(
    value = NULL,
    initialize = function(value) {
      if (rlang::is_quosure(value)) {
        self$value &amp;lt;- rlang::eval_tidy(value)
      } else {
        self$value &amp;lt;- value
      }
    },
    bind = function(f, expr) {
      ## &amp;#39;undo&amp;#39; the pipe and inject the lhs as an argument
      result &amp;lt;- unlist(lapply(unlist(self$value), f))
      args &amp;lt;- as.list(c(self$value, rlang::call_args(expr)))
      fnew &amp;lt;- rlang::call2(rlang::call_name(expr), !!!args)
      cat(&amp;quot; ** Calculating:&amp;quot;, rlang::quo_text(fnew), &amp;quot;=&amp;quot;, result, &amp;quot;\n&amp;quot;)
      Reporter$new(result)
    }
  )
)

reporterM &amp;lt;- function(value) {
  v &amp;lt;- rlang::enquo(value)
  Reporter$new(v)
}

print.Reporter &amp;lt;- function(x, ...) {
  print(value(x))
}

x &amp;lt;- reporterM(17) %&amp;gt;&amp;gt;=%
  timestwo() %&amp;gt;&amp;gt;=%
  square() %&amp;gt;&amp;gt;=% 
  add_n(2) %&amp;gt;&amp;gt;=%
  `/`(8)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  ** Calculating: timestwo(17) = 34 
##  ** Calculating: square(34) = 1156 
##  ** Calculating: add_n(1156, 2) = 1158 
##  ** Calculating: 1158/8 = 144.75&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;value(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 144.75&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is just a toy example; attempting to &lt;code&gt;cat()&lt;/code&gt; a &lt;code&gt;data.frame&lt;/code&gt; result would
not go well.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;other-monads&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Other Monads&lt;/h2&gt;
&lt;p&gt;There are other patterns that I haven’t implemented. One that would have been
interesting is &lt;code&gt;Promise&lt;/code&gt; - I had a ‘mind-blown’ moment reading
&lt;a href=&#34;https://rtfeldman.com/imperative-clothing&#34;&gt;this post about some Roc syntax&lt;/a&gt;
with the throw-away line&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tasks can be chained together using the &lt;code&gt;Task.await&lt;/code&gt; function, similarly to
how JavaScript Promises can be chained together using a Promise’s &lt;code&gt;then()&lt;/code&gt;
method. (You might also know functions in other languages similar to
&lt;code&gt;Task.await&lt;/code&gt; which go by names like &lt;code&gt;andThen&lt;/code&gt;, &lt;code&gt;flatMap&lt;/code&gt;, or &lt;code&gt;bind&lt;/code&gt;.)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;because I had never made the connection between monads and async/await, but it’s
a lot clearer now. I did try implementing &lt;code&gt;Promise&lt;/code&gt; in {monads} using {future}
but I couldn’t quite get the unevaluated promise object to pipe correctly.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;prior-art&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Prior Art&lt;/h2&gt;
&lt;p&gt;There are a handful of existing implementations, most of which are more fleshed
out than mine.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/hadley/monads&#34;&gt;{monads}&lt;/a&gt; - a sketched-out implementation
that relies on dispatch for &lt;code&gt;flatMap&lt;/code&gt; operations. I’m using the same name as
this package, but that one hasn’t been touched in quite a while.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/arendsee/rmonad&#34;&gt;{rmonad}&lt;/a&gt; - archived on CRAN, but offers
a sophisticated ‘funnel’ mechanism and various ways to capture steps of a pipeline.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://armcn.github.io/maybe/&#34;&gt;{maybe}&lt;/a&gt; - a more detailed implementation of
&lt;code&gt;Maybe&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://b-rodrigues.github.io/chronicler/&#34;&gt;{chronicler}&lt;/a&gt; - a way to
post-process the result at each step and capture information, such as the
runtime (see &lt;code&gt;Timer&lt;/code&gt;) or dimensions. Requires an explicit &lt;code&gt;bind()&lt;/code&gt; at each step.
&lt;a href=&#34;https://www.brodrigues.co/blog/2022-04-11-monads/&#34;&gt;Associated blog post&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also found &lt;a href=&#34;https://kupac.gitlab.io/biofunctor/2019/05/25/maybe-monad-in-r/&#34;&gt;this post&lt;/a&gt;
about implementing a &lt;code&gt;Maybe&lt;/code&gt; monad, and &lt;a href=&#34;https://scscript.blogspot.com/2011/03/monads-in-r-sapply-and-foreach.html?m=1&#34;&gt;this one&lt;/a&gt;
comparing the {foreach} package’s &lt;code&gt;%do%&lt;/code&gt; to Haskell.&lt;/p&gt;
&lt;p&gt;I’m somewhat surprised that in all of the above examples, none seem to use the
Haskell ‘bind’ format of a pipe (&lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt; or as a valid R infix special, &lt;code&gt;%&amp;gt;&amp;gt;=%&lt;/code&gt;)
but at least I’m not stepping on other package’s toes there. One particular
benefit of this one is that by deleting the two outermost characters inside the
special you get the {magrittr} pipe &lt;code&gt;%&amp;gt;%&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If nothing else, I found it really useful to go through the process of defining
these myself - I learned a lot about {R6} classes and quosures in the process,
too.&lt;/p&gt;
&lt;p&gt;My package comes with no guarantees - it works for the examples I’ve tried, but
it’s possible (if not likely) that I’ve not thought of all the edge cases. I’ve
certainly relied on R’s vectorisation (rather than explicitly re-mapping
individual values) and my quosure skills are somewhat underdeveloped.&lt;/p&gt;
&lt;p&gt;If you do &lt;a href=&#34;https://github.com/jonocarroll/monads&#34;&gt;take it for a spin&lt;/a&gt; I’d love
to hear your thoughts on it. As always, I can be found on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; and the comment section below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.3 (2024-02-29)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2024-10-18
##  pandoc   3.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version    date (UTC) lib source
##  bit           4.0.4      2020-08-04 [3] CRAN (R 4.0.2)
##  bit64         4.0.5      2020-08-30 [3] CRAN (R 4.2.0)
##  blob          1.2.4      2023-03-17 [3] CRAN (R 4.2.3)
##  blogdown      1.19       2024-02-01 [1] CRAN (R 4.3.3)
##  bookdown      0.36       2023-10-16 [1] CRAN (R 4.3.2)
##  bslib         0.8.0      2024-07-29 [1] CRAN (R 4.3.3)
##  cachem        1.1.0      2024-05-16 [1] CRAN (R 4.3.3)
##  callr         3.7.3      2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1      2023-03-23 [1] CRAN (R 4.3.3)
##  crayon        1.5.2      2022-09-29 [3] CRAN (R 4.2.1)
##  DBI           1.2.1      2024-01-12 [3] CRAN (R 4.3.2)
##  dbplyr        2.4.0      2023-10-26 [3] CRAN (R 4.3.2)
##  devtools      2.4.5      2022-10-11 [1] CRAN (R 4.3.2)
##  digest        0.6.37     2024-08-19 [1] CRAN (R 4.3.3)
##  dplyr       * 1.1.4      2023-11-17 [3] CRAN (R 4.3.2)
##  ellipsis      0.3.2      2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.24.0     2024-06-10 [1] CRAN (R 4.3.3)
##  fansi         1.0.6      2023-12-08 [1] CRAN (R 4.3.3)
##  fastmap       1.2.0      2024-05-15 [1] CRAN (R 4.3.3)
##  fs            1.6.4      2024-04-25 [1] CRAN (R 4.3.3)
##  generics      0.1.3      2022-07-05 [1] CRAN (R 4.3.3)
##  glue          1.7.0      2024-01-09 [1] CRAN (R 4.3.3)
##  htmltools     0.5.8.1    2024-04-04 [1] CRAN (R 4.3.3)
##  htmlwidgets   1.6.2      2023-03-17 [1] CRAN (R 4.3.2)
##  httpuv        1.6.12     2023-10-23 [1] CRAN (R 4.3.2)
##  icecream      0.2.1      2023-09-27 [1] CRAN (R 4.3.2)
##  jquerylib     0.1.4      2021-04-26 [1] CRAN (R 4.3.3)
##  jsonlite      1.8.8      2023-12-04 [1] CRAN (R 4.3.3)
##  knitr         1.48       2024-07-07 [1] CRAN (R 4.3.3)
##  later         1.3.1      2023-05-02 [1] CRAN (R 4.3.2)
##  lifecycle     1.0.4      2023-11-07 [1] CRAN (R 4.3.3)
##  magrittr    * 2.0.3      2022-03-30 [1] CRAN (R 4.3.3)
##  memoise       2.0.1      2021-11-26 [1] CRAN (R 4.3.3)
##  mime          0.12       2021-09-28 [1] CRAN (R 4.3.3)
##  miniUI        0.1.1.1    2018-05-18 [1] CRAN (R 4.3.2)
##  monads      * 0.1.0.9000 2024-10-14 [1] local
##  pillar        1.9.0      2023-03-22 [1] CRAN (R 4.3.3)
##  pkgbuild      1.4.2      2023-06-26 [1] CRAN (R 4.3.2)
##  pkgconfig     2.0.3      2019-09-22 [1] CRAN (R 4.3.3)
##  pkgload       1.3.3      2023-09-22 [1] CRAN (R 4.3.2)
##  prettyunits   1.2.0      2023-09-24 [3] CRAN (R 4.3.1)
##  processx      3.8.3      2023-12-10 [3] CRAN (R 4.3.2)
##  profvis       0.3.8      2023-05-02 [1] CRAN (R 4.3.2)
##  promises      1.2.1      2023-08-10 [1] CRAN (R 4.3.2)
##  ps            1.7.6      2024-01-18 [3] CRAN (R 4.3.2)
##  purrr         1.0.2      2023-08-10 [3] CRAN (R 4.3.1)
##  R6            2.5.1      2021-08-19 [1] CRAN (R 4.3.3)
##  Rcpp          1.0.11     2023-07-06 [1] CRAN (R 4.3.2)
##  remotes       2.4.2.1    2023-07-18 [1] CRAN (R 4.3.2)
##  rlang         1.1.4      2024-06-04 [1] CRAN (R 4.3.3)
##  rmarkdown     2.28       2024-08-17 [1] CRAN (R 4.3.3)
##  RSQLite       2.3.7      2024-05-27 [1] CRAN (R 4.3.3)
##  rstudioapi    0.15.0     2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.9      2024-03-15 [1] CRAN (R 4.3.3)
##  sessioninfo   1.2.2      2021-12-06 [1] CRAN (R 4.3.2)
##  shiny         1.7.5.1    2023-10-14 [1] CRAN (R 4.3.2)
##  stringi       1.8.4      2024-05-06 [1] CRAN (R 4.3.3)
##  stringr       1.5.1      2023-11-14 [1] CRAN (R 4.3.3)
##  tibble        3.2.1      2023-03-20 [1] CRAN (R 4.3.3)
##  tidyselect    1.2.0      2022-10-10 [3] CRAN (R 4.2.1)
##  urlchecker    1.0.1      2021-11-30 [1] CRAN (R 4.3.2)
##  usethis       3.0.0      2024-07-29 [1] CRAN (R 4.3.3)
##  utf8          1.2.4      2023-10-22 [1] CRAN (R 4.3.3)
##  vctrs         0.6.5      2023-12-01 [1] CRAN (R 4.3.3)
##  withr         3.0.0      2024-01-16 [1] CRAN (R 4.3.3)
##  xfun          0.47       2024-08-17 [1] CRAN (R 4.3.3)
##  xtable        1.8-4      2019-04-21 [1] CRAN (R 4.3.2)
##  yaml          2.3.10     2024-07-26 [1] CRAN (R 4.3.3)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>A Safe Space for Learning How to Make Pull Requests</title>
      <link>https://jcarroll.com.au/2024/10/01/a-safe-space-for-learning-how-to-make-pull-requests/</link>
      <pubDate>Tue, 01 Oct 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/10/01/a-safe-space-for-learning-how-to-make-pull-requests/</guid>
      <description>&lt;p&gt;As October rolls around once more, the term Hacktoberfest might pop across your
feeds; an effort aiming to encourage people to contribute to open-source
software, particularly if they’re new to that. In this post I’ll describe what
I’m offering towards that goal.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hacktoberfest.com/participation/&#34;&gt;Hacktoberfest&lt;/a&gt; has been running since
(I think) 2017 and I’ve participated in at least one year - previously
contributors who had the requisite 4 PRs merged received a free t-shirt, but I
suspect that program became overly costly.&lt;/p&gt;
&lt;p&gt;The site describes this as “DigitalOcean’s annual event that encourages
people to contribute to open source” and while one could be cynical (as I
usually am) about a corporate-sponsored “hack” event I have instead decided to
take the opportunity to be encouraging, and help raise the abilities of more
developers. A rising tide lifts all boats.&lt;/p&gt;
&lt;p&gt;Even I started somewhere…&lt;/p&gt;
&lt;p&gt;I’ve been sending code suggestions in the form of pull requests to repositories
I don’t own for very nearly 10 years now - it seems I created my &lt;a href=&#34;https://github.com/jonocarroll&#34;&gt;GitHub
account&lt;/a&gt; on Nov 1, 2014.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/joined_gh.png&#34; alt=&#34;I created my GitHub account and made my first pull request on Nov 1, 2014&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;I created my GitHub account and made my first pull request on Nov 1, 2014&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I made my first pull request in the now archived repository for the {twitteR}
package to fix a single-letter typo in some code, presumably because I noticed
it was broken when using it&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/fix_typo.png&#34; alt=&#34;Changing “errrors” to “errors”&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Changing “errrors” to “errors”&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and in which I apologised just in case I was fixing something that wasn’t
broken (in hindsight, it clearly was, but this was my &lt;em&gt;first&lt;/em&gt; ever pull request,
so, nerves, I guess).&lt;/p&gt;
&lt;p&gt;Judging by the default pull request title “Update &amp;lt;file&amp;gt;” I used the
web interface to achieve this rather than actually pulling a local copy of the
codebase - I now know that titles are a useful way to understand what changes
are being made, especially when looking through a list of pull requests or
issues to see if what you’ve found is already being addressed somewhere. “This
is broken”, “doesn’t work”, “fixed things” are all unhelpful titles when it
comes to browsing a list of these and trying to figure out if the JSON parsing
throwing an unexpected error is a ‘known bug’. You gotta start somewhere,
though.&lt;/p&gt;
&lt;p&gt;Since then I’ve created another 271 pull requests (according to &lt;a href=&#34;https://github.com/search?q=author%3Ajonocarroll+&amp;amp;type=pullrequests&#34;&gt;GitHub&lt;/a&gt;) to
various repositories - some my own (82) but most not. It’s all too easy to forget
how familiar I’ve become with that workflow.&lt;/p&gt;
&lt;p&gt;At &lt;a href=&#34;https://rweekly.org&#34;&gt;RWeekly&lt;/a&gt; we encourage users to submit new blog posts to
us (particularly those that we aren’t otherwise likely to capture via our RSS
feed fetches) via pull requests, and we try to make that as smooth as possible,
but I would bet there’s a reasonable number of readers out there who don’t feel
comfortable with the pull request process to do that.&lt;/p&gt;
&lt;p&gt;There’s no shortage of material on the web explaining how to work with pull requests
in R either at the command line or in RStudio&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://tonyelhabr.rbind.io/posts/making-first-pull-request/&#34;&gt;https://tonyelhabr.rbind.io/posts/making-first-pull-request/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://r-bio.github.io/intro-git-rstudio/&#34;&gt;https://r-bio.github.io/intro-git-rstudio/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://rfortherestofus.com/2021/02/how-to-use-git-github-with-r/&#34;&gt;https://rfortherestofus.com/2021/02/how-to-use-git-github-with-r/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://r-pkgs.org/software-development-practices.html#git-pullreq&#34;&gt;https://r-pkgs.org/software-development-practices.html#git-pullreq&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;but that’s theory - how does a new user practice making a pull request?&lt;/p&gt;
&lt;p&gt;Sure, you could create a toy repository, make your own pull request to that and
merge it yourself - and I recommend you do, it’s great practice - but will that
make you sufficiently comfortable to make a request to &lt;em&gt;someone else’s&lt;/em&gt;
codebase?&lt;/p&gt;
&lt;p&gt;If not, I’m here for you…&lt;/p&gt;
&lt;p&gt;Introducing &lt;a href=&#34;https://github.com/jonocarroll/safespace&#34;&gt;{safespace}&lt;/a&gt; which is a
“broken” repository full of things that need fixing, with zero consequences if
you accidentally break something while learning. The idea of this repository is
to have somewhere a very new user can submit a &lt;em&gt;real&lt;/em&gt; pull request, have it
reviewed (with compassion but aiming to help you improve), and merged. As a
bonus, it’s tagged with the &lt;code&gt;hacktoberfest&lt;/code&gt; topic, so if you do get a pull
request merged it counts towards your contributions; if you have 4 pull requests
started and merged during October across participating repositories you get a
shiny digital badge!&lt;/p&gt;
&lt;p&gt;The repository contains a “real” (but toy) R package that is currently in a broken
state - it requires some code changes to make it work. It also has all sorts of
things that could be improved; typos, documentation, logic issues, etc… it’s
also (hopefully) a good way to learn about building R packages and seeing what
needs to be fixed.&lt;/p&gt;
&lt;p&gt;My target audience for this repository is people who wish they had somewhere to
send a real pull request because they don’t yet feel comfortable participating in
open source software. It’s not for people already comfortable who just want to show
off that they can make pull requests or code changes; I’ll probably just close
any of those if I spot them.&lt;/p&gt;
&lt;p&gt;I’ve added some instructions to the README since this audience is, by definition,
less familiar with the workflow. If those aren’t clear enough or are plain old
wrong, please let me know!&lt;/p&gt;
&lt;p&gt;Open a pull request suggesting some code changes, and I’ll provide some feedback
on the changes; things you may have overlooked, other ways to achieve the same, or
notes on construction. All going well, by the end of October, the repository and
package will be in a fully “working” state, passing &lt;code&gt;devtools::check()&lt;/code&gt;, and with
some reasonable documentation.&lt;/p&gt;
&lt;p&gt;If you’re really unsure about the whole ‘contributing code’ thing but can see
something that looks broken, you can also create an
&lt;a href=&#34;https://github.com/jonocarroll/safespace/issues/new/choose&#34;&gt;Issue&lt;/a&gt; which is a
sort of ‘bug report’ feature on GitHub where you identify something that could
be improved without necessarily fixing it. You &lt;em&gt;can&lt;/em&gt; make code suggestions in there,
but it still needs someone to implement the change.&lt;/p&gt;
&lt;p&gt;Lastly, this really only works if some of the people who would benefit from such
a learning opportunity find out about it, so boosts and re-shares of this post,
the toot announcing it, or the link to the repository itself&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/jonocarroll/safespace&#34;&gt;https://github.com/jonocarroll/safespace&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;would be greatly appreciated!&lt;/p&gt;
&lt;p&gt;As always, I can be found on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; and the comment section below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.3 (2024-02-29)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2024-10-03
##  pandoc   3.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.19    2024-02-01 [1] CRAN (R 4.3.3)
##  bookdown      0.36    2023-10-16 [1] CRAN (R 4.3.2)
##  bslib         0.8.0   2024-07-29 [1] CRAN (R 4.3.3)
##  cachem        1.1.0   2024-05-16 [1] CRAN (R 4.3.3)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [1] CRAN (R 4.3.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.3.2)
##  digest        0.6.37  2024-08-19 [1] CRAN (R 4.3.3)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.24.0  2024-06-10 [1] CRAN (R 4.3.3)
##  fastmap       1.2.0   2024-05-15 [1] CRAN (R 4.3.3)
##  fs            1.6.4   2024-04-25 [1] CRAN (R 4.3.3)
##  glue          1.7.0   2024-01-09 [1] CRAN (R 4.3.3)
##  htmltools     0.5.8.1 2024-04-04 [1] CRAN (R 4.3.3)
##  htmlwidgets   1.6.2   2023-03-17 [1] CRAN (R 4.3.2)
##  httpuv        1.6.12  2023-10-23 [1] CRAN (R 4.3.2)
##  icecream      0.2.1   2023-09-27 [1] CRAN (R 4.3.2)
##  jquerylib     0.1.4   2021-04-26 [1] CRAN (R 4.3.3)
##  jsonlite      1.8.8   2023-12-04 [1] CRAN (R 4.3.3)
##  knitr         1.48    2024-07-07 [1] CRAN (R 4.3.3)
##  later         1.3.1   2023-05-02 [1] CRAN (R 4.3.2)
##  lifecycle     1.0.4   2023-11-07 [1] CRAN (R 4.3.3)
##  magrittr      2.0.3   2022-03-30 [1] CRAN (R 4.3.3)
##  memoise       2.0.1   2021-11-26 [1] CRAN (R 4.3.3)
##  mime          0.12    2021-09-28 [1] CRAN (R 4.3.3)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.3.2)
##  pkgbuild      1.4.2   2023-06-26 [1] CRAN (R 4.3.2)
##  pkgload       1.3.3   2023-09-22 [1] CRAN (R 4.3.2)
##  prettyunits   1.2.0   2023-09-24 [3] CRAN (R 4.3.1)
##  processx      3.8.3   2023-12-10 [3] CRAN (R 4.3.2)
##  profvis       0.3.8   2023-05-02 [1] CRAN (R 4.3.2)
##  promises      1.2.1   2023-08-10 [1] CRAN (R 4.3.2)
##  ps            1.7.6   2024-01-18 [3] CRAN (R 4.3.2)
##  purrr         1.0.2   2023-08-10 [3] CRAN (R 4.3.1)
##  R6            2.5.1   2021-08-19 [1] CRAN (R 4.3.3)
##  Rcpp          1.0.11  2023-07-06 [1] CRAN (R 4.3.2)
##  remotes       2.4.2.1 2023-07-18 [1] CRAN (R 4.3.2)
##  rlang         1.1.4   2024-06-04 [1] CRAN (R 4.3.3)
##  rmarkdown     2.28    2024-08-17 [1] CRAN (R 4.3.3)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.9   2024-03-15 [1] CRAN (R 4.3.3)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.3.2)
##  shiny         1.7.5.1 2023-10-14 [1] CRAN (R 4.3.2)
##  stringi       1.8.4   2024-05-06 [1] CRAN (R 4.3.3)
##  stringr       1.5.1   2023-11-14 [1] CRAN (R 4.3.3)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.3.2)
##  usethis       3.0.0   2024-07-29 [1] CRAN (R 4.3.3)
##  vctrs         0.6.5   2023-12-01 [1] CRAN (R 4.3.3)
##  xfun          0.47    2024-08-17 [1] CRAN (R 4.3.3)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.3.2)
##  yaml          2.3.10  2024-07-26 [1] CRAN (R 4.3.3)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>In-Place Modifications</title>
      <link>https://jcarroll.com.au/2024/09/25/in-place-modifications/</link>
      <pubDate>Wed, 25 Sep 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/09/25/in-place-modifications/</guid>
      <description>&lt;p&gt;In this post I explore some differences between R, python, julia, and APL in
terms of mutability, and try to make something that probably shouldn’t exist.&lt;/p&gt;
&lt;p&gt;I watched &lt;a href=&#34;https://youtu.be/O9AsxoQzNdI&#34;&gt;this code_report&lt;/a&gt; video which describes
a &lt;a href=&#34;https://leetcode.com/problems/final-array-state-after-k-multiplication-operations-i/description/&#34;&gt;leetcode problem&lt;/a&gt;;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You are given an integer array &lt;code&gt;nums&lt;/code&gt;, an integer &lt;code&gt;k&lt;/code&gt;, and an integer &lt;code&gt;multiplier&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You need to perform &lt;code&gt;k&lt;/code&gt; operations on &lt;code&gt;nums&lt;/code&gt;. In each operation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Find the minimum value &lt;code&gt;x&lt;/code&gt; in &lt;code&gt;nums&lt;/code&gt;. If there are multiple occurrences of the minimum value, select the one that appears first.&lt;/li&gt;
&lt;li&gt;Replace the selected minimum value &lt;code&gt;x&lt;/code&gt; with &lt;code&gt;x * multiplier&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Return an integer array denoting the final state of nums after performing all &lt;code&gt;k&lt;/code&gt; operations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Conor’s python solution in the video was&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;def getFinalState(nums, k, m): 
  for _ in range(k): 
    i = nums.index(min(nums)) 
    nums[i] *= m
  return nums

x = [2, 1, 3, 5, 6]
k = 5
mult = 2

getFinalState(x, k, mult)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [8, 4, 6, 5, 6]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and, as always, I wanted to see how I’d do that in R. I came up with this&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;getFinalState = function(nums, k, m) {
  for (i in 1:k) {
    m &amp;lt;- which.min(nums)[1]
    nums[m] &amp;lt;- mult * nums[m]
  }
  nums
}

x &amp;lt;- c(2, 1, 3, 5, 6)
k &amp;lt;- 5
mult &amp;lt;- 2

getFinalState(x, k, mult)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 8 4 6 5 6&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s worth noting that I can’t use a &lt;code&gt;map&lt;/code&gt; in this function because iterations
are dependent; the minimum value at any iteration depends on the previous
values.&lt;/p&gt;
&lt;p&gt;I also had a chance to discuss this solution with some APL’ers at a meetup and
a J solution was presented, but I don’t think I wrote it down.&lt;/p&gt;
&lt;p&gt;My solution is nearly word-for-word the same as the python solution with a
couple of notable exceptions arising from the difference between the two
languages:&lt;/p&gt;
&lt;p&gt;First, R has &lt;code&gt;which.min()&lt;/code&gt; as a built-in rather than needing to query the index
of the minimum value (and two references to &lt;code&gt;nums&lt;/code&gt;). Also, R has no compound
assignment like &lt;code&gt;x *= 2&lt;/code&gt; which modifies in-place - the closest thing I can think
of is the &lt;code&gt;%&amp;lt;&amp;gt;%&lt;/code&gt; operator in {magrittr} (not re-exported in {dplyr} because this
behaviour is considered bad practice in R, despite not really being “in-place”)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(magrittr)

m &amp;lt;- data.frame(x = 1:6, y = letters[1:6])
m&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   x y
## 1 1 a
## 2 2 b
## 3 3 c
## 4 4 d
## 5 5 e
## 6 6 f&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m %&amp;lt;&amp;gt;% head(2)
m&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   x y
## 1 1 a
## 2 2 b&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;although I can certainly see the case for it - this operator avoids repeating
the variable being used and assigned, because the alternative using the
traditional pipe is&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m &amp;lt;- data.frame(x = 1:6, y = letters[1:6])
m&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   x y
## 1 1 a
## 2 2 b
## 3 3 c
## 4 4 d
## 5 5 e
## 6 6 f&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m &amp;lt;- m %&amp;gt;% head(2)
m&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   x y
## 1 1 a
## 2 2 b&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One could argue that writing out even a longer variable name twice still makes
it clear that shadowing is taking place; the value is being overwritten with
a new value, but it does feel a little frustrating to have to type it out twice&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;important_variable &amp;lt;- important_variable * 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Back to my R solution, the indexing at a specific set of values got me thinking
that it would be clean if we could pass a &lt;em&gt;function&lt;/em&gt; to &lt;code&gt;[&lt;/code&gt; so that we could
write&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nums[which.min] &amp;lt;- value&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(maybe not so much for this example where &lt;code&gt;m&lt;/code&gt; is used twice, but it piqued my
interest)&lt;/p&gt;
&lt;p&gt;Let’s say I want to set all the even values of a vector to some other value.
That’s easy enough to do&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x[x %% 2 == 0] &amp;lt;- 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but I don’t love that it requires two references to &lt;code&gt;x&lt;/code&gt;, which may (should?) be
a much longer name&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;important_variable[important_variable %% 2 == 0] &amp;lt;- 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I want something like &lt;code&gt;x[f] &amp;lt;- y&lt;/code&gt; to set the values of &lt;code&gt;x&lt;/code&gt; where &lt;code&gt;f(x)&lt;/code&gt; is
&lt;code&gt;TRUE&lt;/code&gt; to &lt;code&gt;y&lt;/code&gt;. This seemed like it might be possible, maybe with a &lt;code&gt;function&lt;/code&gt;
method to &lt;code&gt;[&amp;lt;-&lt;/code&gt;, but &lt;code&gt;[&amp;lt;-&lt;/code&gt; dispatches on the class of &lt;code&gt;x&lt;/code&gt;, not what’s inside
&lt;code&gt;[&lt;/code&gt;, so no dice. In theory (which will &lt;em&gt;never&lt;/em&gt; happen) the built-in &lt;code&gt;[&amp;lt;-&lt;/code&gt; could
have some branch logic for dealing with a function passed as the indices to be
modified, but I’m not about to go rebuilding R from source myself just to play
with that idea.&lt;/p&gt;
&lt;p&gt;Nonetheless, if I define some functions that do accomplish this&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_even &amp;lt;- function(z) z %% 2 == 0

set_if &amp;lt;- function(x, f, value) {
  x[f(x)] &amp;lt;- value
  x
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then I can try this out on a vector&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- 1:10
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1]  1  2  3  4  5  6  7  8  9 10&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;set_if(a, is_even, 0)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] 1 0 3 0 5 0 7 0 9 0&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a # unchanged&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1]  1  2  3  4  5  6  7  8  9 10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works, but I’m back to having to write &lt;code&gt;a &amp;lt;- do_stuff(a)&lt;/code&gt; because &lt;code&gt;a&lt;/code&gt; isn’t
actually modified by this function.&lt;/p&gt;
&lt;p&gt;Ideally, my function would operate the same as this does&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- 1:10
a[is_even(a)] &amp;lt;- 0
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] 1 0 3 0 5 0 7 0 9 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which &lt;em&gt;does&lt;/em&gt; modify &lt;code&gt;a&lt;/code&gt; in-place; R is not entirely pure, and does occasionally
allow what looks like direct mutation, though under the hood, it’s not - a new
object is actually created&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# not using a range e.g. 1:n because that&amp;#39;s internally 
# a &amp;quot;compact&amp;quot; representation
a &amp;lt;- c(2, 3, 4)
.Internal(inspect(a))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## @5a784d8f2d48 14 REALSXP g0c3 [REF(2)] (len=3, tl=0) 2,3,4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a[2] &amp;lt;- 9
.Internal(inspect(a))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## @5a784d91f018 14 REALSXP g0c3 [REF(1)] (len=3, tl=0) 2,9,4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the memory address has changed.&lt;/p&gt;
&lt;p&gt;If I was working with a language which did support (enable?) modify-in-place
then that might look like&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;def is_even(x):
   return x % 2 == 0

def set_if(x, f, value):
     for i in range(len(x)):
         if f(x[i]):
             x[i] = value

a = list(range(10))
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;set_if(a, is_even, 0)
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [0, 1, 0, 3, 0, 5, 0, 7, 0, 9]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, that’s not always a great thing. In such a language with mutable structures
(e.g. lists) we can do maddening things like this&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;x = [3, 4, 5]
y = x
y is x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## True&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;y[1] = 9
x # still &amp;#39;bound&amp;#39; to y&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [3, 9, 5]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;is&lt;/code&gt; means “are these two things identical in the sense of referring to
the same block of memory”, noting that literals (e.g. single numbers) are
referenced that way, but tuples aren’t&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;abc = (11, 99)
xyz = (11, 99)
abc is xyz&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## False&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;abc == xyz&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## True&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The big question is can I hack together some solution that &lt;em&gt;does&lt;/em&gt; work in-place
in R? Yeah, with some ill-advised calls&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;set_if &amp;lt;- function(x, f, value) {
  # can&amp;#39;t use &amp;lt;&amp;lt;- because the value passed in as the x argument isn&amp;#39;t 
  # necessarily named &amp;#39;x&amp;#39; in the parent scope
  .x &amp;lt;- x
  .x[f(.x)] &amp;lt;- value
  e &amp;lt;- parent.env(environment())
  assign(deparse(substitute(x)), .x, pos = e)
  invisible(.x)
}


a &amp;lt;- 1:10
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1]  1  2  3  4  5  6  7  8  9 10&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;set_if(a, is_even, 0)
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] 1 0 3 0 5 0 7 0 9 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As I note in the comment there, I can’t use the super-assignment arrow &lt;code&gt;&amp;lt;&amp;lt;-&lt;/code&gt;
inside this function because I don’t know the name of the variable I’m updating;
it needs to be deparsed from the incoming argument.&lt;/p&gt;
&lt;p&gt;This means that it works regardless of the name of the variable being modified&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;b &amp;lt;- 10:20
b&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] 10 11 12 13 14 15 16 17 18 19 20&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;set_if(b, is_even, 0)
b&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1]  0 11  0 13  0 15  0 17  0 19  0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I tried to think of some other languages which might support this sort of in-place
&lt;code&gt;set_if(x, f, value)&lt;/code&gt; modification and (Dyalog) APL was worth a thought.&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;    ⍝ create a vector from 1 to 10
    x←⍳10
    x
1 2 3 4 5 6 7 8 9 10

    ⍝ the function {0=2|⍵} calculates a boolean vector with 
    ⍝ 1 where the value is even
    {0=2|⍵} x
0 1 0 1 0 1 0 1 0 1

    ⍝ the `@` operator takes a value (or function) on the left and 
    ⍝ a function (or boolean values) on the right and applies it to the 
    ⍝ other argument on the right
    0@{0=2|⍵} x 
1 0 3 0 5 0 7 0 9 0

    ⍝ alternatively a point-free function defined as the negation (`~`) of a 
    ⍝ binding (`∘`) of the value 2 to modulo (`|`); the negation is needed
    ⍝ otherwise this returns the result of the modulo, not where it is 0
    0@(~2∘|)⍳10
1 0 3 0 5 0 7 0 9 0

    ⍝ x is, however, unchanged as APL is typically immutable
    x
1 2 3 4 5 6 7 8 9 10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So there’s no way to do the in-place modification. it is nice, though, that
&lt;code&gt;0@(~2∘|)x&lt;/code&gt; only refers to &lt;code&gt;x&lt;/code&gt; once.&lt;/p&gt;
&lt;p&gt;Julia makes a nice distinction between functions which mutate arguments and
those which don’t; (by convention) the former are named ending with an
exclamation mark, e.g.&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;vec = collect(1:5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 5-element Vector{Int64}:
##  1
##  2
##  3
##  4
##  5&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;# non-mutating
reverse(vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 5-element Vector{Int64}:
##  5
##  4
##  3
##  2
##  1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;vec&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 5-element Vector{Int64}:
##  1
##  2
##  3
##  4
##  5&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;# mutating
reverse!(vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 5-element Vector{Int64}:
##  5
##  4
##  3
##  2
##  1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;vec&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 5-element Vector{Int64}:
##  5
##  4
##  3
##  2
##  1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In julia, the &lt;code&gt;iseven()&lt;/code&gt; function is already built-in, but vectorisation is
explicit via a broadcast operator &lt;code&gt;.&lt;/code&gt; and the setting of even values to 0
looks like&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;x = collect(1:10);
x[iseven.(x)] .= 0;
x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 10-element Vector{Int64}:
##  1
##  0
##  3
##  0
##  5
##  0
##  7
##  0
##  9
##  0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which looks very much like the R version with some dots where scalar functions
are vectorised. If I don’t use the last &lt;code&gt;.&lt;/code&gt; to perform vectorised assignment,
the error tells me that the failure involved the &lt;code&gt;setindex!&lt;/code&gt; function which does
sound like what I want, but this doesn’t work&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;setindex!(x, 0, iseven.(x))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;because it’s trying to assign the value 0 multiple times and I only provided one
of them. Instead,&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;x = collect(1:10);
setindex!(x, zeros(Int8, 5), iseven.(x));
x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 10-element Vector{Int64}:
##  1
##  0
##  3
##  0
##  5
##  0
##  7
##  0
##  9
##  0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;does work, but I had to manually count how many 0 entries this requires, so the
&lt;code&gt;[&lt;/code&gt; approach seems cleaner. Either way, I’ve had to explicitly calculate
&lt;code&gt;iseven(x)&lt;/code&gt; and pass that result somewhere.&lt;/p&gt;
&lt;p&gt;Since Julia allows users to extend methods, I &lt;em&gt;could&lt;/em&gt; do that modification myself!&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;import Base.setindex! 
  
function setindex!(A::Vector{Int64}, v::Int64, f::Function) 
  A[f.(A)] .= v
end&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## setindex! (generic function with 240 methods)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;x = collect(1:10);
setindex!(x, 0, iseven);
x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 10-element Vector{Int64}:
##  1
##  0
##  3
##  0
##  5
##  0
##  7
##  0
##  9
##  0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which I could just as easily call &lt;code&gt;set_if!&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;set_if! = setindex!;
x = collect(1:10);
set_if!(x, 0, iseven);
x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 10-element Vector{Int64}:
##  1
##  0
##  3
##  0
##  5
##  0
##  7
##  0
##  9
##  0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nice! I do wonder if I can “hack” (ahem, extend) Julia’s &lt;code&gt;[&lt;/code&gt; to get my prized
&lt;code&gt;x[f] = 0&lt;/code&gt; solution but I doubt it’s worth it when the above does the right
thing.&lt;/p&gt;
&lt;p&gt;I don’t imagine I’ll package up my &lt;code&gt;set_if()&lt;/code&gt; anywhere, and I should probably
even avoid using it myself, but it’s been an interesting journey thinking about
this stuff. Maybe there’s a better way to do it? Maybe there’s a language which
better supports something like that? If you know, or you have comments or
suggestions, I can be found on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; or use the comment section below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt; After some inspiration from Doug Kelkhoff I did end up implementing
this as a real package: &lt;a href=&#34;https://github.com/jonocarroll/vec&#34;&gt;{vec}&lt;/a&gt; is intended
as a new vector class where we could implement new features. There are already
a couple of suggestions, and if you have something you wish R’s vectors supported,
then please add an Issue!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE2&lt;/strong&gt; I probably should have noted that the original motivation of updating
the minimum value from the code_report video &lt;em&gt;does&lt;/em&gt; indeed work with this new
package&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(vec)

nums &amp;lt;- as_vec(c(4, 5, 3, 6, 8))
nums[which.min] &amp;lt;- 99
nums&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]  4  5 99  6  8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and I’m very happy about that!&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.3 (2024-02-29)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2024-10-01
##  pandoc   3.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.19    2024-02-01 [1] CRAN (R 4.3.3)
##  bookdown      0.36    2023-10-16 [1] CRAN (R 4.3.2)
##  bslib         0.8.0   2024-07-29 [1] CRAN (R 4.3.3)
##  cachem        1.1.0   2024-05-16 [1] CRAN (R 4.3.3)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [1] CRAN (R 4.3.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.3.2)
##  digest        0.6.37  2024-08-19 [1] CRAN (R 4.3.3)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.24.0  2024-06-10 [1] CRAN (R 4.3.3)
##  fastmap       1.2.0   2024-05-15 [1] CRAN (R 4.3.3)
##  fs            1.6.4   2024-04-25 [1] CRAN (R 4.3.3)
##  glue          1.7.0   2024-01-09 [1] CRAN (R 4.3.3)
##  here          1.0.1   2020-12-13 [1] CRAN (R 4.3.2)
##  htmltools     0.5.8.1 2024-04-04 [1] CRAN (R 4.3.3)
##  htmlwidgets   1.6.2   2023-03-17 [1] CRAN (R 4.3.2)
##  httpuv        1.6.12  2023-10-23 [1] CRAN (R 4.3.2)
##  icecream      0.2.1   2023-09-27 [1] CRAN (R 4.3.2)
##  jquerylib     0.1.4   2021-04-26 [1] CRAN (R 4.3.3)
##  jsonlite      1.8.8   2023-12-04 [1] CRAN (R 4.3.3)
##  JuliaCall     0.17.5  2022-09-08 [1] CRAN (R 4.3.3)
##  knitr         1.48    2024-07-07 [1] CRAN (R 4.3.3)
##  later         1.3.1   2023-05-02 [1] CRAN (R 4.3.2)
##  lattice       0.22-5  2023-10-24 [4] CRAN (R 4.3.1)
##  lifecycle     1.0.4   2023-11-07 [1] CRAN (R 4.3.3)
##  magrittr    * 2.0.3   2022-03-30 [1] CRAN (R 4.3.3)
##  Matrix        1.6-5   2024-01-11 [4] CRAN (R 4.3.3)
##  memoise       2.0.1   2021-11-26 [1] CRAN (R 4.3.3)
##  mime          0.12    2021-09-28 [1] CRAN (R 4.3.3)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.3.2)
##  pkgbuild      1.4.2   2023-06-26 [1] CRAN (R 4.3.2)
##  pkgload       1.3.3   2023-09-22 [1] CRAN (R 4.3.2)
##  png           0.1-8   2022-11-29 [1] CRAN (R 4.3.2)
##  prettyunits   1.2.0   2023-09-24 [3] CRAN (R 4.3.1)
##  processx      3.8.3   2023-12-10 [3] CRAN (R 4.3.2)
##  profvis       0.3.8   2023-05-02 [1] CRAN (R 4.3.2)
##  promises      1.2.1   2023-08-10 [1] CRAN (R 4.3.2)
##  ps            1.7.6   2024-01-18 [3] CRAN (R 4.3.2)
##  purrr         1.0.2   2023-08-10 [3] CRAN (R 4.3.1)
##  R6            2.5.1   2021-08-19 [1] CRAN (R 4.3.3)
##  Rcpp          1.0.11  2023-07-06 [1] CRAN (R 4.3.2)
##  remotes       2.4.2.1 2023-07-18 [1] CRAN (R 4.3.2)
##  reticulate    1.34.0  2023-10-12 [1] CRAN (R 4.3.2)
##  rlang         1.1.4   2024-06-04 [1] CRAN (R 4.3.3)
##  rmarkdown     2.28    2024-08-17 [1] CRAN (R 4.3.3)
##  rprojroot     2.0.4   2023-11-05 [1] CRAN (R 4.3.2)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.9   2024-03-15 [1] CRAN (R 4.3.3)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.3.2)
##  shiny         1.7.5.1 2023-10-14 [1] CRAN (R 4.3.2)
##  stringi       1.8.4   2024-05-06 [1] CRAN (R 4.3.3)
##  stringr       1.5.1   2023-11-14 [1] CRAN (R 4.3.3)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.3.2)
##  usethis       3.0.0   2024-07-29 [1] CRAN (R 4.3.3)
##  vctrs         0.6.5   2023-12-01 [1] CRAN (R 4.3.3)
##  vec         * 0.1.0   2024-10-01 [1] local
##  xfun          0.47    2024-08-17 [1] CRAN (R 4.3.3)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.3.2)
##  yaml          2.3.10  2024-07-26 [1] CRAN (R 4.3.3)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ─ Python configuration ───────────────────────────────────────────────────────
##  python:         /home/jono/.virtualenvs/r-reticulate/bin/python
##  libpython:      /usr/lib/python3.10/config-3.10-x86_64-linux-gnu/libpython3.10.so
##  pythonhome:     /home/jono/.virtualenvs/r-reticulate:/home/jono/.virtualenvs/r-reticulate
##  version:        3.10.12 (main, Sep 11 2024, 15:47:36) [GCC 11.4.0]
##  numpy:           [NOT FOUND]
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Side by Side Comparison - Gleam vs R</title>
      <link>https://jcarroll.com.au/2024/09/05/side-by-side-comparison-gleam-vs-r/</link>
      <pubDate>Thu, 05 Sep 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/09/05/side-by-side-comparison-gleam-vs-r/</guid>
      <description>&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/supereffective.jpg&#34; width=&#34;600&#34; alt=&#34;Gleam vs R&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Gleam vs R&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I thoroughly dislike ‘hot takes’ comparing programming languages based solely on
a “feel” or differential familiarity (“I know this one better therefore it &lt;em&gt;is&lt;/em&gt;
better) so when I came across a blog post detailing a small learning project
written in Gleam I wanted to understand what advantages and disadvantages that
language brings to the problem. This post details a side-by-side comparison after
rewriting the project in R with a goal of better understanding the approach on
both sides.&lt;/p&gt;
&lt;div id=&#34;what-is-gleam&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;What is Gleam?&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;https://gleam.run/images/lucy/lucy.svg&#34; width=&#34;100&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://gleam.run/&#34;&gt;Gleam&lt;/a&gt; is a relatively new language - first released in 2016
and reaching version 1.0 in March this year. It’s implemented in Rust, but
runs on &lt;a href=&#34;https://en.wikipedia.org/wiki/BEAM_(Erlang_virtual_machine)&#34;&gt;BEAM&lt;/a&gt;, Erlang’s
virtual machine. It’s garbage collected but compiles down to JavaScript, the combination
of which makes it fairly fast.&lt;/p&gt;
&lt;p&gt;It’s type-safe with strict immutability and embraces a functional paradigm -
no loops at all, just recursion. It’s pretty straightforward to learn in a day
or so if you’re already familiar with programming and there’s a nice online
&lt;a href=&#34;https://tour.gleam.run/&#34;&gt;language tour&lt;/a&gt; with a built-in playground. In terms of
a package ecosystem the &lt;a href=&#34;https://packages.gleam.run/&#34;&gt;repository&lt;/a&gt; has just under
600 packages but because it can also run Elixir packages, it actually has a lot
of packages available - hex.pm has around &lt;a href=&#34;https://hex.pm/packages&#34;&gt;16k packages&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A simple ’Hello, World!” looks like this&lt;/p&gt;
&lt;pre class=&#34;gleam&#34;&gt;&lt;code&gt;import gleam/io

pub fn main() {
  io.println(&amp;quot;hello, friend!&amp;quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;hello, friend!&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but outside of the playground you need to go through a compile step to actually
run the code. Like Rust, it helps you get to the end goal, with no null values,
no exceptions, and clear error messages.&lt;/p&gt;
&lt;p&gt;It seems to be used a lot for web development, but I’m less familiar with the
common use-cases.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;what-is-r&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;What is R?&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;https://www.r-project.org/Rlogo.png&#34; width=&#34;100&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.r-project.org/&#34;&gt;R&lt;/a&gt; has been around longer - first released in 1993
and currently at version 4.4.1. It’s implemented in C with some self-sufficient
code in R and leaning on numerical libraries in Fortran. It’s also garbage collected
but it’s an interpreted language, so it runs a Read-Evaluate-Print-Loop (REPL) in
which you can enter expressions and get their results back without having to compile
the entire ‘program’. For this reason, it’s frequently used interactively in the
lisp sense where you essentially have a conversation with the computer about
some data, asking questions and getting responses, until you build up the full
‘script’ of what you want to achieve.&lt;/p&gt;
&lt;p&gt;It’s dynamically typed with no type-safety guarantees - a function returns what
it returns. It supports a variety of paradigms, both functional and object-oriented,
and developers can choose to float between these freely even in a single script.&lt;/p&gt;
&lt;p&gt;The canonical package repository &lt;a href=&#34;https://cran.r-project.org/&#34;&gt;CRAN&lt;/a&gt; currently
hosts over 21k packages but users can also download package directly from other
repositories such as &lt;a href=&#34;https://r-universe.dev/&#34;&gt;r-universe&lt;/a&gt; which hosts nearly
26k (including copies of all of the CRAN packages).&lt;/p&gt;
&lt;p&gt;There’s a lot less ceremony involved in an interpreted language, so a
‘Hello, World!’ is as straightforward as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;Hello, World!&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;Hello, World!&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;since evaluating an object (a variable or value) prints it by default.&lt;/p&gt;
&lt;p&gt;R started life in the statistics department of the University of Auckland and
as such has excellent numerical support for statistics and graphing. It’s often
referred to as “a programming language for statistical computing” but I hate the
connotation that it’s &lt;em&gt;only&lt;/em&gt; a “statistical language” - it’s sufficiently general
purpose that you can &lt;a href=&#34;https://github.com/matt-dray/splendid-r-games&#34;&gt;build games&lt;/a&gt;,
&lt;a href=&#34;https://nrennie.rbind.io/projects/generative-art/&#34;&gt;make generative art&lt;/a&gt;,
&lt;a href=&#34;https://flujoo.github.io/gm/&#34;&gt;write and play music&lt;/a&gt;, or
&lt;a href=&#34;https://shiny.posit.co/r/gallery/&#34;&gt;build a full webpage&lt;/a&gt;. I’ve struggled to find
things it &lt;em&gt;can’t&lt;/em&gt; do (at all - there’s plenty of things at which it’s far from the
best choice).&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;the-gleam-project---a-web-scraper&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;The Gleam project - a web scraper&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&#34;https://pliutau.com/my-first-experience-with-gleam-lang/&#34;&gt;post I read&lt;/a&gt; details
a ‘first experience’ with the language and I fully agree with the author that it’s
useful to learn by doing - you learn with your hands, not your eyes.&lt;/p&gt;
&lt;p&gt;It describes using Gleam to write a program which takes in a configuration containing
some URLs to query at given intervals, and optionally a string to search for in
the content of that URL. The resulting status code and whether or not the text
was matched are stored in a database, and the program is run concurrently; the
three sites (in this case) are queried in parallel jobs at their respective
intervals.&lt;/p&gt;
&lt;p&gt;It’s a fine post - perhaps a little light on the explanation of how the code came
about and how it all ties together, but the ideas are mostly there. My post isn’t
about critiquing the code or the post, but rather seeing how a similar thing might
look in R.&lt;/p&gt;
&lt;p&gt;I had a look at the code in the post (which didn’t seem to be all of it) and the
rest of the code on GitHub and figured this seemed like a small enough project
that I could understand all of it and try to consider the advantages and
disadvantages of using Gleam for this task. As with pretty much any small project
I can imagine building it in R (for better or worse) and I wanted to really dig
into what makes a project a good or bad fit for R.&lt;/p&gt;
&lt;p&gt;Sure, R can be “slow” compared to compiled languages, but that depends on what
you’re doing - if it isn’t performance-critical (“oh, no, it takes 0.3s to run
once a day vs 0.3ms - what ever will you do with all that time you saved?”) then
I consider the time one spends writing and later reading the code itself to
factor into the ‘speed’.&lt;/p&gt;
&lt;p&gt;There probably aren’t many webservers built in R, but R has plenty of web-scraping
support. So, what does a strongly typed language like Gleam offer that R doesn’t?&lt;/p&gt;
&lt;p&gt;I updated my Gleam installation (I’d used it for some
&lt;a href=&#34;https://exercism.org/tracks/gleam&#34;&gt;Exercism exercises&lt;/a&gt; but it was considerably
out of date now) and ran the project - it compiled and ran just fine.&lt;/p&gt;
&lt;p&gt;The post starts out by defining a configuration in yaml&lt;/p&gt;
&lt;pre class=&#34;yaml&#34;&gt;&lt;code&gt;websites:
  - url: https://packagemain.tech
    interval: 10
  - url: https://pliutau.com
    interval: 15
  - url: https://news.ycombinator.com
    interval: 30
    pattern: gleam&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and I’m already confused - my guess is that yaml is a widely used configuration
filetype and offers ‘naming’ of the different nested components, but having type
safety means writing a parser for that which does the validation. The post
&lt;em&gt;does&lt;/em&gt; detail that and defines a &lt;code&gt;Config&lt;/code&gt; type consisting of a list of &lt;code&gt;Website&lt;/code&gt;
types. This seems to be a first point of difference:&lt;/p&gt;
&lt;div class=&#34;notice&#34;&gt;
    &lt;p class=&#34;notice-title&#34;&gt;
        &lt;span class=&#34;icon-notice baseline&#34;&gt;
            📝
        &lt;/span&gt;
        Note 
    &lt;/p&gt;
    &lt;p&gt; Static typing means that validation is enforced.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;In R I might use a CSV to store such a configuration with one line per site. Now,
CSV doesn’t guarantee any type safety either, but once I read it into a &lt;code&gt;data.frame&lt;/code&gt;
the columns &lt;em&gt;will&lt;/em&gt; have some types. They might not be what I naively expect, but
if they look like numbers they’ll probably be numbers.&lt;/p&gt;
&lt;p&gt;It seems like that would be a better shape for this data, but I suppose if the
configuration doesn’t ‘rectangle’ very well, CSV might be less appropriate. I
think this is where my confusion arose - but how else would you get data into the
types of the program apart from parsing and validation?&lt;/p&gt;
&lt;p&gt;If I wanted to ingest such a configuration I’d probably do some defensive coding
and assert that the columns are what I think they should be, at least as far as
R’s atomic type system goes.&lt;/p&gt;
&lt;p&gt;Something like&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;config &amp;lt;- function(file) {
  conf &amp;lt;- read.csv(file, header = TRUE)
  expected_cols &amp;lt;- c(&amp;quot;url&amp;quot;, &amp;quot;interval&amp;quot;, &amp;quot;pattern&amp;quot;),
  stopifnot(
    &amp;quot;CSV in unexpected format&amp;quot; = colnames(conf) == expected_cols 
    &amp;quot;url should be character&amp;quot; = is.character(conf$url),
    &amp;quot;interval should be numeric&amp;quot; = is.numeric(conf$interval),
    &amp;quot;pattern should be character&amp;quot; = is.character(conf$pattern)
  )
  conf
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s perhaps an unfortunate ratio of assertions to implementation, but it
gets the job done.&lt;/p&gt;
&lt;p&gt;One &lt;em&gt;could&lt;/em&gt; go even further in either language and validate that the URL appears
to be valid and that the interval is greater than 0, but I don’t have a good sense
for when one should do that.&lt;/p&gt;
&lt;p&gt;This does raise an interesting point, too - in R I’m very familiar with using
&lt;code&gt;data.frame&lt;/code&gt; as a structure, but that’s loosely constrained; it’s a list of
vectors of the same length, but those vectors could be anything - if we extend
the idea to {tibble}s then it we can even have a list containing a list
containing vectors with varying lengths!&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;tibble::tibble(
  id = 1:3, 
  items = list(
    c(&amp;quot;apples&amp;quot;), 
    c(&amp;quot;beans&amp;quot;, &amp;quot;carrots&amp;quot;), 
    c(&amp;quot;dates&amp;quot;)
  )
)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 3 × 2
##      id items    
##   &amp;lt;int&amp;gt; &amp;lt;list&amp;gt;   
## 1     1 &amp;lt;chr [1]&amp;gt;
## 2     2 &amp;lt;chr [2]&amp;gt;
## 3     3 &amp;lt;chr [1]&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Making that strictly typed would mean defining something like&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cart(List(Vec(Int), List(Vec(String))))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which can go further and define each list of items&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Items(Vec(String))
Cart(List(Vec(Int), List(Items)))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;https://fediscience.org/@mario_angst_sci/113072586583881511&#34;&gt;Mario Angst on Mastodon&lt;/a&gt;
was trying to work with more or less this exact problem in the new
&lt;a href=&#34;https://rconsortium.github.io/S7/articles/S7.html&#34;&gt;S7 OOP system&lt;/a&gt; which really
demonstrated how complex that becomes compared to what is typically done in R, and
part of the motivation for writing this post is to better understand where that
prevents bugs or issues.&lt;/p&gt;
&lt;p&gt;In Mario’s case it was validating that columns have a particular structure. In the
case of this project it is protecting against an invalid configuration. If I try
to break the configuration by making one of the intervals a string&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  - url: https://packagemain.tech
    interval: &amp;quot;10&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and build the project… it works just fine. So what’s going on? The config parser
where the interval is read has&lt;/p&gt;
&lt;pre class=&#34;gleam&#34;&gt;&lt;code&gt;int.parse(val_str)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so it ‘recovers’ from the case where a string is used. Should it just fail there?
Or is combining type safety and a ‘try to fix’ approach the right way? Isn’t that
defensive programming?&lt;/p&gt;
&lt;p&gt;If I use a number as the URL&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;websites:
  - url: 1
    interval: 10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;it does indeed break properly&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ gleam run         
   Compiled in 0.07s
    Running websites_checker.main
exception error: #{function =&amp;gt; &amp;lt;&amp;lt;&amp;quot;main&amp;quot;&amp;gt;&amp;gt;,line =&amp;gt; 32,
                   message =&amp;gt;
                       &amp;lt;&amp;lt;&amp;quot;Failed to load config: Invalid config file format&amp;quot;&amp;gt;&amp;gt;,
                   module =&amp;gt; &amp;lt;&amp;lt;&amp;quot;websites_checker&amp;quot;&amp;gt;&amp;gt;,gleam_error =&amp;gt; panic}
  in function  websites_checker:main/0 &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, that’s good.&lt;/p&gt;
&lt;p&gt;The next piece - querying the URL - also left me a bit lost. I could see that the
post details saving the &lt;code&gt;CrawlResult&lt;/code&gt; from the crawler, and I could see a call to
&lt;code&gt;crawl_url&lt;/code&gt;, but it didn’t show the actual crawler. The
&lt;a href=&#34;https://github.com/plutov/websites_checker/blob/aa322f0e4c59d4d5fb944ad01877fed7df9150fa/src/crawler.gleam#L19&#34;&gt;full code&lt;/a&gt;
(updated since the post was written, I believe) does have that and seeing that
resolved that confusion.&lt;/p&gt;
&lt;p&gt;The actual querying and parsing was all done here&lt;/p&gt;
&lt;pre class=&#34;gleam&#34;&gt;&lt;code&gt;let assert Ok(req) = request.to(url)

  case hackney.send(req) {
    Ok(response) -&amp;gt; {
      let pattern_matched =
        pattern != &amp;quot;&amp;quot; &amp;amp;&amp;amp; response.body |&amp;gt; string.contains(pattern)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and I wanted to understand this part - it seems to use the &lt;code&gt;gleam/http/request&lt;/code&gt;
package to create the &lt;a href=&#34;https://hexdocs.pm/gleam_http/gleam/http/request.html#Request&#34;&gt;&lt;code&gt;Request&lt;/code&gt;&lt;/a&gt;
object, and the &lt;code&gt;gleam/hackney&lt;/code&gt; package to send the request, producing a
&lt;a href=&#34;https://hexdocs.pm/gleam_http/gleam/http/response.html#Response&#34;&gt;&lt;code&gt;Response&lt;/code&gt;&lt;/a&gt;
object.&lt;/p&gt;
&lt;p&gt;This was my next source of confusion - what was the ‘type’ of the body of the
response? The body field is used in the pattern matching with &lt;code&gt;string.contains(pattern)&lt;/code&gt;
but is that doing a search on JSON? HTML? XML? I suspect this was my unfamiliarity
with strongly typed languages showing - the documentation actually does say&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The body of the request is parameterised. The HTTP server or client you are
using will have a particular set of types it supports for the body.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;so it’s whatever the server sends. This seems… un-type-safe?&lt;/p&gt;
&lt;div class=&#34;notice&#34;&gt;
    &lt;p class=&#34;notice-title&#34;&gt;
        &lt;span class=&#34;icon-notice baseline&#34;&gt;
            📝
        &lt;/span&gt;
        Note 
    &lt;/p&gt;
    &lt;p&gt;The outside world is messy.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;What I really wanted to do was just fetch the data with that code and &lt;em&gt;see&lt;/em&gt; what
the result looks like, but that’s not how compiled programs work.&lt;/p&gt;
&lt;p&gt;My guess is that there are two options; write a different ‘main()’ entrypoint
that calls just this bit of code and outputs the result, or some sort of debug
statement during runtime (like &lt;a href=&#34;https://jcarroll.com.au/2023/11/07/print-debugging-now-with-icecream/&#34;&gt;this&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I recall seeing someone make the statement along the lines of “if you need a REPL,
it just shows you’re not familiar enough with the language” and I think they
missed the point that it’s not about seeing what some function &lt;em&gt;should do&lt;/em&gt;, it’s
about what does it do to &lt;em&gt;this data&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;I’ll get to how I did find out, but the quick answer is that the server responds
with HTML, so the matching is being performed on one long string. Maybe not ideal
- I’d expect to at least limit the search to the ‘body’ of the page, but it’s a
toy project so whatever.&lt;/p&gt;
&lt;p&gt;Once the site has been scraped, the results are stored in a database. Writing to
SQLite happens via a manually written query, but the libraries appear to handle
the rest of that interaction quite nicely&lt;/p&gt;
&lt;pre class=&#34;gleam&#34;&gt;&lt;code&gt;sqlight.query(
      &amp;quot;insert into websites (started_at, completed_at, status, pattern_matched, url) values (?, ?, ?, ?, ?)&amp;quot;,
      on: db,
      with: [
        sqlight.int(result.started_at),
        sqlight.int(result.completed_at),
        sqlight.int(result.status_code),
        sqlight.int(result.pattern_matched |&amp;gt; bool.to_int),
        sqlight.text(result.url),
      ],
      expecting: mock_decoder,
    )&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last critical piece was looping over the sites defined in the configuration.
Gleam doesn’t have loops, but it does have a &lt;code&gt;list.each()&lt;/code&gt; that can essentially
do a loop. The problem is that this isn’t just one loop over the sites, it’s also
a loop to repeat the scrape at a given interval.&lt;/p&gt;
&lt;p&gt;Part of the appeal of Gleam is concurrency, so ideally we’d do the scraping for
each site independently at the same time. That’s achieved by writing a recursive
function to repeat itself after waiting for some time&lt;/p&gt;
&lt;pre class=&#34;gleam&#34;&gt;&lt;code&gt;fn process_website_recursively(
  db_conn: sqlight.Connection,
  website: config.Website,
) {
  [...]
  process.sleep(website.interval * 1000)
  process_website_recursively(db_conn, website)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is then called in the loop over the sites&lt;/p&gt;
&lt;pre class=&#34;gleam&#34;&gt;&lt;code&gt;list.each(c.websites, fn(w) {
  process.start(fn() { process_website_recursively(db_conn, w) }, True)
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Gleam then kicks off a process for each site, running on its own scheduled
intervals, and performs the operations.&lt;/p&gt;
&lt;p&gt;After letting it run for a bit I opened up the generated SQLite database and
confirmed that it had indeed captured the relevant information for the three
configured sites. Cool!&lt;/p&gt;
&lt;p&gt;Now, how would I do it in R?&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;reproducing-the-project-in-r&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Reproducing the project in R&lt;/h3&gt;
&lt;p&gt;The very first thing I do in an R project is to start interacting with the data
itself; maybe plotting it if I already have it, but if I don’t, then getting a
sample of it to play around with is a first step.&lt;/p&gt;
&lt;p&gt;Since R has a REPL, I can evaluate expressions straight away without building a
‘program’ around them. I do write my expressions in an actual file in RStudio, and
can execute them individually in a REPL with a key combo, so I get the best of
both worlds of recording what I’m doing and having the results immediately at hand.&lt;/p&gt;
&lt;p&gt;With a new &lt;code&gt;.R&lt;/code&gt; file open I can type out and run&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;url &amp;lt;- &amp;quot;https://jcarroll.com.au&amp;quot;

resp &amp;lt;- httr2::request(url) |&amp;gt; 
  httr2::req_perform()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This uses the {httr2} library to build a request object and perform the request.&lt;/p&gt;
&lt;p&gt;I can inspect the &lt;code&gt;resp&lt;/code&gt; object to see what sort of thing I’m getting&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;resp&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## &amp;lt;httr2_response&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## GET https://jcarroll.com.au/&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Status: 200 OK&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Content-Type: text/html&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Body: In memory (32012 bytes)&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;notice&#34;&gt;
    &lt;p class=&#34;notice-title&#34;&gt;
        &lt;span class=&#34;icon-notice baseline&#34;&gt;
            📝
        &lt;/span&gt;
        Note 
    &lt;/p&gt;
    &lt;p&gt; R &lt;em&gt;does&lt;/em&gt; have some properly classed objects, but they&#39;re less common.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Okay, it’s &lt;code&gt;text/html&lt;/code&gt; - that means I can extract the contents with something like
&lt;code&gt;httr2::resp_body_html()&lt;/code&gt; or, if I just want one big string…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;content &amp;lt;- httr2::resp_body_string(resp)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looking at the first chunk of characters, and cleaning it up a little for
presenting here, I see&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cat(gsub(&amp;quot;[ ]*\\\n\\\n&amp;quot;, &amp;quot;&amp;quot;, substr(content, 1, 521)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;lt;!DOCTYPE html&amp;gt;
## &amp;lt;html lang=&amp;quot;en&amp;quot; itemscope itemtype=&amp;quot;http://schema.org/WebPage&amp;quot;&amp;gt;
##   &amp;lt;head&amp;gt;
##   &amp;lt;meta charset=&amp;quot;utf-8&amp;quot; /&amp;gt;
##   &amp;lt;meta http-equiv=&amp;quot;X-UA-Compatible&amp;quot; content=&amp;quot;IE=edge&amp;quot;&amp;gt;
##   &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;
##   
##   &amp;lt;meta name=&amp;quot;author&amp;quot; content=&amp;quot;Jonathan Carroll&amp;quot;/&amp;gt;&amp;lt;script type=&amp;quot;application/ld+json&amp;quot;&amp;gt;
## {
##     &amp;quot;@context&amp;quot;: &amp;quot;http://schema.org&amp;quot;,
##     &amp;quot;@type&amp;quot;: &amp;quot;WebSite&amp;quot;,
##     &amp;quot;name&amp;quot;: &amp;quot;Irregularly Scheduled Programming&amp;quot;,
##     
##     &amp;quot;url&amp;quot;: &amp;quot;https:\/\/jcarroll.com.au&amp;quot;
## }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great - that’s the HTML response for this blog.&lt;/p&gt;
&lt;p&gt;I don’t know how anyone codes without being able to just crack open a piece of
data and see what it looks like inside.&lt;/p&gt;
&lt;p&gt;I’ll want to store the config, and as I noted above I could store that in a CSV.
For now I’ll just load a &lt;code&gt;data.frame&lt;/code&gt; containing that data&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sites &amp;lt;- data.frame(url = c(&amp;quot;https://packagemain.tech&amp;quot;,
                            &amp;quot;https://pliutau.com&amp;quot;,
                            &amp;quot;https://news.ycombinator.com&amp;quot;),
                    interval = c(10, 15, 30),
                    pattern = c(&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;tech&amp;quot;)
)
sites&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##                            url interval pattern
## 1     https://packagemain.tech       10        
## 2          https://pliutau.com       15        
## 3 https://news.ycombinator.com       30    tech&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(I changed the pattern to search to one that almost certainly appears in that
last URL’s content)&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;data.frame&lt;/code&gt; constructor sort of ensures that I have consistent ‘types’ in
the columns, since vectors must be homogenous.&lt;/p&gt;
&lt;p&gt;If I wanted to perform the crawl on one row of this data, I could write a function
that calculates the time, performs the query, calculates the time again, then
constructs a &lt;code&gt;data.frame&lt;/code&gt; with the relevant output&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;test_crawl &amp;lt;- function(url, interval, pattern = &amp;quot;&amp;quot;) {
  
  start_time &amp;lt;- format(Sys.time(), &amp;quot;%s&amp;quot;)
  
  resp &amp;lt;- httr2::request(url) |&amp;gt; 
    httr2::req_perform()
  
  end_time &amp;lt;- format(Sys.time(), &amp;quot;%s&amp;quot;)
  
  data.frame(
    start_time = start_time,
    end_time = end_time,
    status = httr2::resp_status(resp),
    pattern_matched = pattern != &amp;quot;&amp;quot; &amp;amp;&amp;amp; grepl(pattern, httr2::resp_body_string(resp)),
    url = url
  )
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A really useful tool for functional programming in R is {purrr} and it has a &lt;code&gt;pmap&lt;/code&gt;
function which ‘splats’ a list of values out to arguments in a &lt;code&gt;map&lt;/code&gt;, and that
comes in really handy here to take the columns from the rows of &lt;code&gt;sites&lt;/code&gt; and pass
them to the crawling function&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;purrr::pmap(sites[1, ], test_crawl)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [[1]]
##   start_time   end_time status pattern_matched                      url
## 1 1725513563 1725513563    200           FALSE https://packagemain.tech&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I could do the same for all of the rows, and since the results have the same shape,
I could ‘bind’ them together as rows of a new &lt;code&gt;data.frame&lt;/code&gt; with &lt;code&gt;pmap_df&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;purrr::pmap_df(sites, test_crawl)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   start_time   end_time status pattern_matched                          url
## 1 1725513563 1725513563    200           FALSE     https://packagemain.tech
## 2 1725513563 1725513564    200           FALSE          https://pliutau.com
## 3 1725513564 1725513565    200            TRUE https://news.ycombinator.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s all I need to get a preview of the data. The next step was to put that
data into a database. R has great support for this, too. If I define an empty
structure with the appropriate types for the data&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;websites &amp;lt;- data.frame(
  start_time = integer(),
  end_time = integer(),
  status = integer(),
  pattern_matched = logical(),
  url = character()
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can write that empty table to a new database&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;con &amp;lt;- DBI::dbConnect(RSQLite::SQLite(), &amp;quot;websites.sqlite&amp;quot;)
DBI::dbWriteTable(con, &amp;quot;websites&amp;quot;, websites)
DBI::dbDisconnect(con)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I need a way to perform the crawls on a schedule. If I expand the
single-site crawling function to optionally write to the database (possibly
defined by an environment variable)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;single_crawl &amp;lt;- function(url, 
                         pattern = &amp;quot;&amp;quot;, 
                         write = TRUE, 
                         db = Sys.getenv(&amp;quot;CRAWL_DB&amp;quot;)) {
  
  start_time &amp;lt;- format(Sys.time(), &amp;quot;%s&amp;quot;)
  resp &amp;lt;- httr2::request(url) |&amp;gt; 
    httr2::req_perform()
  end_time &amp;lt;- format(Sys.time(), &amp;quot;%s&amp;quot;)
  
  res &amp;lt;- data.frame(
    start_time = start_time,
    end_time = end_time,
    status = httr2::resp_status(resp),
    pattern_matched = pattern != &amp;quot;&amp;quot; &amp;amp;&amp;amp; grepl(pattern, httr2::resp_body_string(resp)),
    url = url
  )
  
  if (!write) {
    return(res)
  } 
  
  con &amp;lt;- DBI::dbConnect(RSQLite::SQLite(), db)
  DBI::dbWriteTable(con, &amp;quot;websites&amp;quot;, res, append = TRUE)
  DBI::dbDisconnect(con)
  
  invisible()
}&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;notice&#34;&gt;
    &lt;p class=&#34;notice-title&#34;&gt;
        &lt;span class=&#34;icon-notice baseline&#34;&gt;
            📝
        &lt;/span&gt;
        Note 
    &lt;/p&gt;
    &lt;p&gt; Being able to play around with whether the result is sent to a database 
    or just returned is only possible &lt;em&gt;without&lt;/em&gt; type safety.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I can also test that, but since writing to the database produces no output, I can
use the &lt;code&gt;walk&lt;/code&gt; variant instead of &lt;code&gt;map&lt;/code&gt;, which doesn’t return output&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;purrr::pwalk(sites, single_crawl, db = &amp;quot;websites.sqlite&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can wrap the individual crawling function with one that runs in a loop. This
version only runs 4 times for each site, but you could just as easily make it
an infinite loop that you need to kill.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;crawl &amp;lt;- function(url,
                  interval, 
                  pattern = &amp;quot;&amp;quot;, 
                  write = TRUE, 
                  db = Sys.getenv(&amp;quot;CRAWL_DB&amp;quot;)) {
  
  for (i in 1:4) {
    message(glue::glue(&amp;quot;Crawling {url} ({i})&amp;quot;))
    single_crawl(url = url, pattern = pattern, write = write, db = db)
    Sys.sleep(interval)
  }
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when I run this I should get the data inserted into a new database (that I’ve
also created ahead of time)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;purrr::pwalk(sites, crawl, db = &amp;quot;websites_seq.sqlite&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Does it work, though? Opening up the database I can see 12 entries. So far, so
good.&lt;/p&gt;
&lt;p&gt;Another reason that I like R is that not only can I do general computing like this,
but when it comes time to &lt;em&gt;analyse&lt;/em&gt; the data produced, R is also a great fit. I’m
not sure what tooling Gleam has for inspecting the data dropped into that database,
but I suspect the use-case is some other language.&lt;/p&gt;
&lt;p&gt;I can plot the data I’ve stored by connecting to the database with R and pulling
out the data. I offset the times relative to the very first one, then plot the
start and end times for each site scraped&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;con &amp;lt;- DBI::dbConnect(RSQLite::SQLite(), &amp;quot;websites_seq.sqlite&amp;quot;)

times &amp;lt;- tbl(con, &amp;quot;websites&amp;quot;) |&amp;gt; 
  collect() |&amp;gt; 
  mutate(start_s = start_time - start_time[1]) |&amp;gt; 
  mutate(end_s = end_time - start_time[1])

library(ggplot2)

ggplot(times) + 
  geom_point(aes(start_s, 1), col = &amp;quot;green&amp;quot;, size = 6) + 
  geom_point(aes(end_s, 1), col = &amp;quot;red&amp;quot;, size = 6) + 
  facet_wrap(~url, ncol = 1) + 
  theme_minimal() + 
  theme(axis.text.y = element_blank(), 
        axis.title.y = element_blank(),
        panel.grid.major.y = element_blank(),
        panel.grid.minor.y = element_blank()) +
  scale_x_continuous(breaks = seq(0, 200, 10))&lt;/code&gt;&lt;/pre&gt;
&lt;a href=&#34;images/crawl_timings.png&#34;&gt;
&lt;img src=&#34;images/crawl_timings_seq.png&#34; width=&#34;600&#34; /&gt;
&lt;/a&gt;
&lt;p class=&#34;caption&#34;&gt;
Timings for a sequential crawl; click to embiggen
&lt;/p&gt;
&lt;p&gt;As you can see, these are performed sequentially - 4 crawls of each site, one
site at a time.&lt;/p&gt;
&lt;p&gt;In order to also make this concurrent, all I need to do is swap out the &lt;code&gt;purrr::pwalk()&lt;/code&gt;
with a &lt;code&gt;furrr::future_pwalk()&lt;/code&gt; which wraps the {future} package&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(future)
plan(multisession)

furrr::future_pwalk(sites, crawl, db = &amp;quot;~/Projects/websites_par.sqlite&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using this database and producing the same plot I get&lt;/p&gt;
&lt;a href=&#34;images/crawl_timings.png&#34;&gt;
&lt;img src=&#34;images/crawl_timings.png&#34; width=&#34;600&#34; /&gt;
&lt;/a&gt;
&lt;p class=&#34;caption&#34;&gt;
Timings for parallel crawls; click to embiggen
&lt;/p&gt;
&lt;p&gt;and yes, the timings show that the crawls occurred in parallel!&lt;/p&gt;
&lt;p&gt;The entire project in R is then the following (less than 100) lines, including
the configuration, database connection, execution, and analysis.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## Config

sites &amp;lt;- data.frame(url = c(&amp;quot;https://packagemain.tech&amp;quot;,
                            &amp;quot;https://pliutau.com&amp;quot;,
                            &amp;quot;https://news.ycombinator.com&amp;quot;),
                    interval = c(10, 15, 30),
                    pattern = c(&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;tech&amp;quot;)
)

## Database

## write a blank table to preserve types
websites &amp;lt;- data.frame(
  start_time = integer(),
  end_time = integer(),
  status = integer(),
  pattern_matched = logical(),
  url = character()
)

con &amp;lt;- DBI::dbConnect(RSQLite::SQLite(), &amp;quot;~/Projects/websites_par.sqlite&amp;quot;)
DBI::dbWriteTable(con, &amp;quot;websites&amp;quot;, websites, overwrite = TRUE)
DBI::dbDisconnect(con)

## Crawl

single_crawl &amp;lt;- function(url, 
                         pattern = &amp;quot;&amp;quot;, 
                         write = TRUE, 
                         db = Sys.getenv(&amp;quot;CRAWL_DB&amp;quot;)) {
  
  start_time &amp;lt;- format(Sys.time(), &amp;quot;%s&amp;quot;)
  resp &amp;lt;- httr2::request(url) |&amp;gt; 
    httr2::req_perform()
  end_time &amp;lt;- format(Sys.time(), &amp;quot;%s&amp;quot;)
  
  res &amp;lt;- data.frame(
    start_time = start_time,
    end_time = end_time,
    status = httr2::resp_status(resp),
    pattern_matched = pattern != &amp;quot;&amp;quot; &amp;amp;&amp;amp; grepl(pattern, httr2::resp_body_string(resp)),
    url = url
  )
  
  if (!write) {
    return(res)
  } 
  
  con &amp;lt;- DBI::dbConnect(RSQLite::SQLite(), db)
  DBI::dbWriteTable(con, &amp;quot;websites&amp;quot;, res, append = TRUE)
  DBI::dbDisconnect(con)
  
  invisible()
}

crawl &amp;lt;- function(url,
                  interval, 
                  pattern = &amp;quot;&amp;quot;, 
                  write = TRUE, 
                  db = Sys.getenv(&amp;quot;CRAWL_DB&amp;quot;)) {
  
  for (i in 1:4) {
    message(glue::glue(&amp;quot;Crawling {url} ({i})&amp;quot;))
    single_crawl(url = url, pattern = pattern, write = write, db = db)
    Sys.sleep(interval)
  }
  
}

## Execute

library(future)
plan(multisession)

furrr::future_pwalk(sites, crawl, db = &amp;quot;websites_par.sqlite&amp;quot;)

## Analysis 

con &amp;lt;- DBI::dbConnect(RSQLite::SQLite(), &amp;quot;websites_par.sqlite&amp;quot;))
times &amp;lt;- tbl(con, &amp;quot;websites&amp;quot;) |&amp;gt; 
  collect() |&amp;gt; 
  mutate(start_s = start_time - start_time[1]) |&amp;gt; 
  mutate(end_s = end_time - start_time[1])
DBI::dbDisconnect(con)

library(ggplot2)

ggplot(times) + 
  geom_point(aes(start_s, 1), col = &amp;quot;green&amp;quot;, size = 6) + 
  geom_point(aes(end_s, 1), col = &amp;quot;red&amp;quot;, size = 6) + 
  facet_wrap(~url, ncol = 1) + 
  theme_minimal() + 
  theme(axis.text.y = element_blank(), 
        axis.title.y = element_blank(),
        panel.grid.major.y = element_blank(),
        panel.grid.minor.y = element_blank()) +
  scale_x_continuous(breaks = seq(0, 200, 10))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One point I think it worth making is that a lot of academics write code this way
- starting with something interactive that works, and that’s fantastic, but leaving
it in this state is probably a mistake, especially if you ever plan to use it
again.&lt;/p&gt;
&lt;p&gt;What should really be done next is to wrap it up into an R package - the equivalent
of the Gleam program - with defined entry points, maybe an exported &lt;code&gt;paralell_crawl()&lt;/code&gt;
function, but including the well-defined imports. I haven’t done that here for the
sake of simplicity - I don’t actually plan to use this.&lt;/p&gt;
&lt;p&gt;Let’s say you did, though - how would you run it? Even as a script, you could
go beyond interactively running it and do so from the command line&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Rscript myfile.R&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(especially if it doesn’t need command-line arguments).&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;comparing-approaches&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Comparing approaches&lt;/h2&gt;
&lt;p&gt;The point of all of this wasn’t to say which language is better or which one you
&lt;em&gt;should&lt;/em&gt; use for anything - that’s entirely dependent on your familiarity with a
language and its tooling and support for what you’re trying to do. My goal was
to compare the approaches and see what I like about each of them.&lt;/p&gt;
&lt;p&gt;I really like R’s ability to dive into the data itself in the REPL and have that
guide what I’m writing next. That does all-too frequently lead to leaving code
in an ‘interactive’ state, which is a poor way to structure a project.&lt;/p&gt;
&lt;p&gt;The strongly typed nature of the Gleam code means that it’s less likely to mishandle
any pieces of data. I was hoping I’d spot somewhere in the Gleam code where I could
say “ah, if I tried to pass &lt;em&gt;this&lt;/em&gt; in here I’d get a compile error” but perhaps
this is too small a project for that to be an issue.&lt;/p&gt;
&lt;p&gt;That strict typing possibly also makes it &lt;em&gt;harder&lt;/em&gt; to ‘just work’ with the data
- I haven’t tried it, but I wonder if the custom &lt;code&gt;CrawlResult&lt;/code&gt; structure has a
print method, or if it just prints all the fields.&lt;/p&gt;
&lt;p&gt;The R approach has less ‘ceremony’, largely because it lacks the type handling. I
also believe R to better handle the data across its journey from crawling to
analysis, and re-emphasise that this wasn’t a ‘statistics’ project.&lt;/p&gt;
&lt;p&gt;I’d love to hear what people think about this comparison - are there points I’ve
overlooked where Gleam has an advantage? Considerations I’ve missed? Big wins on
either side? As always, I can be found on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; and the comment section below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.3 (2024-02-29)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2024-09-05
##  pandoc   3.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.19.1  2024-09-05 [1] Github (rstudio/blogdown@c6e73fb)
##  bookdown      0.36    2023-10-16 [1] CRAN (R 4.3.2)
##  bslib         0.6.1   2023-11-28 [3] CRAN (R 4.3.2)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [1] CRAN (R 4.3.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  curl          5.0.2   2023-08-14 [3] CRAN (R 4.3.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.3.2)
##  digest        0.6.34  2024-01-11 [3] CRAN (R 4.3.2)
##  dplyr         1.1.4   2023-11-17 [3] CRAN (R 4.3.2)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.23    2023-11-01 [3] CRAN (R 4.3.2)
##  fansi         1.0.6   2023-12-08 [1] CRAN (R 4.3.3)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  generics      0.1.3   2022-07-05 [3] CRAN (R 4.2.1)
##  glue          1.7.0   2024-01-09 [1] CRAN (R 4.3.3)
##  htmltools     0.5.7   2023-11-03 [3] CRAN (R 4.3.2)
##  htmlwidgets   1.6.2   2023-03-17 [1] CRAN (R 4.3.2)
##  httpuv        1.6.12  2023-10-23 [1] CRAN (R 4.3.2)
##  httr2         1.0.0   2023-11-14 [1] CRAN (R 4.3.2)
##  icecream      0.2.1   2023-09-27 [1] CRAN (R 4.3.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.8   2023-12-04 [3] CRAN (R 4.3.2)
##  knitr         1.45    2023-10-30 [3] CRAN (R 4.3.2)
##  later         1.3.1   2023-05-02 [1] CRAN (R 4.3.2)
##  lifecycle     1.0.4   2023-11-07 [1] CRAN (R 4.3.3)
##  magrittr      2.0.3   2022-03-30 [1] CRAN (R 4.3.3)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.3.2)
##  pillar        1.9.0   2023-03-22 [1] CRAN (R 4.3.3)
##  pkgbuild      1.4.2   2023-06-26 [1] CRAN (R 4.3.2)
##  pkgconfig     2.0.3   2019-09-22 [1] CRAN (R 4.3.3)
##  pkgload       1.3.3   2023-09-22 [1] CRAN (R 4.3.2)
##  prettyunits   1.2.0   2023-09-24 [3] CRAN (R 4.3.1)
##  processx      3.8.3   2023-12-10 [3] CRAN (R 4.3.2)
##  profvis       0.3.8   2023-05-02 [1] CRAN (R 4.3.2)
##  promises      1.2.1   2023-08-10 [1] CRAN (R 4.3.2)
##  ps            1.7.6   2024-01-18 [3] CRAN (R 4.3.2)
##  purrr         1.0.2   2023-08-10 [3] CRAN (R 4.3.1)
##  R6            2.5.1   2021-08-19 [1] CRAN (R 4.3.3)
##  rappdirs      0.3.3   2021-01-31 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.11  2023-07-06 [1] CRAN (R 4.3.2)
##  remotes       2.4.2.1 2023-07-18 [1] CRAN (R 4.3.2)
##  rlang         1.1.4   2024-06-04 [1] CRAN (R 4.3.3)
##  rmarkdown     2.25    2023-09-18 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.8   2023-12-06 [3] CRAN (R 4.3.2)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.3.2)
##  shiny         1.7.5.1 2023-10-14 [1] CRAN (R 4.3.2)
##  stringi       1.8.3   2023-12-11 [3] CRAN (R 4.3.2)
##  stringr       1.5.1   2023-11-14 [3] CRAN (R 4.3.2)
##  tibble        3.2.1   2023-03-20 [1] CRAN (R 4.3.3)
##  tidyselect    1.2.0   2022-10-10 [3] CRAN (R 4.2.1)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.3.2)
##  usethis       3.0.0   2024-07-29 [1] CRAN (R 4.3.3)
##  utf8          1.2.4   2023-10-22 [1] CRAN (R 4.3.3)
##  vctrs         0.6.5   2023-12-01 [1] CRAN (R 4.3.3)
##  xfun          0.41    2023-11-01 [3] CRAN (R 4.3.2)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.3.2)
##  yaml          2.3.8   2023-12-11 [3] CRAN (R 4.3.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>IPv4 Components in APL</title>
      <link>https://jcarroll.com.au/2024/08/22/ipv4-components-in-apl/</link>
      <pubDate>Thu, 22 Aug 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/08/22/ipv4-components-in-apl/</guid>
      <description>&lt;p&gt;At a recent APL-focussed Meetup someone posed a challenge to slice up the
components of an IPv4 address with an APL language and it prompted me to learn
a bit more about how that works in general and how I could do the processing in
APL myself.&lt;/p&gt;
&lt;p&gt;The person who posed the challenge had approached it themselves using &lt;a href=&#34;https://en.wikipedia.org/wiki/J_(programming_language)&#34;&gt;J&lt;/a&gt;
which I’m only vaguely familiar with, but it gave me an opportunity to learn a bit more
about it. It’s not all that dissimilar from the Dyalog APL I know a bit better;
it uses a standard ASCII input with many of the same ideas - for example, determining
whether a year is a leapyear or not &lt;a href=&#34;https://jcarroll.xyz/2024/08/19/leap-years-with.html&#34;&gt;as I explored recently&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In Dyalog APL:&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;⍝ Dyalog APL
      leapyear ← {(80∨⍵) &amp;gt; 50∨⍵}
      years ← 1890+⍳30
      (leapyear years) ⌿ years
1892 1896 1904 1908 1912 1916 1920

⍝ or tacit
      leapyear ← 80∘∨ &amp;gt; 50∘∨&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;compared to J:&lt;/p&gt;
&lt;pre class=&#34;j&#34;&gt;&lt;code&gt;NB. J
   leapyear =: {{ (80 +. y) &amp;gt; (50 +. y) }}
   years =: 1890 + i.31
   (leapyear years) # years
1892 1896 1904 1908 1912 1916 1920

NB. or tatic
   leapyear =: 80&amp;amp;+. &amp;gt; 50&amp;amp;+.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s fairly straightforward to see the correlation between these two.&lt;/p&gt;
&lt;p&gt;I don’t think we worked through the J solution to slicing up the components
of an IPv4 address, but I did have a go during the meeting at a Dyalog APL
solution, which we walked through and I’ve since improved.&lt;/p&gt;
&lt;p&gt;The problem as posed was - given an IPv4 address, e.g. ‘192.0.2.63’ and a subnet
mask in &lt;a href=&#34;https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation&#34;&gt;CIDR notation&lt;/a&gt;
(e.g. &lt;code&gt;/24&lt;/code&gt;), can we identify the different networking components?&lt;/p&gt;
&lt;p&gt;This is a neat problem because it potentially involves arrays - maybe we should
start with what this means. I’m no expert in this myself, but explaining things
is a great way to learn more about them, so feel free to correct me at any point.&lt;/p&gt;
&lt;p&gt;I started with &lt;a href=&#34;https://www.auvik.com/franklyit/blog/what-is-subnet-mask/&#34;&gt;this guide&lt;/a&gt;
which I &lt;em&gt;know&lt;/em&gt; already has a mistake in one of the graphics - can you find it?&lt;/p&gt;
&lt;p&gt;An IPv4 address consists of four octets separated by dots, each number representing
8 bits (hence ‘octet’) which in binary means 8 &lt;code&gt;1&lt;/code&gt;s or &lt;code&gt;0&lt;/code&gt;s for a maximum value of 255&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;192 = 11000000
    = 1x(2^8) + 1x(2^7) + 0x(2^6) + 0x(2^5) + ... 
    = 256 + 128 + 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so we have four of these sets of 8 binary values that represent an address.&lt;/p&gt;
&lt;p&gt;The subnet mask is described by the CIDR block and it essentially represents how
many &lt;code&gt;1&lt;/code&gt;s are at the start of an address, so if the mask is ‘255.0.0.0’ then it
would be&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;11111111 00000000 00000000 00000000&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is 8 &lt;code&gt;1&lt;/code&gt;s, so it would be &lt;code&gt;/8&lt;/code&gt;. Similarly &lt;code&gt;/26&lt;/code&gt; would have 26 &lt;code&gt;1&lt;/code&gt;s and
converting from binary to decimal would represent a mask of ‘255.255.255.192’.&lt;/p&gt;
&lt;p&gt;So, given an address and a CIDR block, what is the mask?&lt;/p&gt;
&lt;p&gt;First, we need to convert our address from a string to an array of binary digits.
One way to partition a string at a character in APL is&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      &amp;#39;.&amp;#39;(≠⊆⊢)&amp;#39;192.0.2.63&amp;#39;
192  0  2  63      &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and we can convert this array of strings to numbers with ‘eval’&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      ⍎¨&amp;#39;.&amp;#39;(≠⊆⊢)&amp;#39;192.0.2.63&amp;#39;
192 0 2 63&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Converting to binary in APL is as easy as ‘decode’ with a radix of 8 &lt;code&gt;2&lt;/code&gt;s&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      2 2 2 2 2 2 2 2 ⊤ ⍎¨&amp;#39;.&amp;#39;(≠⊆⊢)&amp;#39;192.0.2.63&amp;#39;
1 0 0 0
1 0 0 0
0 0 0 1
0 0 0 1
0 0 0 1
0 0 0 1
0 0 1 1
0 0 0 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but of course we can write all those &lt;code&gt;2&lt;/code&gt;s with either &lt;code&gt;(8⍴2)&lt;/code&gt; (‘reshape’ a value
of &lt;code&gt;2&lt;/code&gt; to length 8) or &lt;code&gt;(8/2)&lt;/code&gt; (‘repeat’ &lt;code&gt;2&lt;/code&gt; 8 times) so&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      (8⍴2)⊤⍎¨&amp;#39;.&amp;#39;(≠⊆⊢)&amp;#39;192.0.2.63&amp;#39;
1 0 0 0
1 0 0 0
0 0 0 1
0 0 0 1
0 0 0 1
0 0 0 1
0 0 1 1
0 0 0 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That gives us the binary sequences for each of the octets as columns of an array.
It’s a lot to type out each time, though, so we can create a function that
takes a right argument&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      asbin←{(8/2)⊤⍎¨&amp;#39;.&amp;#39;(≠⊆⊢)⍵}
      asbin &amp;#39;192.0.2.63&amp;#39;
1 0 0 0
1 0 0 0
0 0 0 1
0 0 0 1
0 0 0 1
0 0 0 1
0 0 1 1
0 0 0 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, if we want to go back the other way and see this as an IP address made
of octets, we can ‘paste’ the values (converted back to integers) together with
dots between them with&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      asoct←2∘⊥
      asip←{∊(⍕¨⍵),¨&amp;#39;.&amp;#39; &amp;#39;.&amp;#39; &amp;#39;.&amp;#39; &amp;#39;&amp;#39;}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first of these creates a “curried” (partially applied) ‘decode’ with radix &lt;code&gt;2&lt;/code&gt;,
while the second ’format’s the values in the specified pattern, so&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      asoct asbin &amp;#39;192.0.2.63&amp;#39;
192 0 2 63

      asip asoct asbin &amp;#39;192.0.2.63&amp;#39;
192.0.2.63&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cool, we can round-trip this.&lt;/p&gt;
&lt;p&gt;The subnet mask is a series of &lt;code&gt;1&lt;/code&gt;s filled to 32 values with &lt;code&gt;0&lt;/code&gt;s which we can write as&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      mask←{⍉4 8 ⍴ 1=⍸⍵ 0 (32-⍵)}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which creates a 4x8 array of values filled with the right number of &lt;code&gt;1&lt;/code&gt;s&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      mask 26
1 1 1 1
1 1 1 1
1 1 1 0
1 1 1 0
1 1 1 0
1 1 1 0
1 1 1 0
1 1 1 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can view this subnet mask with this new function, too&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      asoct mask 26
255 255 255 192

      asip asoct mask 26
255.255.255.192&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The ‘network address’ for this address is found by a bitwise AND between this
mask and the IP address, and APL has a builtin ‘and’&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;      (mask 26) ∧ asbin &amp;#39;192.0.2.63&amp;#39;
1 0 0 0
1 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 1 0
0 0 0 0

      asip asoct (mask 26) ∧ asbin &amp;#39;192.0.2.63&amp;#39;
192.0.2.0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The ‘broadcast address’ is found by a bitwise OR between the &lt;em&gt;inverse&lt;/em&gt; of the
mask and the IP address&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      (~mask 26) ∨ asbin &amp;#39;192.0.2.63&amp;#39;
1 0 0 0
1 0 0 0
0 0 0 1
0 0 0 1
0 0 0 1
0 0 0 1
0 0 1 1
0 0 0 1

      asip asoct (~mask 26) ∨ asbin &amp;#39;192.0.2.63&amp;#39;
192.0.2.63&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looking at what we have so far, we can write out some functions&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      asip←{∊(⍕¨⍵),¨&amp;#39;.&amp;#39; &amp;#39;.&amp;#39; &amp;#39;.&amp;#39; &amp;#39;&amp;#39;}
      asoct←2∘⊥
      mask←{⍉4 8 ⍴ 1=⍸⍵ 0 (32-⍵)}
      smask←{asip asoct mask ⍵}
      asbin←{(8/2)⊤⍎¨&amp;#39;.&amp;#39;(≠⊆⊢)⍵}
      netaddr←{asip asoct (mask ⍺) ∧ asbin ⍵}
      bcast←{asip asoct (~mask ⍺) ∨ asbin ⍵}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and try these on some different addresses&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      ip←&amp;#39;192.168.0.1&amp;#39;
      smask 8
255.0.0.0

      26 netaddr ip
192.168.0.0

      26 bcast ip
192.168.0.63

      ip←&amp;#39;142.250.70.174&amp;#39;
      
      16 netaddr ip
142.250.0.0

      16 bcast ip
142.250.255.255&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cool!&lt;/p&gt;
&lt;p&gt;We could also calculate the number of hosts that can be assigned, since
that’s just 2 to the power of the number of host bits (non-network bits), minus
the network and broadcast addresses&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      nhosts←{¯2+2*(32-⍵)}
      nhosts 26
62&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We could list the entire range of host IPs, except we need to offset the
network and broadcast addresses. Time to make some utilities&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      netutil←{asoct (mask ⍺) ∧ asbin ⍵}
      butil←{asoct (~mask ⍺) ∨ asbin ⍵}

      bcast1←{x←⍺ butil ⍵ ⋄ x[4]←x[4]-1 ⋄ asip x}
      netaddr1←{x←⍺ netutil ⍵ ⋄ x[4]←x[4]+1 ⋄ asip x}
      
      iprange←{n←⍺ netaddr1 ⍵ ⋄ b←⍺ bcast1 ⍵ ⋄ n,&amp;#39;-&amp;#39;,b}
      
      26 iprange &amp;#39;192.0.2.63&amp;#39;
192.0.2.1-192.0.2.62&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That seems like a good set of utilities - and a great opportunity to learn about
how Dyalog APL packages up things into namespaces. One way is to write the
functions to a file, say &lt;code&gt;SubnetCalc.dyalog&lt;/code&gt; as&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:Namespace SubnetCalc
    asip←{∊(⍕¨⍵),¨&amp;#39;.&amp;#39; &amp;#39;.&amp;#39; &amp;#39;.&amp;#39; &amp;#39;&amp;#39;}
    asoct←{2⊥⍵}
    mask←{⍉4 8 ⍴ 1=⍸⍵ 0 (32-⍵)}
    nhosts←{¯2+2*(32-⍵)}
    smask←{asip asoct mask ⍵}
    asbin←{(8/2)⊤⍎¨&amp;#39;.&amp;#39;(≠⊆⊢)⍵}
    netutil←{asoct (mask ⍺)∧asbin ⍵}
    netaddr←{asip ⍺ netutil ⍵}
    netaddr1←{x←⍺ netutil ⍵ ⋄ x[4]←x[4]+1 ⋄ asip x}
    butil←{asoct (~mask ⍺)∨asbin ⍵}
    bcast←{asip ⍺ butil ⍵}
    bcast1←{x←⍺ butil ⍵ ⋄ x[4]←x[4]-1 ⋄ asip x}
    iprange←{n←⍺ netaddr1 ⍵ ⋄ b←⍺ bcast1 ⍵ ⋄ n,&amp;#39;-&amp;#39;,b}
:EndNamespace&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(noting that I needed to use explicit defuns rather than just tacit calls) then
load that into the RIDE editor session with&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;⎕FIX &amp;#39;/path/to/project/SubnetCalc.dyalog&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and give it a shorter name, if desired&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;&amp;#39;ip&amp;#39; ⎕NS SubnetCalc&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I can call my functions even faster&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      ip.smask 26
255.255.255.192

      google←&amp;#39;142.250.70.174&amp;#39;

      26 ip.iprange google
142.250.70.129-142.250.70.190&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dyalog has recently announced a proper package infrastructure &lt;a href=&#34;https://tatin.dev/&#34;&gt;Tatin&lt;/a&gt;
which might come as a surprise to those more familiar with newer languages, but
it’s actually one of the &lt;em&gt;first&lt;/em&gt; package ecosystems for an APL language that I
know of. I want to figure out whether my ‘toy’ package is too simplistic to be
shared, or if it’s worth learning those ropes. At the moment all the packages
in that system are internally sourced, but presumably that would open up to
external users once it’s stabilised.&lt;/p&gt;
&lt;p&gt;All of this was a lot of fun and I learned a lot. How would I go about this
in another language? Well, there’s almost always an R package for something, and
sure enough there’s an {ipaddress} package on CRAN that has all of this
functionality plus more, though it does seem to rely on compiling some C++ code
to do it.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ipaddress)

ip &amp;lt;- ip_address(&amp;quot;192.0.2.44&amp;quot;)
ip_to_binary(ip)                     # c.f. asbin&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;11000000000000000000001000101100&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ipn &amp;lt;- ip_network(&amp;quot;192.0.2.0/26&amp;quot;)
prefix_length(ipn)                   # c.f. nhosts&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 26&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;network_address(ipn)                 # c.f. netaddr&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;lt;ip_address[1]&amp;gt;
## [1] 192.0.2.0&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;broadcast_address(ipn)               # c.f. bcast&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;lt;ip_address[1]&amp;gt;
## [1] 192.0.2.63&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;netmask(ipn)                         # c.f. smask&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;lt;ip_address[1]&amp;gt;
## [1] 255.255.255.192&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;hostmask(ipn)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;lt;ip_address[1]&amp;gt;
## [1] 0.0.0.63&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;range(hosts(ipn))                    # c.f. iprange&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;lt;ip_address[2]&amp;gt;
## [1] 192.0.2.1  192.0.2.62&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_within(ip, ipn)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One of the advantages of the APL approach, I feel, is that you can see exactly
what the function is doing - often there’s no point naming a function because
any useful name you might give it typically has more characters than the actual
implementation. Digging into this package even slightly, it’s not immediately
obvious where the processing is happening. I sometimes worry that we add too
many layers to higher and higher abstractions, though I appreciate that
sometimes gets us a lot of benefit.&lt;/p&gt;
&lt;p&gt;I wouldn’t use my APL code in production - it has no checks or error handling, but
building these helped me really understand what’s going on between all the ones
and zeroes.&lt;/p&gt;
&lt;p&gt;If you have comments, suggestions, or improvements, as always, feel free to use
the comment section below, or hit me up on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.3 (2024-02-29)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2024-08-22
##  pandoc   3.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.19    2024-02-01 [1] CRAN (R 4.3.3)
##  bookdown      0.36    2023-10-16 [1] CRAN (R 4.3.2)
##  bslib         0.6.1   2023-11-28 [3] CRAN (R 4.3.2)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [1] CRAN (R 4.3.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.3.2)
##  digest        0.6.34  2024-01-11 [3] CRAN (R 4.3.2)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.23    2023-11-01 [3] CRAN (R 4.3.2)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  glue          1.7.0   2024-01-09 [1] CRAN (R 4.3.3)
##  htmltools     0.5.7   2023-11-03 [3] CRAN (R 4.3.2)
##  htmlwidgets   1.6.2   2023-03-17 [1] CRAN (R 4.3.2)
##  httpuv        1.6.12  2023-10-23 [1] CRAN (R 4.3.2)
##  icecream      0.2.1   2023-09-27 [1] CRAN (R 4.3.2)
##  ipaddress   * 1.0.2   2023-12-01 [1] CRAN (R 4.3.3)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.8   2023-12-04 [3] CRAN (R 4.3.2)
##  knitr         1.45    2023-10-30 [3] CRAN (R 4.3.2)
##  later         1.3.1   2023-05-02 [1] CRAN (R 4.3.2)
##  lifecycle     1.0.4   2023-11-07 [1] CRAN (R 4.3.3)
##  magrittr      2.0.3   2022-03-30 [1] CRAN (R 4.3.3)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.3.2)
##  pkgbuild      1.4.2   2023-06-26 [1] CRAN (R 4.3.2)
##  pkgload       1.3.3   2023-09-22 [1] CRAN (R 4.3.2)
##  prettyunits   1.2.0   2023-09-24 [3] CRAN (R 4.3.1)
##  processx      3.8.3   2023-12-10 [3] CRAN (R 4.3.2)
##  profvis       0.3.8   2023-05-02 [1] CRAN (R 4.3.2)
##  promises      1.2.1   2023-08-10 [1] CRAN (R 4.3.2)
##  ps            1.7.6   2024-01-18 [3] CRAN (R 4.3.2)
##  purrr         1.0.2   2023-08-10 [3] CRAN (R 4.3.1)
##  R6            2.5.1   2021-08-19 [1] CRAN (R 4.3.3)
##  Rcpp          1.0.11  2023-07-06 [1] CRAN (R 4.3.2)
##  remotes       2.4.2.1 2023-07-18 [1] CRAN (R 4.3.2)
##  rlang         1.1.4   2024-06-04 [1] CRAN (R 4.3.3)
##  rmarkdown     2.25    2023-09-18 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.8   2023-12-06 [3] CRAN (R 4.3.2)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.3.2)
##  shiny         1.7.5.1 2023-10-14 [1] CRAN (R 4.3.2)
##  stringi       1.8.3   2023-12-11 [3] CRAN (R 4.3.2)
##  stringr       1.5.1   2023-11-14 [3] CRAN (R 4.3.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.3.2)
##  usethis       3.0.0   2024-07-29 [1] CRAN (R 4.3.3)
##  vctrs         0.6.5   2023-12-01 [1] CRAN (R 4.3.3)
##  xfun          0.41    2023-11-01 [3] CRAN (R 4.3.2)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.3.2)
##  yaml          2.3.8   2023-12-11 [3] CRAN (R 4.3.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Tidy DataFrames but not Tibbles</title>
      <link>https://jcarroll.com.au/2024/08/11/tidy-dataframes-but-not-tibbles/</link>
      <pubDate>Sun, 11 Aug 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/08/11/tidy-dataframes-but-not-tibbles/</guid>
      <description>&lt;p&gt;A while ago (2019 seems so long ago now) I started working on something I
thought was interesting but which never really got any traction. It has
potential once more, so it’s about time I wrote up what it does and why I think
it’s a useful idea. I’m going to talk about using the {dplyr} package on some
data with rows and columns, but we’re not talking about &lt;code&gt;data.frame&lt;/code&gt;s or
&lt;code&gt;tibble&lt;/code&gt;s…&lt;/p&gt;
&lt;p&gt;Okay, I probably do need to talk about them a little to start with.&lt;/p&gt;
&lt;p&gt;I’m also taking this opportunity to reinforce my own understanding of all
these pieces - I find the best way to learn something is to teach it.&lt;/p&gt;
&lt;div id=&#34;data.frame&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;code&gt;data.frame&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;One of the basic building blocks of data in R is the &lt;code&gt;data.frame&lt;/code&gt; - technically
a list of vectors (vectors must have the same ‘type’ but lists don’t have this
restriction) where the vectors are all the same length. An example looks like
this&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;d &amp;lt;- data.frame(x = 2:5, y = LETTERS[2:5], z = 4:7+2i)
d&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   x y    z
## 1 2 B 4+2i
## 2 3 C 5+2i
## 3 4 D 6+2i
## 4 5 E 7+2i&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we unpack that a bit, it &lt;em&gt;is&lt;/em&gt; just a list of vectors&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;unclass(d)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## $x
## [1] 2 3 4 5
## 
## $y
## [1] &amp;quot;B&amp;quot; &amp;quot;C&amp;quot; &amp;quot;D&amp;quot; &amp;quot;E&amp;quot;
## 
## $z
## [1] 4+2i 5+2i 6+2i 7+2i
## 
## attr(,&amp;quot;row.names&amp;quot;)
## [1] 1 2 3 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and there we see one more feature; they have an attribute &lt;code&gt;row.names&lt;/code&gt;. By default
these are just numbers (encoded as strings) which we can get to with the &lt;code&gt;rownames()&lt;/code&gt;
function&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;rownames(d)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;1&amp;quot; &amp;quot;2&amp;quot; &amp;quot;3&amp;quot; &amp;quot;4&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you’ve read any guides to using R you will likely have seen the &lt;code&gt;mtcars&lt;/code&gt; dataset
which features these row names prominently - here’s the first 4 rows and columns&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mtcars[1:4, 1:4]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##                 mpg cyl disp  hp
## Mazda RX4      21.0   6  160 110
## Mazda RX4 Wag  21.0   6  160 110
## Datsun 710     22.8   4  108  93
## Hornet 4 Drive 21.4   6  258 110&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can extract those row names&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;rownames(mtcars[1:4, 1:4])&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;Mazda RX4&amp;quot;      &amp;quot;Mazda RX4 Wag&amp;quot;  &amp;quot;Datsun 710&amp;quot;     &amp;quot;Hornet 4 Drive&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This “row name” data sort of sits off to the side of the data object, but yes,
they &lt;em&gt;could&lt;/em&gt; live “in” the data just fine as their own vector. That’s the approach
that the tidyverse takes with &lt;code&gt;tibble&lt;/code&gt;s. There’s one other benefit to these that
is often overlooked, though.&lt;/p&gt;
&lt;p&gt;In the above examples I’ve extracted some rows of the &lt;code&gt;mtcars&lt;/code&gt; &lt;code&gt;data.frame&lt;/code&gt; with
indices, but the &lt;code&gt;[&lt;/code&gt; method works just as well with row identifiers (strings)…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mercs &amp;lt;- grep(&amp;quot;Merc&amp;quot;, rownames(mtcars), value = TRUE)
mercs&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;Merc 240D&amp;quot;   &amp;quot;Merc 230&amp;quot;    &amp;quot;Merc 280&amp;quot;    &amp;quot;Merc 280C&amp;quot;   &amp;quot;Merc 450SE&amp;quot; 
## [6] &amp;quot;Merc 450SL&amp;quot;  &amp;quot;Merc 450SLC&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mtcars[mercs, 1:4]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##              mpg cyl  disp  hp
## Merc 240D   24.4   4 146.7  62
## Merc 230    22.8   4 140.8  95
## Merc 280    19.2   6 167.6 123
## Merc 280C   17.8   6 167.6 123
## Merc 450SE  16.4   8 275.8 180
## Merc 450SL  17.3   8 275.8 180
## Merc 450SLC 15.2   8 275.8 180&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’re probably more familiar with this when subsetting columns, in which case
you’re using the column names in exactly the same way&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;metrics &amp;lt;- c(&amp;quot;mpg&amp;quot;, &amp;quot;hp&amp;quot;, &amp;quot;drat&amp;quot;)
mtcars[mercs, metrics]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##              mpg  hp drat
## Merc 240D   24.4  62 3.69
## Merc 230    22.8  95 3.92
## Merc 280    19.2 123 3.92
## Merc 280C   17.8 123 3.92
## Merc 450SE  16.4 180 3.07
## Merc 450SL  17.3 180 3.07
## Merc 450SLC 15.2 180 3.07&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As we’ll see, this becomes very convenient when we have meaningful identifiers
in both dimensions.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;tibble&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;{tibble}&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;tibble&lt;/code&gt; is almost exactly like a &lt;code&gt;data.frame&lt;/code&gt; except that the print method shows
it a bit differently&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;tbl &amp;lt;- tibble::as_tibble(mtcars[1:4, 1:4])
tbl&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 4 × 4
##     mpg   cyl  disp    hp
##   &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt;
## 1  21       6   160   110
## 2  21       6   160   110
## 3  22.8     4   108    93
## 4  21.4     6   258   110&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the row names are gone. That’s by design, and enforced quite strongly - if I
tried to add them back, {tibble} complains, and refuses&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;rownames(tbl) &amp;lt;- rownames(mtcars)[1:4]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-warning text-warning&#34;&gt;&lt;code&gt;## Warning: Setting row names on a tibble is deprecated.&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;tbl&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 4 × 4
##     mpg   cyl  disp    hp
## * &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt;
## 1  21       6   160   110
## 2  21       6   160   110
## 3  22.8     4   108    93
## 4  21.4     6   258   110&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The world moves on, though.&lt;/p&gt;
&lt;p&gt;If you &lt;em&gt;have&lt;/em&gt; row names that you really want to keep, {tibble} has a way to get them
into their own column so that they’ll be preserved in a &lt;code&gt;tibble&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;tbl_rows &amp;lt;- mtcars[6:10, 1:5] |&amp;gt; 
  tibble::rownames_to_column() |&amp;gt; 
  tibble::as_tibble()
tbl_rows&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 5 × 6
##   rowname      mpg   cyl  disp    hp  drat
##   &amp;lt;chr&amp;gt;      &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt;
## 1 Valiant     18.1     6  225    105  2.76
## 2 Duster 360  14.3     8  360    245  3.21
## 3 Merc 240D   24.4     4  147.    62  3.69
## 4 Merc 230    22.8     4  141.    95  3.92
## 5 Merc 280    19.2     6  168.   123  3.92&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get the named subsetting behaviour described earlier, we have to specify the
&lt;code&gt;&#34;rowname&#34;&lt;/code&gt; column in the output and do some filtering on it to get the rows we
want&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;tbl_rows[tbl_rows$rowname %in% mercs, c(&amp;quot;rowname&amp;quot;, metrics)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 3 × 4
##   rowname     mpg    hp  drat
##   &amp;lt;chr&amp;gt;     &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt;
## 1 Merc 240D  24.4    62  3.69
## 2 Merc 230   22.8    95  3.92
## 3 Merc 280   19.2   123  3.92&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, there’s a better way to subset a &lt;code&gt;tibble&lt;/code&gt;…&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;dplyr&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;{dplyr}&lt;/h2&gt;
&lt;p&gt;In terms of interacting with these objects, {dplyr} is great - it’s reminiscent
of SQL syntax (&lt;code&gt;SELECT&lt;/code&gt;, &lt;code&gt;GROUP BY&lt;/code&gt;, … look, it’s not 1:1, but it’s somewhat
familiar) and makes for a really clean pipeline of data processing - it got in
early supporting the {magrittr} pipe and encouraging a ‘data as the first
argument’ construction that meant piping from one function to another went
smoothly.&lt;/p&gt;
&lt;p&gt;There’s not much in {dplyr} that you couldn’t do with a bunch of base functions
if you were so inclined - and some people have gone as far as proving that with
non-dplyr packages with matching functions but base internals, forgoing {dplyr}’s
ability to connect to a database with the exact same code you would use on a
local &lt;code&gt;tibble&lt;/code&gt; ({dbplyr} translates the R calls into native SQL syntax behind the
scenes) for some more debuggable code, e.g. &lt;a href=&#34;https://nathaneastwood.github.io/poorman/&#34;&gt;{poorman}&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;{dplyr} functions mostly return the same class as the input; if you &lt;code&gt;mutate&lt;/code&gt; a
&lt;code&gt;data.frame&lt;/code&gt; you’ll get back a &lt;code&gt;data.frame&lt;/code&gt; (which wasn’t always the case, but
is less surprising now)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mtcars[1:5, 1:6] |&amp;gt; 
  dplyr::mutate(pwr = hp / wt)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##                    mpg cyl disp  hp drat    wt      pwr
## Mazda RX4         21.0   6  160 110 3.90 2.620 41.98473
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 38.26087
## Datsun 710        22.8   4  108  93 3.85 2.320 40.08621
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 34.21462
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 50.87209&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One feature that &lt;code&gt;tibble&lt;/code&gt; adds on top of &lt;code&gt;data.frame&lt;/code&gt; is the concept of “groups”.
For this reason, if you perform a grouping on a &lt;code&gt;data.frame&lt;/code&gt; you’ll get a &lt;code&gt;tibble&lt;/code&gt;
because that’s the only supported option&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# slice(1) on a data.frame returns 1 row of a data.frame
mtcars |&amp;gt; 
  dplyr::slice(1)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##           mpg cyl disp  hp drat   wt  qsec vs am gear carb
## Mazda RX4  21   6  160 110  3.9 2.62 16.46  0  1    4    4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# slice(1) on a grouped tibble returns 1 row _per group_ 
mtcars |&amp;gt; 
  dplyr::group_by(gear, am) |&amp;gt; 
  dplyr::slice(1)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 4 × 11
## # Groups:   gear, am [4]
##     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
##   &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt; &amp;lt;dbl&amp;gt;
## 1  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1
## 2  24.4     4  147.    62  3.69  3.19  20       1     0     4     2
## 3  21       6  160    110  3.9   2.62  16.5     0     1     4     4
## 4  26       4  120.    91  4.43  2.14  16.7     0     1     5     2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;{tibble} stores this information in a special &lt;code&gt;&#34;groups&#34;&lt;/code&gt; attribute, and ensures
that {dplyr} functions are aware of it. It also prints this information above
the object (plus the number of resulting ‘groups’).&lt;/p&gt;
&lt;p&gt;Is there anything it can’t do?&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;a-whole-new-world&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;A Whole New World&lt;/h2&gt;
&lt;p&gt;That ended up being a lot of background, glad to see you’re still with me. That’s
{dplyr} which can take either a &lt;code&gt;data.frame&lt;/code&gt; or a &lt;code&gt;tibble&lt;/code&gt; to do lots of useful
operations on data. If, like me prior to joining the world of computational
biology, you thought that was all there was to it, the next part comes as a bit of
an eye opener.&lt;/p&gt;
&lt;p&gt;Just like in a video game where all of a sudden the map is revealed to be twice as
large as you knew it, there’s an entire world of R packages beyond CRAN, mainly
targeted at computational biology/bioinformatics, known as &lt;a href=&#34;https://bioconductor.org/&#34;&gt;Bioconductor&lt;/a&gt;.
This is well supported by the R project itself, but you could spend your life
writing R analyses and never use it if you aren’t working on bioinfo stuff.&lt;/p&gt;
&lt;p&gt;I don’t think I’d used anything from Bioconductor before I joined a large biotech -
incidentally the one at which Robert Gentleman himself was a senior director in
bioinformatics and computational biology until just a couple of years before I
joined. Over the next few years, though, I’d become very familiar with the packages
on offer in that space.&lt;/p&gt;
&lt;p&gt;In the world of sequencing data, the humble &lt;code&gt;data.frame&lt;/code&gt; just doesn’t have the
right amount of structure - rectangular data is great, but no matter which way
you pivot (wide or long) you’re going to have some trouble representing all the
different qualities and quantities associated with a sample; for example representing
the level of expression of some gene for some samples belonging to some subject,
where both the subject and the sample have metadata, as does the experiment itself,
as do the genes. Keeping in mind that this might involve a thousand samples and
many tens of thousands of genes, a flat table just won’t cut it.&lt;/p&gt;
&lt;p&gt;A better option is to create a different structure, one which keeps the different
components (sample metadata, gene metadata) aligned and together, but not in the
same table. Several of these have evolved over time, but a current favourite of
the field is the &lt;code&gt;SummarizedExperiment&lt;/code&gt; structure. This organises the components
in a way that they can be stored and interrogated without having to perform a
dozen filters to get to the corner of data you’re interested in.&lt;/p&gt;
&lt;p&gt;If we think of this like a database, we have a table for the actual measurements,
another for the sample metadata, and another for the metadata on the things being
observed (e.g. genes). The problem is, we need to define keys that link the
different tables together. If our measurements were a giant matrix of values, e.g.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;expression_data &amp;lt;- matrix(c(2, 3, 1, 0, 9, 5, 3, 4, 5), ncol = 3)
expression_data&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3]
## [1,]    2    0    3
## [2,]    3    9    4
## [3,]    1    5    5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;how would we know that the second column is for sample_Y and the third row is
for gene_DEF? The matrix itself is numeric, so we can’t just add a new row/column
to store the sample/gene information, which is character.&lt;/p&gt;
&lt;p&gt;No points for guessing that the intro above was for a reason - those attributes
are now really useful.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(charcuterie)
rownames(expression_data) &amp;lt;- paste0(&amp;quot;gene_&amp;quot;, c(&amp;quot;ABC&amp;quot;, &amp;quot;DEF&amp;quot;, &amp;quot;GHI&amp;quot;))
colnames(expression_data) &amp;lt;- paste0(&amp;quot;sample_&amp;quot;, chars(&amp;quot;XYZ&amp;quot;))
expression_data&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##          sample_X sample_Y sample_Z
## gene_ABC        2        0        3
## gene_DEF        3        9        4
## gene_GHI        1        5        5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Much clearer! Even better, now we have a way to link up the metadata in either
dimension.&lt;/p&gt;
&lt;p&gt;For the samples, we can create a &lt;code&gt;data.frame&lt;/code&gt; with the relevant metadata for
each sample, and label each sample row with the relevant ID&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sample_metadata &amp;lt;- data.frame(name = c(&amp;quot;Jim&amp;quot;, &amp;quot;Jack&amp;quot;, &amp;quot;Joe&amp;quot;), age = c(51, 53, 52))
rownames(sample_metadata) &amp;lt;- paste0(&amp;quot;sample_&amp;quot;, chars(&amp;quot;XYZ&amp;quot;))
sample_metadata&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##          name age
## sample_X  Jim  51
## sample_Y Jack  53
## sample_Z  Joe  52&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can imagine taking this metadata and sort of turning it sideways so that
the labels align like interlocking puzzle pieces. These run across the columns,
so we can call them the “column data” of the final structure. Similarly, we can
do the same for the genes, perhaps annotating the chromosome they’re on, and
other identifiers, and use these as the “row data”.&lt;/p&gt;
&lt;p&gt;This is the basic structure of the &lt;code&gt;SummarizedExperiment&lt;/code&gt;, but all is not well.&lt;/p&gt;
&lt;p&gt;Bioconductor leans heavily into the S4 object model, making use of multiple
dispatch as well as object validation. For example, if I wanted to create a range
of fake genomic locations I could use&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;gr &amp;lt;- GenomicRanges::GRanges(&amp;quot;chrX&amp;quot;, IRanges::IRanges(1:6, width = 6:1))
gr&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## GRanges object with 6 ranges and 0 metadata columns:
##       seqnames    ranges strand
##          &amp;lt;Rle&amp;gt; &amp;lt;IRanges&amp;gt;  &amp;lt;Rle&amp;gt;
##   [1]     chrX       1-6      *
##   [2]     chrX       2-6      *
##   [3]     chrX       3-6      *
##   [4]     chrX       4-6      *
##   [5]     chrX       5-6      *
##   [6]     chrX         6      *
##   -------
##   seqinfo: 1 sequence from an unspecified genome; no seqlengths&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, and this is just a toy example, if I wanted to use some of these in a
&lt;code&gt;data.frame&lt;/code&gt;…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;d &amp;lt;- data.frame(a = 1:6, b = gr)
d&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   a b.seqnames b.start b.end b.width b.strand
## 1 1       chrX       1     6       6        *
## 2 2       chrX       2     6       5        *
## 3 3       chrX       3     6       4        *
## 4 4       chrX       4     6       3        *
## 5 5       chrX       5     6       2        *
## 6 6       chrX       6     6       1        *&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hmmm… it looks like it unfolded and did something strange. It was expecting a
vector, not … whatever &lt;code&gt;gr&lt;/code&gt; is.&lt;/p&gt;
&lt;p&gt;Not to worry, though - the Bioconductor ecosystem defines a &lt;code&gt;DataFrame&lt;/code&gt; object
that &lt;em&gt;does&lt;/em&gt; know how to deal with S4 classes just fine (there will be a lot of R
noise here, I can’t help that - lots of masking)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(S4Vectors)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Loading required package: stats4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Loading required package: BiocGenerics&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## 
## Attaching package: &amp;#39;BiocGenerics&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following objects are masked from &amp;#39;package:stats&amp;#39;:
## 
##     IQR, mad, sd, var, xtabs&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following objects are masked from &amp;#39;package:base&amp;#39;:
## 
##     anyDuplicated, aperm, append, as.data.frame, basename, cbind,
##     colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find,
##     get, grep, grepl, intersect, is.unsorted, lapply, Map, mapply,
##     match, mget, order, paste, pmax, pmax.int, pmin, pmin.int,
##     Position, rank, rbind, Reduce, rownames, sapply, setdiff, sort,
##     table, tapply, union, unique, unsplit, which.max, which.min&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## 
## Attaching package: &amp;#39;S4Vectors&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following object is masked from &amp;#39;package:utils&amp;#39;:
## 
##     findMatches&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following objects are masked from &amp;#39;package:base&amp;#39;:
## 
##     expand.grid, I, unname&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;DataFrame(a = 1:6, b = gr)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 6 rows and 2 columns
##           a         b
##   &amp;lt;integer&amp;gt; &amp;lt;GRanges&amp;gt;
## 1         1  chrX:1-6
## 2         2  chrX:2-6
## 3         3  chrX:3-6
## 4         4  chrX:4-6
## 5         5  chrX:5-6
## 6         6    chrX:6&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might say - “hey, that looks familiar! It’s kind of like a &lt;code&gt;tibble&lt;/code&gt;” and
you’re right; the &lt;em&gt;types&lt;/em&gt; of each column are shown at the top, and in the case
of the &lt;code&gt;GRanges&lt;/code&gt; object, it’s a non-atomic type, handled correctly. There’s
important differences compared to a &lt;code&gt;tibble&lt;/code&gt;, though. Importantly, we can add
row names to this just fine&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;DataFrame(a = 1:6, b = gr, row.names = paste0(&amp;quot;range&amp;quot;, 1:6))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 6 rows and 2 columns
##                a         b
##        &amp;lt;integer&amp;gt; &amp;lt;GRanges&amp;gt;
## range1         1  chrX:1-6
## range2         2  chrX:2-6
## range3         3  chrX:3-6
## range4         4  chrX:4-6
## range5         5  chrX:5-6
## range6         6    chrX:6&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we break the object, it will let us know because S4 performs object validation&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- DataFrame(x = 1:3, y = LETTERS[1:3])
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 3 rows and 2 columns
##           x           y
##   &amp;lt;integer&amp;gt; &amp;lt;character&amp;gt;
## 1         1           A
## 2         2           B
## 3         3           C&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;validObject(a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# look away, I&amp;#39;m not supposed to do this
names(a@listData) &amp;lt;- NULL
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 3 rows and 2 columns
##   c(&amp;quot;1&amp;quot;, &amp;quot;2&amp;quot;, &amp;quot;3&amp;quot;) c(&amp;quot;A&amp;quot;, &amp;quot;B&amp;quot;, &amp;quot;C&amp;quot;)
##          &amp;lt;integer&amp;gt;      &amp;lt;character&amp;gt;
## 1                1                A
## 2                2                B
## 3                3                C&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;validObject(a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in validObject(a): invalid class &amp;quot;DFrame&amp;quot; object: 
##     column names should not be NULL&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the right class for our sample metadata&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as(sample_metadata, &amp;quot;DataFrame&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 3 rows and 2 columns
##                 name       age
##          &amp;lt;character&amp;gt; &amp;lt;numeric&amp;gt;
## sample_X         Jim        51
## sample_Y        Jack        53
## sample_Z         Joe        52&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Perfect!&lt;/p&gt;
&lt;p&gt;If we look at an actual example of a &lt;code&gt;SummarizedExperiment&lt;/code&gt;, e.g. from the {airway}
package which captures read counts per gene for an airway smooth muscle cell lines
&lt;a href=&#34;https://en.wikipedia.org/wiki/RNA-Seq&#34;&gt;RNA-Seq&lt;/a&gt; experiment&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(&amp;quot;airway&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Loading required package: SummarizedExperiment&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Loading required package: MatrixGenerics&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Loading required package: matrixStats&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## 
## Attaching package: &amp;#39;MatrixGenerics&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following objects are masked from &amp;#39;package:matrixStats&amp;#39;:
## 
##     colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse,
##     colCounts, colCummaxs, colCummins, colCumprods, colCumsums,
##     colDiffs, colIQRDiffs, colIQRs, colLogSumExps, colMadDiffs,
##     colMads, colMaxs, colMeans2, colMedians, colMins, colOrderStats,
##     colProds, colQuantiles, colRanges, colRanks, colSdDiffs, colSds,
##     colSums2, colTabulates, colVarDiffs, colVars, colWeightedMads,
##     colWeightedMeans, colWeightedMedians, colWeightedSds,
##     colWeightedVars, rowAlls, rowAnyNAs, rowAnys, rowAvgsPerColSet,
##     rowCollapse, rowCounts, rowCummaxs, rowCummins, rowCumprods,
##     rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps,
##     rowMadDiffs, rowMads, rowMaxs, rowMeans2, rowMedians, rowMins,
##     rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks,
##     rowSdDiffs, rowSds, rowSums2, rowTabulates, rowVarDiffs, rowVars,
##     rowWeightedMads, rowWeightedMeans, rowWeightedMedians,
##     rowWeightedSds, rowWeightedVars&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Loading required package: GenomicRanges&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Loading required package: IRanges&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Loading required package: GenomeInfoDb&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Loading required package: Biobase&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Welcome to Bioconductor
## 
##     Vignettes contain introductory material; view with
##     &amp;#39;browseVignettes()&amp;#39;. To cite Bioconductor, see
##     &amp;#39;citation(&amp;quot;Biobase&amp;quot;)&amp;#39;, and for packages &amp;#39;citation(&amp;quot;pkgname&amp;quot;)&amp;#39;.&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## 
## Attaching package: &amp;#39;Biobase&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following object is masked from &amp;#39;package:MatrixGenerics&amp;#39;:
## 
##     rowMedians&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following objects are masked from &amp;#39;package:matrixStats&amp;#39;:
## 
##     anyMissing, rowMedians&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;data(&amp;quot;airway&amp;quot;)
se &amp;lt;- airway
se&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## class: RangedSummarizedExperiment 
## dim: 63677 8 
## metadata(1): &amp;#39;&amp;#39;
## assays(1): counts
## rownames(63677): ENSG00000000003 ENSG00000000005 ... ENSG00000273492
##   ENSG00000273493
## rowData names(10): gene_id gene_name ... seq_coord_system symbol
## colnames(8): SRR1039508 SRR1039509 ... SRR1039520 SRR1039521
## colData names(9): SampleName cell ... Sample BioSample&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;we see a lot of information - the “dimensions” of this object is 63677
genes measured for 8 samples. The ‘rownames’ element shows the IDs
of these genes which will link the ‘rowData’ to the counts assay rows, and the ‘colnames’
element shows the sample IDs which will link the ‘colData’ to the counts assay columns.&lt;/p&gt;
&lt;p&gt;Pulling this apart…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cd &amp;lt;- colData(se)
cd&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 8 rows and 9 columns
##            SampleName     cell      dex    albut        Run avgLength
##              &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt;   &amp;lt;factor&amp;gt; &amp;lt;integer&amp;gt;
## SRR1039508 GSM1275862  N61311     untrt    untrt SRR1039508       126
## SRR1039509 GSM1275863  N61311     trt      untrt SRR1039509       126
## SRR1039512 GSM1275866  N052611    untrt    untrt SRR1039512       126
## SRR1039513 GSM1275867  N052611    trt      untrt SRR1039513        87
## SRR1039516 GSM1275870  N080611    untrt    untrt SRR1039516       120
## SRR1039517 GSM1275871  N080611    trt      untrt SRR1039517       126
## SRR1039520 GSM1275874  N061011    untrt    untrt SRR1039520       101
## SRR1039521 GSM1275875  N061011    trt      untrt SRR1039521        98
##            Experiment    Sample    BioSample
##              &amp;lt;factor&amp;gt;  &amp;lt;factor&amp;gt;     &amp;lt;factor&amp;gt;
## SRR1039508  SRX384345 SRS508568 SAMN02422669
## SRR1039509  SRX384346 SRS508567 SAMN02422675
## SRR1039512  SRX384349 SRS508571 SAMN02422678
## SRR1039513  SRX384350 SRS508572 SAMN02422670
## SRR1039516  SRX384353 SRS508575 SAMN02422682
## SRR1039517  SRX384354 SRS508576 SAMN02422673
## SRR1039520  SRX384357 SRS508579 SAMN02422683
## SRR1039521  SRX384358 SRS508580 SAMN02422677&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;we see the sample metadata includes whether or not the sample was treated, and some
details about the experiment. Similarly, the gene metadata details the various IDs
and genomic locations.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;rowData(se)[1:3, ]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 3 rows and 10 columns
##                         gene_id   gene_name  entrezid   gene_biotype
##                     &amp;lt;character&amp;gt; &amp;lt;character&amp;gt; &amp;lt;integer&amp;gt;    &amp;lt;character&amp;gt;
## ENSG00000000003 ENSG00000000003      TSPAN6        NA protein_coding
## ENSG00000000005 ENSG00000000005        TNMD        NA protein_coding
## ENSG00000000419 ENSG00000000419        DPM1        NA protein_coding
##                 gene_seq_start gene_seq_end    seq_name seq_strand
##                      &amp;lt;integer&amp;gt;    &amp;lt;integer&amp;gt; &amp;lt;character&amp;gt;  &amp;lt;integer&amp;gt;
## ENSG00000000003       99883667     99894988           X         -1
## ENSG00000000005       99839799     99854882           X          1
## ENSG00000000419       49551404     49575092          20         -1
##                 seq_coord_system      symbol
##                        &amp;lt;integer&amp;gt; &amp;lt;character&amp;gt;
## ENSG00000000003               NA      TSPAN6
## ENSG00000000005               NA        TNMD
## ENSG00000000419               NA        DPM1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tying these together is the actual assay data&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;assay(se)[1:5, 1:5]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##                 SRR1039508 SRR1039509 SRR1039512 SRR1039513 SRR1039516
## ENSG00000000003        679        448        873        408       1138
## ENSG00000000005          0          0          0          0          0
## ENSG00000000419        467        515        621        365        587
## ENSG00000000457        260        211        263        164        245
## ENSG00000000460         60         55         40         35         78&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It all works really nicely - there are also additional places to store metadata
about the experiment shared across samples, and metadata about the columns themselves&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mcols(colData(se)) &amp;lt;- DataFrame(
  position = paste0(&amp;quot;column &amp;quot;, 1:9), 
  is_ID = c(TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE)
)
mcols(colData(se))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 9 rows and 2 columns
##               position     is_ID
##            &amp;lt;character&amp;gt; &amp;lt;logical&amp;gt;
## SampleName    column 1      TRUE
## cell          column 2      TRUE
## dex           column 3     FALSE
## albut         column 4     FALSE
## Run           column 5      TRUE
## avgLength     column 6     FALSE
## Experiment    column 7      TRUE
## Sample        column 8      TRUE
## BioSample     column 9      TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;filtering-a-dataframe&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Filtering a DataFrame&lt;/h2&gt;
&lt;p&gt;Now we get to a really interesting part - we want to do some analysis on this data.&lt;/p&gt;
&lt;p&gt;First, we want to look at the samples which were untreated. A &lt;code&gt;DataFrame&lt;/code&gt; uses the
same &lt;code&gt;[&lt;/code&gt; subsetting mechanism as a &lt;code&gt;data.frame&lt;/code&gt; so we could do&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cd[cd$dex == &amp;quot;untrt&amp;quot;, c(&amp;quot;SampleName&amp;quot;, &amp;quot;avgLength&amp;quot;)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 4 rows and 2 columns
##            SampleName avgLength
##              &amp;lt;factor&amp;gt; &amp;lt;integer&amp;gt;
## SRR1039508 GSM1275862       126
## SRR1039512 GSM1275866       126
## SRR1039516 GSM1275870       120
## SRR1039520 GSM1275874       101&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or even&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;subset(cd, dex == &amp;quot;untrt&amp;quot;, select = c(&amp;quot;SampleName&amp;quot;, &amp;quot;avgLength&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 4 rows and 2 columns
##            SampleName avgLength
##              &amp;lt;factor&amp;gt; &amp;lt;integer&amp;gt;
## SRR1039508 GSM1275862       126
## SRR1039512 GSM1275866       126
## SRR1039516 GSM1275870       120
## SRR1039520 GSM1275874       101&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and those work fine.&lt;/p&gt;
&lt;p&gt;What can often happen is you want the data for a specific sample. Sure, that ID
might be encoded in a column, but typically the sample identifiers are used as
the rownames of the &lt;code&gt;colData&lt;/code&gt;, so we can get the data for sample “SRR1039512” with&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cd[&amp;quot;SRR1039512&amp;quot;, ]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 1 row and 9 columns
##            SampleName     cell      dex    albut        Run avgLength
##              &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt;   &amp;lt;factor&amp;gt; &amp;lt;integer&amp;gt;
## SRR1039512 GSM1275866  N052611    untrt    untrt SRR1039512       126
##            Experiment    Sample    BioSample
##              &amp;lt;factor&amp;gt;  &amp;lt;factor&amp;gt;     &amp;lt;factor&amp;gt;
## SRR1039512  SRX384349 SRS508571 SAMN02422678&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What would be really nice, though, is to be able to use {dplyr}!&lt;/p&gt;
&lt;p&gt;Let’s try…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dplyr::filter(cd, dex == &amp;quot;untrt&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in UseMethod(&amp;quot;filter&amp;quot;): no applicable method for &amp;#39;filter&amp;#39; applied to an object of class &amp;quot;c(&amp;#39;DFrame&amp;#39;, &amp;#39;DataFrame&amp;#39;, &amp;#39;SimpleList&amp;#39;, &amp;#39;RectangularData&amp;#39;, &amp;#39;List&amp;#39;, &amp;#39;DataFrame_OR_NULL&amp;#39;, &amp;#39;Vector&amp;#39;, &amp;#39;list_OR_List&amp;#39;, &amp;#39;Annotated&amp;#39;, &amp;#39;vector_OR_Vector&amp;#39;)&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nope, it’s not defined for this class.&lt;/p&gt;
&lt;p&gt;One of the most frequent workarounds for this is to convert this &lt;code&gt;DataFrame&lt;/code&gt; to
a &lt;code&gt;tibble&lt;/code&gt;, at which point, yes, {dplyr} should work&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;tbl_untrt &amp;lt;- dplyr::filter(tibble::as_tibble(cd), dex == &amp;quot;untrt&amp;quot;)
tbl_untrt&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 4 × 9
##   SampleName cell    dex   albut Run       avgLength Experiment Sample BioSample
##   &amp;lt;fct&amp;gt;      &amp;lt;fct&amp;gt;   &amp;lt;fct&amp;gt; &amp;lt;fct&amp;gt; &amp;lt;fct&amp;gt;         &amp;lt;int&amp;gt; &amp;lt;fct&amp;gt;      &amp;lt;fct&amp;gt;  &amp;lt;fct&amp;gt;    
## 1 GSM1275862 N61311  untrt untrt SRR10395…       126 SRX384345  SRS50… SAMN0242…
## 2 GSM1275866 N052611 untrt untrt SRR10395…       126 SRX384349  SRS50… SAMN0242…
## 3 GSM1275870 N080611 untrt untrt SRR10395…       120 SRX384353  SRS50… SAMN0242…
## 4 GSM1275874 N061011 untrt untrt SRR10395…       101 SRX384357  SRS50… SAMN0242…&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That works, but there are two problems - both of them are that we now have a
&lt;code&gt;tibble&lt;/code&gt;, firstly because it now has no row names, and secondly, as a consequence,
we can’t “put it back” into the &lt;code&gt;SummarizedExperiment&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We have the same problem with the gene information - we &lt;em&gt;can&lt;/em&gt; convert to &lt;code&gt;tibble&lt;/code&gt;
and use {dplyr}, but we’re stuck there&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dplyr::filter(tibble::as_tibble(rowData(airway)), symbol == &amp;quot;CD38&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 1 × 10
##   gene_id   gene_name entrezid gene_biotype gene_seq_start gene_seq_end seq_name
##   &amp;lt;chr&amp;gt;     &amp;lt;chr&amp;gt;        &amp;lt;int&amp;gt; &amp;lt;chr&amp;gt;                 &amp;lt;int&amp;gt;        &amp;lt;int&amp;gt; &amp;lt;chr&amp;gt;   
## 1 ENSG0000… CD38            NA protein_cod…       15779898     15854853 4       
## # ℹ 3 more variables: seq_strand &amp;lt;int&amp;gt;, seq_coord_system &amp;lt;int&amp;gt;, symbol &amp;lt;chr&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Critically, &lt;code&gt;tibble&lt;/code&gt; suffers from the same lack of S4 support as regular &lt;code&gt;data.frame&lt;/code&gt;s,
so if there &lt;em&gt;are&lt;/em&gt; any of those columns, this workflow will break&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;d &amp;lt;- tibble::tibble(a = 1)
d&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 1 × 1
##       a
##   &amp;lt;dbl&amp;gt;
## 1     1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;d$grX &amp;lt;- GenomicRanges::GRanges(&amp;quot;chrX&amp;quot;, IRanges::IRanges(1:6, width = 6:1))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in `$&amp;lt;-`:
## ! Assigned data `GenomicRanges::GRanges(&amp;quot;chrX&amp;quot;, IRanges::IRanges(1:6,
##   width = 6:1))` must be a vector.
## Caused by error in `vec_size()`:
## ! `x` must be a vector, not a &amp;lt;GRanges&amp;gt; object.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What else can we do?&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;of-course-i-have-a-proposed-solution&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Of Course I Have a Proposed Solution&lt;/h2&gt;
&lt;p&gt;Let’s create a gnarly &lt;code&gt;DataFrame&lt;/code&gt; with S4 columns and row names&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m &amp;lt;- mtcars[, c(&amp;quot;cyl&amp;quot;, &amp;quot;hp&amp;quot;, &amp;quot;am&amp;quot;, &amp;quot;gear&amp;quot;, &amp;quot;disp&amp;quot;)]
d &amp;lt;- as(m, &amp;quot;DataFrame&amp;quot;)
d&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 32 rows and 5 columns
##                         cyl        hp        am      gear      disp
##                   &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt;
## Mazda RX4                 6       110         1         4       160
## Mazda RX4 Wag             6       110         1         4       160
## Datsun 710                4        93         1         4       108
## Hornet 4 Drive            6       110         0         3       258
## Hornet Sportabout         8       175         0         3       360
## ...                     ...       ...       ...       ...       ...
## Lotus Europa              4       113         1         5      95.1
## Ford Pantera L            8       264         1         5     351.0
## Ferrari Dino              6       175         1         5     145.0
## Maserati Bora             8       335         1         5     301.0
## Volvo 142E                4       109         1         4     121.0&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;d$grX &amp;lt;- GenomicRanges::GRanges(&amp;quot;chrX&amp;quot;, IRanges::IRanges(1:32, width=10))
d$grY &amp;lt;- GenomicRanges::GRanges(&amp;quot;chrY&amp;quot;, IRanges::IRanges(1:32, width = 10))
d$nl &amp;lt;- IRanges::NumericList(lapply(d$gear, function(n) round(rnorm(n), 2)))
d&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 32 rows and 8 columns
##                         cyl        hp        am      gear      disp        grX
##                   &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt;  &amp;lt;GRanges&amp;gt;
## Mazda RX4                 6       110         1         4       160  chrX:1-10
## Mazda RX4 Wag             6       110         1         4       160  chrX:2-11
## Datsun 710                4        93         1         4       108  chrX:3-12
## Hornet 4 Drive            6       110         0         3       258  chrX:4-13
## Hornet Sportabout         8       175         0         3       360  chrX:5-14
## ...                     ...       ...       ...       ...       ...        ...
## Lotus Europa              4       113         1         5      95.1 chrX:28-37
## Ford Pantera L            8       264         1         5     351.0 chrX:29-38
## Ferrari Dino              6       175         1         5     145.0 chrX:30-39
## Maserati Bora             8       335         1         5     301.0 chrX:31-40
## Volvo 142E                4       109         1         4     121.0 chrX:32-41
##                          grY                    nl
##                    &amp;lt;GRanges&amp;gt;         &amp;lt;NumericList&amp;gt;
## Mazda RX4          chrY:1-10    1.94,0.80,1.02,...
## Mazda RX4 Wag      chrY:2-11  0.90, 1.52,-0.46,...
## Datsun 710         chrY:3-12    1.64,0.47,0.66,...
## Hornet 4 Drive     chrY:4-13      0.06, 1.93,-1.11
## Hornet Sportabout  chrY:5-14     -1.01,-0.77,-0.04
## ...                      ...                   ...
## Lotus Europa      chrY:28-37 -0.22, 0.66,-1.10,...
## Ford Pantera L    chrY:29-38 -1.38, 0.74, 1.24,...
## Ferrari Dino      chrY:30-39 -0.81, 1.10, 0.85,...
## Maserati Bora     chrY:31-40    1.59,0.65,1.32,...
## Volvo 142E        chrY:32-41    1.07,0.78,0.00,...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and add some more metadata about the &lt;code&gt;colData&lt;/code&gt; columns&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mcols(colData(se)) &amp;lt;- DataFrame(
  position = paste0(&amp;quot;column &amp;quot;, 1:9), 
  is_ID = c(TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE)
)
mcols(colData(se))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 9 rows and 2 columns
##               position     is_ID
##            &amp;lt;character&amp;gt; &amp;lt;logical&amp;gt;
## SampleName    column 1      TRUE
## cell          column 2      TRUE
## dex           column 3     FALSE
## albut         column 4     FALSE
## Run           column 5      TRUE
## avgLength     column 6     FALSE
## Experiment    column 7      TRUE
## Sample        column 8      TRUE
## BioSample     column 9      TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My solution was to write the {dplyr} verbs in a way that was compatible with &lt;code&gt;DataFrame&lt;/code&gt;
but which avoids passing through a &lt;code&gt;tibble&lt;/code&gt; wherever possible. That became {DFplyr}
and it’s been sitting around &lt;a href=&#34;https://github.com/jonocarroll/DFplyr/&#34;&gt;on GitHub&lt;/a&gt;
not doing much for the last 5 years.&lt;/p&gt;
&lt;p&gt;I wrote a first version of this package despite being quite naive to the actual
implementation of &lt;code&gt;DataFrame&lt;/code&gt;, so I’m very grateful to Michael Lawrence and
Hervé Pagès who helped improve compatibility and pointed out bugs with what I’d
done.&lt;/p&gt;
&lt;p&gt;Time to take it for a tour&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(DFplyr)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Loading required package: dplyr&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## 
## Attaching package: &amp;#39;dplyr&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following object is masked from &amp;#39;package:Biobase&amp;#39;:
## 
##     combine&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following objects are masked from &amp;#39;package:GenomicRanges&amp;#39;:
## 
##     intersect, setdiff, union&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following object is masked from &amp;#39;package:GenomeInfoDb&amp;#39;:
## 
##     intersect&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following objects are masked from &amp;#39;package:IRanges&amp;#39;:
## 
##     collapse, desc, intersect, setdiff, slice, union&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following object is masked from &amp;#39;package:matrixStats&amp;#39;:
## 
##     count&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following objects are masked from &amp;#39;package:S4Vectors&amp;#39;:
## 
##     first, intersect, rename, setdiff, setequal, union&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following objects are masked from &amp;#39;package:BiocGenerics&amp;#39;:
## 
##     combine, intersect, setdiff, union&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following objects are masked from &amp;#39;package:stats&amp;#39;:
## 
##     filter, lag&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following objects are masked from &amp;#39;package:base&amp;#39;:
## 
##     intersect, setdiff, setequal, union&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-warning text-warning&#34;&gt;&lt;code&gt;## Warning: replacing previous import &amp;#39;S4Vectors::rename&amp;#39; by &amp;#39;dplyr::rename&amp;#39; when
## loading &amp;#39;DFplyr&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## 
## Attaching package: &amp;#39;DFplyr&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following objects are masked from &amp;#39;package:dplyr&amp;#39;:
## 
##     count, desc&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following objects are masked from &amp;#39;package:IRanges&amp;#39;:
## 
##     desc, slice&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following object is masked from &amp;#39;package:matrixStats&amp;#39;:
## 
##     count&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## The following object is masked from &amp;#39;package:stats&amp;#39;:
## 
##     filter&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;colData(se)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 8 rows and 9 columns
##            SampleName     cell      dex    albut        Run avgLength
##              &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt;   &amp;lt;factor&amp;gt; &amp;lt;integer&amp;gt;
## SRR1039508 GSM1275862  N61311     untrt    untrt SRR1039508       126
## SRR1039509 GSM1275863  N61311     trt      untrt SRR1039509       126
## SRR1039512 GSM1275866  N052611    untrt    untrt SRR1039512       126
## SRR1039513 GSM1275867  N052611    trt      untrt SRR1039513        87
## SRR1039516 GSM1275870  N080611    untrt    untrt SRR1039516       120
## SRR1039517 GSM1275871  N080611    trt      untrt SRR1039517       126
## SRR1039520 GSM1275874  N061011    untrt    untrt SRR1039520       101
## SRR1039521 GSM1275875  N061011    trt      untrt SRR1039521        98
##            Experiment    Sample    BioSample
##              &amp;lt;factor&amp;gt;  &amp;lt;factor&amp;gt;     &amp;lt;factor&amp;gt;
## SRR1039508  SRX384345 SRS508568 SAMN02422669
## SRR1039509  SRX384346 SRS508567 SAMN02422675
## SRR1039512  SRX384349 SRS508571 SAMN02422678
## SRR1039513  SRX384350 SRS508572 SAMN02422670
## SRR1039516  SRX384353 SRS508575 SAMN02422682
## SRR1039517  SRX384354 SRS508576 SAMN02422673
## SRR1039520  SRX384357 SRS508579 SAMN02422683
## SRR1039521  SRX384358 SRS508580 SAMN02422677&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cd &amp;lt;- colData(se) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One thing I added was a custom ‘label’ if you’re using this package within RStudio,
in which case the Environment pane will show &lt;code&gt;cd&lt;/code&gt; as “Formal class DataFrame (dplyr-compatible)”.
That’s not a change in the object itself, but rather all &lt;code&gt;DataFrame&lt;/code&gt; objects will
now show this, because {dplyr} verbs should work on them.&lt;/p&gt;
&lt;p&gt;Now I can just &lt;code&gt;filter&lt;/code&gt; the &lt;code&gt;colData&lt;/code&gt; as if it was a &lt;code&gt;data.frame&lt;/code&gt; or a &lt;code&gt;tibble&lt;/code&gt;,
but the result is still a &lt;code&gt;DataFrame&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;treated &amp;lt;- filter(cd, dex == &amp;quot;trt&amp;quot;)
treated&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 4 rows and 9 columns
##            SampleName     cell      dex    albut        Run avgLength
##              &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt;   &amp;lt;factor&amp;gt; &amp;lt;integer&amp;gt;
## SRR1039509 GSM1275863  N61311       trt    untrt SRR1039509       126
## SRR1039513 GSM1275867  N052611      trt    untrt SRR1039513        87
## SRR1039517 GSM1275871  N080611      trt    untrt SRR1039517       126
## SRR1039521 GSM1275875  N061011      trt    untrt SRR1039521        98
##            Experiment    Sample    BioSample
##              &amp;lt;factor&amp;gt;  &amp;lt;factor&amp;gt;     &amp;lt;factor&amp;gt;
## SRR1039509  SRX384346 SRS508567 SAMN02422675
## SRR1039513  SRX384350 SRS508572 SAMN02422670
## SRR1039517  SRX384354 SRS508576 SAMN02422673
## SRR1039521  SRX384358 SRS508580 SAMN02422677&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Importantly, the row names and metadata are completely preserved, relevant to
this filtered subset&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;rownames(treated)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;SRR1039509&amp;quot; &amp;quot;SRR1039513&amp;quot; &amp;quot;SRR1039517&amp;quot; &amp;quot;SRR1039521&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mcols(treated)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 9 rows and 2 columns
##               position     is_ID
##            &amp;lt;character&amp;gt; &amp;lt;logical&amp;gt;
## SampleName    column 1      TRUE
## cell          column 2      TRUE
## dex           column 3     FALSE
## albut         column 4     FALSE
## Run           column 5      TRUE
## avgLength     column 6     FALSE
## Experiment    column 7      TRUE
## Sample        column 8      TRUE
## BioSample     column 9      TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;exp &amp;lt;- select(cd, Experiment, Sample, BioSample)
exp&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 8 rows and 3 columns
##            Experiment    Sample    BioSample
##              &amp;lt;factor&amp;gt;  &amp;lt;factor&amp;gt;     &amp;lt;factor&amp;gt;
## SRR1039508  SRX384345 SRS508568 SAMN02422669
## SRR1039509  SRX384346 SRS508567 SAMN02422675
## SRR1039512  SRX384349 SRS508571 SAMN02422678
## SRR1039513  SRX384350 SRS508572 SAMN02422670
## SRR1039516  SRX384353 SRS508575 SAMN02422682
## SRR1039517  SRX384354 SRS508576 SAMN02422673
## SRR1039520  SRX384357 SRS508579 SAMN02422683
## SRR1039521  SRX384358 SRS508580 SAMN02422677&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mcols(exp)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 3 rows and 2 columns
##               position     is_ID
##            &amp;lt;character&amp;gt; &amp;lt;logical&amp;gt;
## Experiment    column 7      TRUE
## Sample        column 8      TRUE
## BioSample     column 9      TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can &lt;em&gt;add&lt;/em&gt; more sample data if I have it&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cdq &amp;lt;- mutate(cd, quality = runif(nrow(cd)))
cdq&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 8 rows and 10 columns
##            SampleName     cell      dex    albut        Run avgLength
##              &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt;   &amp;lt;factor&amp;gt; &amp;lt;integer&amp;gt;
## SRR1039508 GSM1275862  N61311     untrt    untrt SRR1039508       126
## SRR1039509 GSM1275863  N61311     trt      untrt SRR1039509       126
## SRR1039512 GSM1275866  N052611    untrt    untrt SRR1039512       126
## SRR1039513 GSM1275867  N052611    trt      untrt SRR1039513        87
## SRR1039516 GSM1275870  N080611    untrt    untrt SRR1039516       120
## SRR1039517 GSM1275871  N080611    trt      untrt SRR1039517       126
## SRR1039520 GSM1275874  N061011    untrt    untrt SRR1039520       101
## SRR1039521 GSM1275875  N061011    trt      untrt SRR1039521        98
##            Experiment    Sample    BioSample   quality
##              &amp;lt;factor&amp;gt;  &amp;lt;factor&amp;gt;     &amp;lt;factor&amp;gt; &amp;lt;numeric&amp;gt;
## SRR1039508  SRX384345 SRS508568 SAMN02422669  0.386436
## SRR1039509  SRX384346 SRS508567 SAMN02422675  0.566096
## SRR1039512  SRX384349 SRS508571 SAMN02422678  0.327839
## SRR1039513  SRX384350 SRS508572 SAMN02422670  0.744911
## SRR1039516  SRX384353 SRS508575 SAMN02422682  0.331616
## SRR1039517  SRX384354 SRS508576 SAMN02422673  0.728328
## SRR1039520  SRX384357 SRS508579 SAMN02422683  0.626803
## SRR1039521  SRX384358 SRS508580 SAMN02422677  0.248757&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mcols(cdq)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 10 rows and 2 columns
##               position     is_ID
##            &amp;lt;character&amp;gt; &amp;lt;logical&amp;gt;
## SampleName    column 1      TRUE
## cell          column 2      TRUE
## dex           column 3     FALSE
## albut         column 4     FALSE
## Run           column 5      TRUE
## avgLength     column 6     FALSE
## Experiment    column 7      TRUE
## Sample        column 8      TRUE
## BioSample     column 9      TRUE
## quality             NA        NA&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and since no metadata about this new column was available, it has a blank row in
the &lt;code&gt;mcols&lt;/code&gt; entry.&lt;/p&gt;
&lt;p&gt;If I perform an operation that doesn’t make sense in terms of row names, they &lt;em&gt;will&lt;/em&gt;
be removed&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cdq |&amp;gt; 
  group_by(dex) |&amp;gt; 
  summarise(avg_quality = mean(quality))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##     dex avg_quality
## 1   trt   0.5720231
## 2 untrt   0.4181736&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but rearranging them is fine&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cdq |&amp;gt; 
  arrange(desc(quality)) |&amp;gt; 
  slice(1:4)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 4 rows and 10 columns
##            SampleName     cell      dex    albut        Run avgLength
##              &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt;   &amp;lt;factor&amp;gt; &amp;lt;integer&amp;gt;
## SRR1039513 GSM1275867  N052611    trt      untrt SRR1039513        87
## SRR1039517 GSM1275871  N080611    trt      untrt SRR1039517       126
## SRR1039520 GSM1275874  N061011    untrt    untrt SRR1039520       101
## SRR1039509 GSM1275863  N61311     trt      untrt SRR1039509       126
##            Experiment    Sample    BioSample   quality
##              &amp;lt;factor&amp;gt;  &amp;lt;factor&amp;gt;     &amp;lt;factor&amp;gt; &amp;lt;numeric&amp;gt;
## SRR1039513  SRX384350 SRS508572 SAMN02422670  0.744911
## SRR1039517  SRX384354 SRS508576 SAMN02422673  0.728328
## SRR1039520  SRX384357 SRS508579 SAMN02422683  0.626803
## SRR1039509  SRX384346 SRS508567 SAMN02422675  0.566096&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One thing that &lt;code&gt;DataFrame&lt;/code&gt; lacks - as does &lt;code&gt;data.frame&lt;/code&gt; - is the concept of groups.
{tibble} resolved this by adding a &lt;code&gt;&#34;groups&#34;&lt;/code&gt; attribute, so I did the same in {DFplyr} -
I don’t own {S4Vectors}, so I had to mask some functions in order to build in this
support. I can now perform grouped operations on a &lt;code&gt;DataFrame&lt;/code&gt; and have the
grouping information printed like {tibble} does&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cd |&amp;gt; 
  group_by(dex) &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 8 rows and 9 columns
## Groups:  dex 
##            SampleName     cell      dex    albut        Run avgLength
##              &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt;   &amp;lt;factor&amp;gt; &amp;lt;integer&amp;gt;
## SRR1039508 GSM1275862  N61311     untrt    untrt SRR1039508       126
## SRR1039509 GSM1275863  N61311     trt      untrt SRR1039509       126
## SRR1039512 GSM1275866  N052611    untrt    untrt SRR1039512       126
## SRR1039513 GSM1275867  N052611    trt      untrt SRR1039513        87
## SRR1039516 GSM1275870  N080611    untrt    untrt SRR1039516       120
## SRR1039517 GSM1275871  N080611    trt      untrt SRR1039517       126
## SRR1039520 GSM1275874  N061011    untrt    untrt SRR1039520       101
## SRR1039521 GSM1275875  N061011    trt      untrt SRR1039521        98
##            Experiment    Sample    BioSample
##              &amp;lt;factor&amp;gt;  &amp;lt;factor&amp;gt;     &amp;lt;factor&amp;gt;
## SRR1039508  SRX384345 SRS508568 SAMN02422669
## SRR1039509  SRX384346 SRS508567 SAMN02422675
## SRR1039512  SRX384349 SRS508571 SAMN02422678
## SRR1039513  SRX384350 SRS508572 SAMN02422670
## SRR1039516  SRX384353 SRS508575 SAMN02422682
## SRR1039517  SRX384354 SRS508576 SAMN02422673
## SRR1039520  SRX384357 SRS508579 SAMN02422683
## SRR1039521  SRX384358 SRS508580 SAMN02422677&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cd |&amp;gt; 
  group_by(dex) |&amp;gt; 
  summarise(meanAvgLength = mean(avgLength))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##     dex meanAvgLength
## 1   trt        109.25
## 2 untrt        118.25&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I try to “put back” the subset &lt;code&gt;colData&lt;/code&gt; I get an error, because there is
assay data for samples we dropped&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;colData(se)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 8 rows and 9 columns
##            SampleName     cell      dex    albut        Run avgLength
##              &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt;   &amp;lt;factor&amp;gt; &amp;lt;integer&amp;gt;
## SRR1039508 GSM1275862  N61311     untrt    untrt SRR1039508       126
## SRR1039509 GSM1275863  N61311     trt      untrt SRR1039509       126
## SRR1039512 GSM1275866  N052611    untrt    untrt SRR1039512       126
## SRR1039513 GSM1275867  N052611    trt      untrt SRR1039513        87
## SRR1039516 GSM1275870  N080611    untrt    untrt SRR1039516       120
## SRR1039517 GSM1275871  N080611    trt      untrt SRR1039517       126
## SRR1039520 GSM1275874  N061011    untrt    untrt SRR1039520       101
## SRR1039521 GSM1275875  N061011    trt      untrt SRR1039521        98
##            Experiment    Sample    BioSample
##              &amp;lt;factor&amp;gt;  &amp;lt;factor&amp;gt;     &amp;lt;factor&amp;gt;
## SRR1039508  SRX384345 SRS508568 SAMN02422669
## SRR1039509  SRX384346 SRS508567 SAMN02422675
## SRR1039512  SRX384349 SRS508571 SAMN02422678
## SRR1039513  SRX384350 SRS508572 SAMN02422670
## SRR1039516  SRX384353 SRS508575 SAMN02422682
## SRR1039517  SRX384354 SRS508576 SAMN02422673
## SRR1039520  SRX384357 SRS508579 SAMN02422683
## SRR1039521  SRX384358 SRS508580 SAMN02422677&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;treated&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 4 rows and 9 columns
##            SampleName     cell      dex    albut        Run avgLength
##              &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt;   &amp;lt;factor&amp;gt; &amp;lt;integer&amp;gt;
## SRR1039509 GSM1275863  N61311       trt    untrt SRR1039509       126
## SRR1039513 GSM1275867  N052611      trt    untrt SRR1039513        87
## SRR1039517 GSM1275871  N080611      trt    untrt SRR1039517       126
## SRR1039521 GSM1275875  N061011      trt    untrt SRR1039521        98
##            Experiment    Sample    BioSample
##              &amp;lt;factor&amp;gt;  &amp;lt;factor&amp;gt;     &amp;lt;factor&amp;gt;
## SRR1039509  SRX384346 SRS508567 SAMN02422675
## SRR1039513  SRX384350 SRS508572 SAMN02422670
## SRR1039517  SRX384354 SRS508576 SAMN02422673
## SRR1039521  SRX384358 SRS508580 SAMN02422677&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;colData(se) &amp;lt;- treated&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in `colData&amp;lt;-`(`*tmp*`, value = new(&amp;quot;DFrame&amp;quot;, rownames = c(&amp;quot;SRR1039509&amp;quot;, : nrow of supplied &amp;#39;colData&amp;#39; must equal ncol of object&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But as long as I have some metadata for all the samples, it’s fine - &lt;code&gt;cdq&lt;/code&gt; was the
version of &lt;code&gt;colData&lt;/code&gt; with quality information, and you can see it’s incorporated
on the last line of this output&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;colData(se) &amp;lt;- cdq
se&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## class: RangedSummarizedExperiment 
## dim: 63677 8 
## metadata(1): &amp;#39;&amp;#39;
## assays(1): counts
## rownames(63677): ENSG00000000003 ENSG00000000005 ... ENSG00000273492
##   ENSG00000273493
## rowData names(10): gene_id gene_name ... seq_coord_system symbol
## colnames(8): SRR1039508 SRR1039509 ... SRR1039520 SRR1039521
## colData names(10): SampleName cell ... BioSample quality&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Storing S4 classes isn’t all we can do - performing {dplyr} operations on S4 columns
is perfectly fine; here, adding more S4 columns based on others&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;myrange &amp;lt;- GenomicRanges::GRanges(&amp;quot;chrX&amp;quot;, IRanges::IRanges(2:5, width = 10))

d &amp;lt;- mutate(d, quality = runif(32), overlaps = GenomicRanges::countOverlaps(grX, myrange))
d &amp;lt;- mutate(d, nearest = plyranges::join_nearest(grX, myrange))
d&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 32 rows and 11 columns
##                         cyl        hp        am      gear      disp        grX
##                   &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt;  &amp;lt;GRanges&amp;gt;
## Mazda RX4                 6       110         1         4       160  chrX:1-10
## Mazda RX4 Wag             6       110         1         4       160  chrX:2-11
## Datsun 710                4        93         1         4       108  chrX:3-12
## Hornet 4 Drive            6       110         0         3       258  chrX:4-13
## Hornet Sportabout         8       175         0         3       360  chrX:5-14
## ...                     ...       ...       ...       ...       ...        ...
## Lotus Europa              4       113         1         5      95.1 chrX:28-37
## Ford Pantera L            8       264         1         5     351.0 chrX:29-38
## Ferrari Dino              6       175         1         5     145.0 chrX:30-39
## Maserati Bora             8       335         1         5     301.0 chrX:31-40
## Volvo 142E                4       109         1         4     121.0 chrX:32-41
##                          grY                    nl  overlaps   quality
##                    &amp;lt;GRanges&amp;gt;         &amp;lt;NumericList&amp;gt; &amp;lt;integer&amp;gt; &amp;lt;numeric&amp;gt;
## Mazda RX4          chrY:1-10    1.94,0.80,1.02,...         4  0.144992
## Mazda RX4 Wag      chrY:2-11  0.90, 1.52,-0.46,...         4  0.726243
## Datsun 710         chrY:3-12    1.64,0.47,0.66,...         4  0.146000
## Hornet 4 Drive     chrY:4-13      0.06, 1.93,-1.11         4  0.695177
## Hornet Sportabout  chrY:5-14     -1.01,-0.77,-0.04         4  0.921556
## ...                      ...                   ...       ...       ...
## Lotus Europa      chrY:28-37 -0.22, 0.66,-1.10,...         0  0.371289
## Ford Pantera L    chrY:29-38 -1.38, 0.74, 1.24,...         0  0.420842
## Ferrari Dino      chrY:30-39 -0.81, 1.10, 0.85,...         0  0.890471
## Maserati Bora     chrY:31-40    1.59,0.65,1.32,...         0  0.395305
## Volvo 142E        chrY:32-41    1.07,0.78,0.00,...         0  0.532688
##                      nearest
##                    &amp;lt;GRanges&amp;gt;
## Mazda RX4          chrX:1-10
## Mazda RX4 Wag      chrX:2-11
## Datsun 710         chrX:3-12
## Hornet 4 Drive     chrX:4-13
## Hornet Sportabout  chrX:5-14
## ...                      ...
## Lotus Europa      chrX:28-37
## Ford Pantera L    chrX:29-38
## Ferrari Dino      chrX:30-39
## Maserati Bora     chrX:31-40
## Volvo 142E        chrX:32-41&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or filtering rows&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;d |&amp;gt; 
  arrange(desc(quality)) |&amp;gt; 
  filter(overlaps &amp;gt; 0) |&amp;gt; 
  slice(1:4)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 4 rows and 11 columns
##                         cyl        hp        am      gear      disp        grX
##                   &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt; &amp;lt;numeric&amp;gt;  &amp;lt;GRanges&amp;gt;
## Merc 280C                 6       123         0         4     167.6 chrX:11-20
## Merc 450SL                8       180         0         3     275.8 chrX:13-22
## Merc 450SE                8       180         0         3     275.8 chrX:12-21
## Hornet Sportabout         8       175         0         3     360.0  chrX:5-14
##                          grY                    nl  overlaps   quality
##                    &amp;lt;GRanges&amp;gt;         &amp;lt;NumericList&amp;gt; &amp;lt;integer&amp;gt; &amp;lt;numeric&amp;gt;
## Merc 280C         chrY:11-20 -0.08, 0.55,-0.59,...         4  0.990185
## Merc 450SL        chrY:13-22      1.23,-0.35, 0.04         2  0.979190
## Merc 450SE        chrY:12-21      2.60, 0.98,-1.50         3  0.958658
## Hornet Sportabout  chrY:5-14     -1.01,-0.77,-0.04         4  0.921556
##                      nearest
##                    &amp;lt;GRanges&amp;gt;
## Merc 280C         chrX:11-20
## Merc 450SL        chrX:13-22
## Merc 450SE        chrX:12-21
## Hornet Sportabout  chrX:5-14&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You don’t necessarily need to extract the &lt;code&gt;DataFrame&lt;/code&gt; into a variable, either -
working with the extraction directly could be cleaner in some cases&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;count(colData(se), cell)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 4 rows and 2 columns
##       cell         n
##   &amp;lt;factor&amp;gt; &amp;lt;integer&amp;gt;
## 1  N052611         2
## 2  N061011         2
## 3  N080611         2
## 4  N61311          2&lt;/code&gt;&lt;/pre&gt;
&lt;!-- ## Plotting --&gt;
&lt;!-- When I first wrote {DFplyr} a `DataFrame` wouldn&#39;t work in {ggplot2}, but it seems --&gt;
&lt;!-- it does now, so we can easily plot sample metadata --&gt;
&lt;!-- ```{r} --&gt;
&lt;!-- library(ggplot2) --&gt;
&lt;!-- ggplot(colData(airway), aes(dex, avgLength)) + --&gt;
&lt;!--   geom_boxplot() + --&gt;
&lt;!--   geom_point(aes(col = cell), position = position_jitter(width = 0.2), size = 4) --&gt;
&lt;!-- ``` --&gt;
&lt;!-- I suppose I can remove the support from {DFplyr} now. --&gt;
&lt;/div&gt;
&lt;div id=&#34;other-ways-to-filter&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Other Ways to Filter&lt;/h2&gt;
&lt;p&gt;Using {dplyr} syntax on a &lt;code&gt;DataFrame&lt;/code&gt; is very convenient, but that’s only one
component of a &lt;code&gt;SummarizedExperiment&lt;/code&gt; - it would be great to be able to extend
this further and do something like&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;filter(airway, rows = ..., cols = ...)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It &lt;em&gt;is&lt;/em&gt; possible to do something like this - if I generate IDs of the ‘rows’ and
‘columns’ I want to subset to, I can pass these in to a &lt;code&gt;[&lt;/code&gt; extraction&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;untrt &amp;lt;- colData(airway) |&amp;gt; filter(dex == &amp;quot;untrt&amp;quot;) |&amp;gt; rownames()
untrt&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;SRR1039508&amp;quot; &amp;quot;SRR1039512&amp;quot; &amp;quot;SRR1039516&amp;quot; &amp;quot;SRR1039520&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;genes &amp;lt;- rowData(airway)[c(1:3, 8:10), ] |&amp;gt; rownames()
genes&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;ENSG00000000003&amp;quot; &amp;quot;ENSG00000000005&amp;quot; &amp;quot;ENSG00000000419&amp;quot; &amp;quot;ENSG00000001036&amp;quot;
## [5] &amp;quot;ENSG00000001084&amp;quot; &amp;quot;ENSG00000001167&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;airway_sub &amp;lt;- airway[genes, untrt]
airway_sub&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## class: RangedSummarizedExperiment 
## dim: 6 4 
## metadata(1): &amp;#39;&amp;#39;
## assays(1): counts
## rownames(6): ENSG00000000003 ENSG00000000005 ... ENSG00000001084
##   ENSG00000001167
## rowData names(10): gene_id gene_name ... seq_coord_system symbol
## colnames(4): SRR1039508 SRR1039512 SRR1039516 SRR1039520
## colData names(9): SampleName cell ... Sample BioSample&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dim(airway_sub)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 6 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;colData(airway_sub)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 4 rows and 9 columns
##            SampleName     cell      dex    albut        Run avgLength
##              &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt; &amp;lt;factor&amp;gt;   &amp;lt;factor&amp;gt; &amp;lt;integer&amp;gt;
## SRR1039508 GSM1275862  N61311     untrt    untrt SRR1039508       126
## SRR1039512 GSM1275866  N052611    untrt    untrt SRR1039512       126
## SRR1039516 GSM1275870  N080611    untrt    untrt SRR1039516       120
## SRR1039520 GSM1275874  N061011    untrt    untrt SRR1039520       101
##            Experiment    Sample    BioSample
##              &amp;lt;factor&amp;gt;  &amp;lt;factor&amp;gt;     &amp;lt;factor&amp;gt;
## SRR1039508  SRX384345 SRS508568 SAMN02422669
## SRR1039512  SRX384349 SRS508571 SAMN02422678
## SRR1039516  SRX384353 SRS508575 SAMN02422682
## SRR1039520  SRX384357 SRS508579 SAMN02422683&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;rowData(airway_sub)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 6 rows and 10 columns
##                         gene_id   gene_name  entrezid   gene_biotype
##                     &amp;lt;character&amp;gt; &amp;lt;character&amp;gt; &amp;lt;integer&amp;gt;    &amp;lt;character&amp;gt;
## ENSG00000000003 ENSG00000000003      TSPAN6        NA protein_coding
## ENSG00000000005 ENSG00000000005        TNMD        NA protein_coding
## ENSG00000000419 ENSG00000000419        DPM1        NA protein_coding
## ENSG00000001036 ENSG00000001036       FUCA2        NA protein_coding
## ENSG00000001084 ENSG00000001084        GCLC        NA protein_coding
## ENSG00000001167 ENSG00000001167        NFYA        NA protein_coding
##                 gene_seq_start gene_seq_end    seq_name seq_strand
##                      &amp;lt;integer&amp;gt;    &amp;lt;integer&amp;gt; &amp;lt;character&amp;gt;  &amp;lt;integer&amp;gt;
## ENSG00000000003       99883667     99894988           X         -1
## ENSG00000000005       99839799     99854882           X          1
## ENSG00000000419       49551404     49575092          20         -1
## ENSG00000001036      143815948    143832827           6         -1
## ENSG00000001084       53362139     53481768           6         -1
## ENSG00000001167       41040684     41067715           6          1
##                 seq_coord_system      symbol
##                        &amp;lt;integer&amp;gt; &amp;lt;character&amp;gt;
## ENSG00000000003               NA      TSPAN6
## ENSG00000000005               NA        TNMD
## ENSG00000000419               NA        DPM1
## ENSG00000001036               NA       FUCA2
## ENSG00000001084               NA        GCLC
## ENSG00000001167               NA        NFYA&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that this new object now has only 6 genes and 4 samples (the original has
63677 genes and 8 samples).&lt;/p&gt;
&lt;p&gt;This sort of filtering is even nicer in &lt;code&gt;MultiAssayExperiment&lt;/code&gt; where multiple
&lt;code&gt;SummarizedExperiments&lt;/code&gt; (or similar objects) are aggregated into a super object
where the &lt;code&gt;colData&lt;/code&gt; may be relevant to samples which appear in multiple assays.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/mae.png&#34; alt=&#34;MultiAssayExperiment data layout&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;MultiAssayExperiment data layout&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;MultiAssayExperiment&lt;/code&gt; has some of the best written &lt;a href=&#34;https://bioconductor.org/packages/release/bioc/vignettes/MultiAssayExperiment/inst/doc/QuickStartMultiAssay.html&#34;&gt;vignettes&lt;/a&gt;
I’ve seen, and I thoroughly recommend reading them if you have any need to use
this format&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(MultiAssayExperiment)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(building the object not shown)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mae &amp;lt;- MultiAssayExperiment(experiments = ExpList, 
                            colData = colDat,
                            sampleMap = sampMap
)

mae&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## A MultiAssayExperiment object of 4 listed
##  experiments with user-defined names and respective classes.
##  Containing an ExperimentList class object of length 4:
##  [1] Affy: SummarizedExperiment with 5 rows and 4 columns
##  [2] Methyl450k: matrix with 5 rows and 5 columns
##  [3] RNASeqGene: matrix with 5 rows and 4 columns
##  [4] GISTIC: RangedSummarizedExperiment with 5 rows and 3 columns
## Functionality:
##  experiments() - obtain the ExperimentList instance
##  colData() - the primary/phenotype DataFrame
##  sampleMap() - the sample coordination DataFrame
##  `$`, `[`, `[[` - extract colData columns, subset, or experiment
##  *Format() - convert into a long or wide DataFrame
##  assays() - convert ExperimentList to a SimpleList of matrices
##  exportClass() - save data to flat files&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;colData(mae)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 4 rows and 2 columns
##                 sex       age
##         &amp;lt;character&amp;gt; &amp;lt;integer&amp;gt;
## Jack              M        38
## Jill              F        39
## Bob               M        40
## Barbara           F        41&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Subsetting the different dimensions (rows, columns, assays) can be done with the
following format&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;myMultiAssay[rows, columns, assays]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and since &lt;code&gt;mae$x&lt;/code&gt; is defined to extract a &lt;code&gt;colData&lt;/code&gt; column, I can subset this
object to measurements of two genes in any assay for just the male subjects&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mae[c(&amp;quot;ENST00000355076&amp;quot;, &amp;quot;ENST00000383323&amp;quot;), mae$sex == &amp;quot;M&amp;quot;, ]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## A MultiAssayExperiment object of 4 listed
##  experiments with user-defined names and respective classes.
##  Containing an ExperimentList class object of length 4:
##  [1] Affy: SummarizedExperiment with 2 rows and 2 columns
##  [2] Methyl450k: matrix with 2 rows and 3 columns
##  [3] RNASeqGene: matrix with 1 rows and 2 columns
##  [4] GISTIC: RangedSummarizedExperiment with 1 rows and 2 columns
## Functionality:
##  experiments() - obtain the ExperimentList instance
##  colData() - the primary/phenotype DataFrame
##  sampleMap() - the sample coordination DataFrame
##  `$`, `[`, `[[` - extract colData columns, subset, or experiment
##  *Format() - convert into a long or wide DataFrame
##  assays() - convert ExperimentList to a SimpleList of matrices
##  exportClass() - save data to flat files&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All of that brings us to the &lt;a href=&#34;https://tidyomics.com/&#34;&gt;tidyOmics&lt;/a&gt; project which
aims to create tidy analysis packages for omics data. One of the packages there
is &lt;code&gt;tidySummarizedExperiment&lt;/code&gt; which is a reframing of &lt;code&gt;SummarizedExperiment&lt;/code&gt; in
a ‘tidy’ sense&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# remotes::install_github(&amp;quot;stemangiola/tidySummarizedExperiment&amp;quot;)
tidySummarizedExperiment::pasilla&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A SummarizedExperiment-tibble abstraction: 102,193 × 5
## # Features=14599 | Samples=7 | Assays=counts
##    .feature    .sample counts condition type      
##    &amp;lt;chr&amp;gt;       &amp;lt;chr&amp;gt;    &amp;lt;int&amp;gt; &amp;lt;chr&amp;gt;     &amp;lt;chr&amp;gt;     
##  1 FBgn0000003 untrt1       0 untreated single_end
##  2 FBgn0000008 untrt1      92 untreated single_end
##  3 FBgn0000014 untrt1       5 untreated single_end
##  4 FBgn0000015 untrt1       0 untreated single_end
##  5 FBgn0000017 untrt1    4664 untreated single_end
##  6 FBgn0000018 untrt1     583 untreated single_end
##  7 FBgn0000022 untrt1       0 untreated single_end
##  8 FBgn0000024 untrt1      10 untreated single_end
##  9 FBgn0000028 untrt1       0 untreated single_end
## 10 FBgn0000032 untrt1    1446 untreated single_end
## # ℹ 40 more rows&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you’re already familiar with &lt;code&gt;MultiAssayExperiment&lt;/code&gt; then you may find this
somewhat familiar to the &lt;code&gt;longFormat&lt;/code&gt; output there&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;longFormat(mae)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## DataFrame with 80 rows and 5 columns
##           assay     primary         rowname     colname     value
##     &amp;lt;character&amp;gt; &amp;lt;character&amp;gt;     &amp;lt;character&amp;gt; &amp;lt;character&amp;gt; &amp;lt;numeric&amp;gt;
## 1          Affy        Jack ENST00000294241      array1       101
## 2          Affy        Jack ENST00000355076      array1       102
## 3          Affy        Jack ENST00000383706      array1       103
## 4          Affy        Jack ENST00000234812      array1       104
## 5          Affy        Jack ENST00000383323      array1       105
## ...         ...         ...             ...         ...       ...
## 76       GISTIC        Jill ENST00000135411       samp2         0
## 77       GISTIC        Jill ENST00000135412       samp2         1
## 78       GISTIC        Jill ENST00000135413       samp2         0
## 79       GISTIC        Jill ENST00000135414       samp2         1
## 80       GISTIC        Jill ENST00000383323       samp2         0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;summary&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That was a bit long winded, but I’ve been wanting to spell out my love for rownames
which comes from this Bioconductor approach for some time. {DFplyr} is a bit of a
mess internally, but I believe it has promise to be useful, so I’m interested in
use-cases, failure modes, etc… The tidyOmics project defines a lot of new structures
which need to interact with &lt;code&gt;DataFrame&lt;/code&gt;s and I’m reasonably sure that {DFplyr} can
help with that.&lt;/p&gt;
&lt;p&gt;If you have comments, suggestions, or improvements - or if you think {DFplyr} could
be useful to you, feel free to use the comment section below, or hit me up on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.3 (2024-02-29)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2024-08-11
##  pandoc   3.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package                  * version     date (UTC) lib source
##  abind                      1.4-5       2016-07-21 [1] CRAN (R 4.3.3)
##  airway                   * 1.22.0      2023-10-26 [1] Bioconductor
##  Biobase                  * 2.62.0      2023-10-24 [1] Bioconductor
##  BiocBaseUtils              1.4.0       2023-10-24 [1] Bioconductor
##  BiocGenerics             * 0.48.1      2023-11-01 [1] Bioconductor
##  BiocIO                     1.12.0      2023-10-24 [1] Bioconductor
##  BiocParallel               1.36.0      2023-10-24 [1] Bioconductor
##  Biostrings                 2.70.3      2024-03-13 [1] Bioconductor 3.18 (R 4.3.3)
##  bitops                     1.0-7       2021-04-24 [1] CRAN (R 4.3.2)
##  blogdown                   1.19        2024-02-01 [1] CRAN (R 4.3.3)
##  bookdown                   0.36        2023-10-16 [1] CRAN (R 4.3.2)
##  bslib                      0.6.1       2023-11-28 [3] CRAN (R 4.3.2)
##  cachem                     1.0.8       2023-05-01 [3] CRAN (R 4.3.0)
##  callr                      3.7.3       2022-11-02 [3] CRAN (R 4.2.2)
##  charcuterie              * 0.0.2       2024-08-07 [1] local
##  cli                        3.6.1       2023-03-23 [1] CRAN (R 4.3.3)
##  codetools                  0.2-19      2023-02-01 [4] CRAN (R 4.2.2)
##  colorspace                 2.1-0       2023-01-23 [1] CRAN (R 4.3.3)
##  crayon                     1.5.2       2022-09-29 [3] CRAN (R 4.2.1)
##  data.table                 1.15.0      2024-01-30 [3] CRAN (R 4.3.2)
##  DelayedArray               0.28.0      2023-10-24 [1] Bioconductor
##  devtools                   2.4.5       2022-10-11 [1] CRAN (R 4.3.2)
##  DFplyr                   * 0.0.1.9000  2024-08-11 [1] local
##  digest                     0.6.34      2024-01-11 [3] CRAN (R 4.3.2)
##  dplyr                    * 1.1.4       2023-11-17 [3] CRAN (R 4.3.2)
##  ellipsis                   0.3.2       2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate                   0.23        2023-11-01 [3] CRAN (R 4.3.2)
##  fansi                      1.0.6       2023-12-08 [1] CRAN (R 4.3.3)
##  fastmap                    1.1.1       2023-02-24 [3] CRAN (R 4.2.2)
##  fs                         1.6.3       2023-07-20 [3] CRAN (R 4.3.1)
##  generics                   0.1.3       2022-07-05 [3] CRAN (R 4.2.1)
##  GenomeInfoDb             * 1.38.8      2024-03-15 [1] Bioconductor 3.18 (R 4.3.3)
##  GenomeInfoDbData           1.2.11      2024-06-21 [1] Bioconductor
##  GenomicAlignments          1.38.2      2024-01-16 [1] Bioconductor 3.18 (R 4.3.3)
##  GenomicRanges            * 1.54.1      2023-10-29 [1] Bioconductor
##  ggplot2                    3.5.1       2024-04-23 [1] CRAN (R 4.3.3)
##  glue                       1.7.0       2024-01-09 [1] CRAN (R 4.3.3)
##  gtable                     0.3.5       2024-04-22 [1] CRAN (R 4.3.3)
##  htmltools                  0.5.7       2023-11-03 [3] CRAN (R 4.3.2)
##  htmlwidgets                1.6.2       2023-03-17 [1] CRAN (R 4.3.2)
##  httpuv                     1.6.12      2023-10-23 [1] CRAN (R 4.3.2)
##  httr                       1.4.7       2023-08-15 [3] CRAN (R 4.3.1)
##  icecream                   0.2.1       2023-09-27 [1] CRAN (R 4.3.2)
##  IRanges                  * 2.36.0      2023-10-24 [1] Bioconductor
##  jquerylib                  0.1.4       2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite                   1.8.8       2023-12-04 [3] CRAN (R 4.3.2)
##  knitr                      1.45        2023-10-30 [3] CRAN (R 4.3.2)
##  later                      1.3.1       2023-05-02 [1] CRAN (R 4.3.2)
##  lattice                    0.22-5      2023-10-24 [4] CRAN (R 4.3.1)
##  lazyeval                   0.2.2       2019-03-15 [1] CRAN (R 4.3.2)
##  lifecycle                  1.0.4       2023-11-07 [1] CRAN (R 4.3.3)
##  magrittr                   2.0.3       2022-03-30 [1] CRAN (R 4.3.3)
##  Matrix                     1.6-5       2024-01-11 [4] CRAN (R 4.3.3)
##  MatrixGenerics           * 1.14.0      2023-10-24 [1] Bioconductor
##  matrixStats              * 1.1.0       2023-11-07 [1] CRAN (R 4.3.2)
##  memoise                    2.0.1       2021-11-26 [3] CRAN (R 4.2.0)
##  mime                       0.12        2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI                     0.1.1.1     2018-05-18 [1] CRAN (R 4.3.2)
##  MultiAssayExperiment     * 1.28.0      2023-10-24 [1] Bioconductor
##  munsell                    0.5.1       2024-04-01 [1] CRAN (R 4.3.3)
##  pillar                     1.9.0       2023-03-22 [1] CRAN (R 4.3.3)
##  pkgbuild                   1.4.2       2023-06-26 [1] CRAN (R 4.3.2)
##  pkgconfig                  2.0.3       2019-09-22 [1] CRAN (R 4.3.3)
##  pkgload                    1.3.3       2023-09-22 [1] CRAN (R 4.3.2)
##  plotly                     4.10.4      2024-01-13 [1] CRAN (R 4.3.3)
##  plyranges                  1.22.0      2023-10-24 [1] Bioconductor
##  prettyunits                1.2.0       2023-09-24 [3] CRAN (R 4.3.1)
##  processx                   3.8.3       2023-12-10 [3] CRAN (R 4.3.2)
##  profvis                    0.3.8       2023-05-02 [1] CRAN (R 4.3.2)
##  promises                   1.2.1       2023-08-10 [1] CRAN (R 4.3.2)
##  ps                         1.7.6       2024-01-18 [3] CRAN (R 4.3.2)
##  purrr                      1.0.2       2023-08-10 [3] CRAN (R 4.3.1)
##  R6                         2.5.1       2021-08-19 [1] CRAN (R 4.3.3)
##  Rcpp                       1.0.11      2023-07-06 [1] CRAN (R 4.3.2)
##  RCurl                      1.98-1.14   2024-01-09 [1] CRAN (R 4.3.3)
##  remotes                    2.4.2.1     2023-07-18 [1] CRAN (R 4.3.2)
##  restfulr                   0.0.15      2022-06-16 [1] CRAN (R 4.3.3)
##  rjson                      0.2.21      2022-01-09 [1] CRAN (R 4.3.3)
##  rlang                      1.1.4       2024-06-04 [1] CRAN (R 4.3.3)
##  rmarkdown                  2.25        2023-09-18 [3] CRAN (R 4.3.1)
##  Rsamtools                  2.18.0      2023-10-24 [1] Bioconductor
##  rstudioapi                 0.15.0      2023-07-07 [3] CRAN (R 4.3.1)
##  rtracklayer                1.62.0      2023-10-24 [1] Bioconductor
##  S4Arrays                   1.2.1       2024-03-04 [1] Bioconductor 3.18 (R 4.3.3)
##  S4Vectors                * 0.40.2      2023-11-23 [1] Bioconductor 3.18 (R 4.3.3)
##  sass                       0.4.8       2023-12-06 [3] CRAN (R 4.3.2)
##  scales                     1.3.0       2023-11-28 [1] CRAN (R 4.3.2)
##  sessioninfo                1.2.2       2021-12-06 [1] CRAN (R 4.3.2)
##  shiny                      1.7.5.1     2023-10-14 [1] CRAN (R 4.3.2)
##  SparseArray                1.2.4       2024-02-11 [1] Bioconductor 3.18 (R 4.3.3)
##  stringi                    1.8.3       2023-12-11 [3] CRAN (R 4.3.2)
##  stringr                    1.5.1       2023-11-14 [3] CRAN (R 4.3.2)
##  SummarizedExperiment     * 1.32.0      2023-10-24 [1] Bioconductor
##  tibble                     3.2.1       2023-03-20 [1] CRAN (R 4.3.3)
##  tidyr                      1.3.1       2024-01-24 [3] CRAN (R 4.3.2)
##  tidyselect                 1.2.0       2022-10-10 [3] CRAN (R 4.2.1)
##  tidySummarizedExperiment   1.15.1      2024-08-06 [1] Github (stemangiola/tidySummarizedExperiment@4b8a4e1)
##  ttservice                  0.4.1       2024-06-07 [1] CRAN (R 4.3.3)
##  urlchecker                 1.0.1       2021-11-30 [1] CRAN (R 4.3.2)
##  usethis                    3.0.0       2024-07-29 [1] CRAN (R 4.3.3)
##  utf8                       1.2.4       2023-10-22 [1] CRAN (R 4.3.3)
##  vctrs                      0.6.5       2023-12-01 [1] CRAN (R 4.3.3)
##  viridisLite                0.4.2       2023-05-02 [1] CRAN (R 4.3.3)
##  withr                      3.0.0       2024-01-16 [1] CRAN (R 4.3.3)
##  xfun                       0.41        2023-11-01 [3] CRAN (R 4.3.2)
##  XML                        3.99-0.16.1 2024-01-22 [1] CRAN (R 4.3.3)
##  xtable                     1.8-4       2019-04-21 [1] CRAN (R 4.3.2)
##  XVector                    0.42.0      2023-10-24 [1] Bioconductor
##  yaml                       2.3.8       2023-12-11 [3] CRAN (R 4.3.2)
##  zlibbioc                   1.48.2      2024-03-13 [1] Bioconductor 3.18 (R 4.3.3)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>{charcuterie} - What if Strings Were Iterable in R?</title>
      <link>https://jcarroll.com.au/2024/08/03/charcuterie-what-if-strings-were-iterable-in-r/</link>
      <pubDate>Sat, 03 Aug 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/08/03/charcuterie-what-if-strings-were-iterable-in-r/</guid>
      <description>&lt;p&gt;I’ve been using a lot of programming languages recently and they all have their
quirks, differentiating features, and unique qualities, but one thing most of
them have is that they handle strings as a collection of characters. R doesn’t,
it has a “character” type which is 0 or more characters, and that’s what we call
a “string”, but what if it &lt;em&gt;did&lt;/em&gt; have iterable strings?&lt;/p&gt;
&lt;p&gt;For comparison, here’s some Python code&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;for i in &amp;quot;string&amp;quot;:
    print(i)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;s
t
r
i
n
g&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and some Haskell&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;upperA = map (\c -&amp;gt; if c == &amp;#39;a&amp;#39; then &amp;#39;A&amp;#39; else c)
upperA &amp;quot;banana&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;&amp;quot;bAnAnA&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and some Julia&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;[x+1 for x in &amp;quot;HAL&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;3-element Vector{Char}:
 &amp;#39;I&amp;#39;: ASCII/Unicode U+0049 (category Lu: Letter, uppercase)
 &amp;#39;B&amp;#39;: ASCII/Unicode U+0042 (category Lu: Letter, uppercase)
 &amp;#39;M&amp;#39;: ASCII/Unicode U+004D (category Lu: Letter, uppercase)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In each of these cases the string is treated as a collection of individual
characters. Many languages make this distinction, going so far as using different
quotes to distinguish them; e.g. double quotes for strings &lt;code&gt;&#34;string&#34;&lt;/code&gt; and single
quotes for individual characters &lt;code&gt;&#39;s&#39;&lt;/code&gt;. This makes a even more sense when the
language supports &lt;em&gt;types&lt;/em&gt; in that a string has a &lt;code&gt;String&lt;/code&gt; type that is composed
of 0 or more &lt;code&gt;Char&lt;/code&gt; types.&lt;/p&gt;
&lt;p&gt;R is dynamically typed, so we don’t strictly enforce type signatures, and is an
array language, so it has natural support for arrays (vectors, lists, matrices).
So why are strings not collections of characters?&lt;/p&gt;
&lt;p&gt;My guess is that for the majority of use-cases, it wasn’t necessary - a lot of
the time when we read in text data we want the entirety of the string and don’t
want to worry about dealing with a collection on top of the collection of strings
themselves. Plus, if you really need the individual characters you can split the
text up with &lt;code&gt;strsplit(x, &#34;&#34;)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But if you &lt;em&gt;do&lt;/em&gt; want to work with individual characters, calling
&lt;code&gt;strsplit(x, &#34;&#34;)[[1]]&lt;/code&gt; throughout your code gets ugly. I solved the Exercism
problem ‘Anagram’ in R and really didn’t like &lt;a href=&#34;https://exercism.org/tracks/r/exercises/anagram/solutions/jonocarroll&#34;&gt;how it looked&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;anagram &amp;lt;- function(subject, candidates) {
  # remove any same words and inconsistent lengths
  nonsames &amp;lt;- candidates[tolower(candidates) != tolower(subject) &amp;amp; 
                           nchar(subject) == nchar(candidates)]
  if (!length(nonsames)) return(c()) # no remaining candidates
  s_letters &amp;lt;- sort(tolower(strsplit(subject, &amp;quot;&amp;quot;)[[1]]))
  c_letters &amp;lt;- sapply(sapply(nonsames, \(x) strsplit(x, &amp;quot;&amp;quot;)), sort, simplify = FALSE)
  # find all cases where the letters are all the same
  anagrams &amp;lt;- nonsames[sapply(c_letters, \(x) all(s_letters == tolower(x)))]
  # if none found, return NULL
  if(!length(anagrams)) NULL else anagrams
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two calls to &lt;code&gt;strsplit&lt;/code&gt;, then needing to &lt;code&gt;sapply&lt;/code&gt; over that collection to sort it…
not pretty at all. Here’s &lt;a href=&#34;https://exercism.org/tracks/haskell/exercises/anagram/solutions/jontra&#34;&gt;a Haskell solution&lt;/a&gt;
from someone very knowledgeable in our local functional programming Meetup group&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;import Data.List (sort)
import Data.Char (toLower)
anagramsFor :: String -&amp;gt; [String] -&amp;gt; [String]
anagramsFor xs = filter (isAnagram xs&amp;#39; . map toLower)
  where xs&amp;#39; = map toLower xs
isAnagram :: String -&amp;gt; String -&amp;gt; Bool
isAnagram a b
  | a == b = False
  | otherwise = sort a == sort b&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which, excluding the type declarations and the fact that it needs to deal with
the edge case that it &lt;em&gt;has to be&lt;/em&gt; a rearrangement, could nearly be a one-liner&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;import Data.List (sort)
import Data.Char (toLower)
isAnagram a b = sort (map toLower a) == sort (map toLower b)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wouldn’t it be nice if we could do things like this in R?&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/iterablestrings.jpg&#34; alt=&#34;The world if R had iterable strings&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;The world if R had iterable strings&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I don’t expect it would ever happen (maaaybe via some special string handling
like the bare strings &lt;code&gt;r&#34;(this doesn&#39;t need escaping)&#34;&lt;/code&gt; but unlikely). I
couldn’t find a package that did this (by all means, let me know if there &lt;em&gt;is&lt;/em&gt;
one) so I decided to build it myself and see how it could work.&lt;/p&gt;
&lt;p&gt;Introducing &lt;a href=&#34;https://github.com/jonocarroll/charcuterie&#34;&gt;{charcuterie}&lt;/a&gt; - named
partly because it looks like “cut” “char”, and partly because of charcuterie boards
involving lots of little bits of appetizers.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/charcuterie_small.jpeg&#34; alt=&#34;image by Google gemini&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;image by Google gemini&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(charcuterie)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At its core, this is just defining &lt;code&gt;chars(x)&lt;/code&gt; as &lt;code&gt;strsplit(x, &#34;&#34;)[[1]]&lt;/code&gt; and
slapping a new class on the output, but big improvements don’t immediately come
from moonshots, they come from incremental improvements. Once I had this, I wanted
to do things with it like sort the individual characters. There is of course a
sort method for vectors (but not for individual strings) so&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sort(&amp;quot;string&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;string&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sort(c(&amp;quot;s&amp;quot;, &amp;quot;t&amp;quot;, &amp;quot;r&amp;quot;, &amp;quot;i&amp;quot;, &amp;quot;n&amp;quot;, &amp;quot;g&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;g&amp;quot; &amp;quot;i&amp;quot; &amp;quot;n&amp;quot; &amp;quot;r&amp;quot; &amp;quot;s&amp;quot; &amp;quot;t&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One aspect of treating strings as collections of characters is that they should
&lt;em&gt;always&lt;/em&gt; look like strings, so I needed to modify the sort method to return an
object of this new class, and make this class display collections of characters
as a string. That just involves pasting the characters back together for printing,
so now I can have this&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;s &amp;lt;- chars(&amp;quot;string&amp;quot;)
s&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;string&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sort(s)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;ginrst&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It &lt;em&gt;looks&lt;/em&gt; like a string, but it behaves like a collection of characters!&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/doright.jpg&#34; alt=&#34;When you do things right, people won’t know you’ve done anything at all&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;When you do things right, people won’t know you’ve done anything at all&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I thought about what other operations I might want to do and now I have methods to&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sort with &lt;code&gt;sort&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;reverse with &lt;code&gt;rev&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;index with &lt;code&gt;[&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;concatenate with &lt;code&gt;c&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;print with &lt;code&gt;format&lt;/code&gt; and &lt;code&gt;print&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;slice with &lt;code&gt;head&lt;/code&gt; and &lt;code&gt;tail&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;set operations with &lt;code&gt;setdiff&lt;/code&gt;, &lt;code&gt;union&lt;/code&gt;, &lt;code&gt;intersect&lt;/code&gt;, and a new &lt;code&gt;except&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;leverage existing vectorised operations like &lt;code&gt;unique&lt;/code&gt;, &lt;code&gt;toupper&lt;/code&gt;, and &lt;code&gt;tolower&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I suspect the concatenation will be the one that raises the most eyebrows… I’ve
dealt with the way that other languages join together strings &lt;a href=&#34;https://jcarroll.com.au/2018/10/06/adding-strings-in-r/&#34;&gt;before&lt;/a&gt;
and I’m certainly open to what this version &lt;em&gt;should&lt;/em&gt; do, but I think it makes
sense to add the collections as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;c(chars(&amp;quot;butter&amp;quot;), chars(&amp;quot;fly&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;butterfly&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you need more than one &lt;code&gt;chars&lt;/code&gt; at a time, you’re asking for a vector of vectors,
which R doesn’t support - it supports a &lt;em&gt;list&lt;/em&gt; of them, though&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- lapply(c(&amp;quot;butter&amp;quot;, &amp;quot;fly&amp;quot;), chars)
x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [[1]]
## [1] &amp;quot;butter&amp;quot;
## 
## [[2]]
## [1] &amp;quot;fly&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;unclass(x[[2]])&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;f&amp;quot; &amp;quot;l&amp;quot; &amp;quot;y&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This still sounds simple, and it is - the point is that it feels a lot more
ergonomic to use this inside a function compared to &lt;code&gt;strsplit(x, &#34;&#34;)[[1]]&lt;/code&gt; and
working with the collection manually.&lt;/p&gt;
&lt;p&gt;I added an entire vignette of examples to the package, including identifying vowels&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;vowels &amp;lt;- function(word) {
  ch &amp;lt;- chars(word)
  setNames(ch %in% chars(&amp;quot;aeiou&amp;quot;), ch)
}
vowels(&amp;quot;string&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##     s     t     r     i     n     g 
## FALSE FALSE FALSE  TRUE FALSE FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;vowels(&amp;quot;banana&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##     b     a     n     a     n     a 
## FALSE  TRUE FALSE  TRUE FALSE  TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;palindromes&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;palindrome &amp;lt;- function(a, ignore_spaces = FALSE) {
  a &amp;lt;- chars(a)
  if (ignore_spaces) a &amp;lt;- except(a, &amp;quot; &amp;quot;)
  all(rev(a) == a)
}
palindrome(&amp;quot;palindrome&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;palindrome(&amp;quot;racecar&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;palindrome(&amp;quot;never odd or even&amp;quot;, ignore_spaces = TRUE)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and performing character-level substitutions&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;spongebob &amp;lt;- function(phrase) {
  x &amp;lt;- chars(phrase)
  odds &amp;lt;- seq(1, length(x), 2)
  x[odds] &amp;lt;- toupper(x[odds])
  string(x)
}
spongebob(&amp;quot;you can&amp;#39;t do anything useful with this package&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;YoU CaN&amp;#39;T Do aNyThInG UsEfUl wItH ThIs pAcKaGe&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/spongebob.jpg&#34; alt=&#34;YoU CaN’T Do aNyThInG UsEfUl wItH ThIs pAcKaGe&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;YoU CaN’T Do aNyThInG UsEfUl wItH ThIs pAcKaGe&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;On top of all that, I felt it was worthwhile stretching my R package building
muscles, so I’ve added tests with 100% coverage, and ensured it fully passes
&lt;code&gt;check()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I don’t expect this would be used on huge text sources, but it’s useful to me
for silly little projects. If you have any suggestions for functionality that
could extend this then by all means let me know either in
&lt;a href=&#34;https://github.com/jonocarroll/charcuterie/issues&#34;&gt;GitHub Issues&lt;/a&gt;, the comment section
below, or &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.3 (2024-02-29)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2024-08-03
##  pandoc   3.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version    date (UTC) lib source
##  blogdown      1.18       2023-06-19 [1] CRAN (R 4.3.2)
##  bookdown      0.36       2023-10-16 [1] CRAN (R 4.3.2)
##  bslib         0.6.1      2023-11-28 [3] CRAN (R 4.3.2)
##  cachem        1.0.8      2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3      2022-11-02 [3] CRAN (R 4.2.2)
##  charcuterie * 0.0.0.9000 2024-08-03 [1] local
##  cli           3.6.1      2023-03-23 [1] CRAN (R 4.3.3)
##  crayon        1.5.2      2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5      2022-10-11 [1] CRAN (R 4.3.2)
##  digest        0.6.34     2024-01-11 [3] CRAN (R 4.3.2)
##  ellipsis      0.3.2      2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.23       2023-11-01 [3] CRAN (R 4.3.2)
##  fastmap       1.1.1      2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3      2023-07-20 [3] CRAN (R 4.3.1)
##  glue          1.7.0      2024-01-09 [1] CRAN (R 4.3.3)
##  htmltools     0.5.7      2023-11-03 [3] CRAN (R 4.3.2)
##  htmlwidgets   1.6.2      2023-03-17 [1] CRAN (R 4.3.2)
##  httpuv        1.6.12     2023-10-23 [1] CRAN (R 4.3.2)
##  icecream      0.2.1      2023-09-27 [1] CRAN (R 4.3.2)
##  jquerylib     0.1.4      2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.8      2023-12-04 [3] CRAN (R 4.3.2)
##  knitr         1.45       2023-10-30 [3] CRAN (R 4.3.2)
##  later         1.3.1      2023-05-02 [1] CRAN (R 4.3.2)
##  lifecycle     1.0.4      2023-11-07 [1] CRAN (R 4.3.3)
##  magrittr      2.0.3      2022-03-30 [1] CRAN (R 4.3.3)
##  memoise       2.0.1      2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12       2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1    2018-05-18 [1] CRAN (R 4.3.2)
##  pkgbuild      1.4.2      2023-06-26 [1] CRAN (R 4.3.2)
##  pkgload       1.3.3      2023-09-22 [1] CRAN (R 4.3.2)
##  prettyunits   1.2.0      2023-09-24 [3] CRAN (R 4.3.1)
##  processx      3.8.3      2023-12-10 [3] CRAN (R 4.3.2)
##  profvis       0.3.8      2023-05-02 [1] CRAN (R 4.3.2)
##  promises      1.2.1      2023-08-10 [1] CRAN (R 4.3.2)
##  ps            1.7.6      2024-01-18 [3] CRAN (R 4.3.2)
##  purrr         1.0.2      2023-08-10 [3] CRAN (R 4.3.1)
##  R6            2.5.1      2021-08-19 [1] CRAN (R 4.3.3)
##  Rcpp          1.0.11     2023-07-06 [1] CRAN (R 4.3.2)
##  remotes       2.4.2.1    2023-07-18 [1] CRAN (R 4.3.2)
##  rlang         1.1.4      2024-06-04 [1] CRAN (R 4.3.3)
##  rmarkdown     2.25       2023-09-18 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0     2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.8      2023-12-06 [3] CRAN (R 4.3.2)
##  sessioninfo   1.2.2      2021-12-06 [1] CRAN (R 4.3.2)
##  shiny         1.7.5.1    2023-10-14 [1] CRAN (R 4.3.2)
##  stringi       1.8.3      2023-12-11 [3] CRAN (R 4.3.2)
##  stringr       1.5.1      2023-11-14 [3] CRAN (R 4.3.2)
##  urlchecker    1.0.1      2021-11-30 [1] CRAN (R 4.3.2)
##  usethis       3.0.0      2024-07-29 [1] CRAN (R 4.3.3)
##  vctrs         0.6.5      2023-12-01 [1] CRAN (R 4.3.3)
##  xfun          0.41       2023-11-01 [3] CRAN (R 4.3.2)
##  xtable        1.8-4      2019-04-21 [1] CRAN (R 4.3.2)
##  yaml          2.3.8      2023-12-11 [3] CRAN (R 4.3.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Let&#39;s Talk About the Weather</title>
      <link>https://jcarroll.com.au/2024/07/27/let-s-talk-about-the-weather/</link>
      <pubDate>Sat, 27 Jul 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/07/27/let-s-talk-about-the-weather/</guid>
      <description>&lt;p&gt;A while ago I made some plots I really liked, but I never made a blog post
about them. Then the data source stopped working and I couldn’t make them
again. Now there’s a new data source, so it’s time for a post about some
weather data!&lt;/p&gt;
&lt;p&gt;Way back in the mid 2010s I was interested in getting my hands on some weather
data to answer a question I had. In Australia we have the Bureau of Meteorology
(&lt;a href=&#34;https://www.abc.net.au/news/2022-10-19/bureau-meteorology-rebrand-cost-200-thousand/101552620&#34;&gt;“don’t call it ‘the bom’”&lt;/a&gt;)
which has been keeping track of weather data for a very long time (on the scale
of colonial Australia). They don’t have an official API to get to that data,
they have a website that doesn’t use HTTPS - if you &lt;em&gt;have&lt;/em&gt; a link to a page on
their site and try to visit in in any modern browser which assumes you want to
use HTTPS, you’ll see this page&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/bom.png&#34; alt=&#34;The state of internet technology at the BoM&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;The state of internet technology at the BoM&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;then be redirected to the landing page, regardless of where your link was trying
to send you. They &lt;em&gt;are&lt;/em&gt; working on improving this, and there’s a new
&lt;a href=&#34;https://beta.bom.gov.au/&#34;&gt;https://beta.bom.gov.au/&lt;/a&gt; which notes it’s a test
website.&lt;/p&gt;
&lt;p&gt;That rant aside, if you wanted some temperature data, you clicked your way
through the interface on the website to specify a station and some settings, and
eventually were presented with a tabular output of the data and the ability to
export it as a .zip file containing an actual .csv plus a note file.&lt;/p&gt;
&lt;p&gt;At the time, I was aware of a BoM-related R package &lt;code&gt;{bomrang}&lt;/code&gt; by Adam Sparks,
which began life at the rOpenSci AUUnconf in Brisbane, 2016 where I had the
pleasure of meeting him. It didn’t have access to the weather data the way I
wanted, but it had a lot of other cool functionality such as finding the closest
station and fetching forecasts, radar imagery, and bulletins. I wasn’t able to
use a package to get the data I wanted, so I had to figure something out myself.&lt;/p&gt;
&lt;p&gt;I realised that the generated URL to that .zip file was parameterized, involving
the station id, and some codes presumably representing what type of data was
being fetched (temperature, rainfall, …). The codes themselves weren’t
documented on the site, they were most likely only for internal use, but if I
knew which one I wanted, I probably had enough information to get the full URL.
With a bit of tinkering, I figured out the meaning of one of the codes (rain =
136, min_temp = 123, max_temp = 122, solar = 193) and could specify which one I
wanted. There was still one more code in the URL, and I found a way to decode
that via an additional URL query, at which point I could build the entire URL.&lt;/p&gt;
&lt;p&gt;After that, I could programatically unpack the .zip with &lt;code&gt;utils::unzip()&lt;/code&gt; and
read in the .csv data. Thus, &lt;code&gt;bomrang::get_historical_weather()&lt;/code&gt; was forged and
introduced &lt;a href=&#34;https://github.com/ropensci-archive/bomrang/pull/68&#34;&gt;via a pull request&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Fast forward to 2021 and this function started failing - the data was available
just fine via a browser, but was returning an error in R/RStudio. It turned out
that changing the user-agent allowed for a brief period of access, but eventually
the official statement was released&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Bureau is monitoring screen scraping activity on the site and will
commence interrupting, and eventually blocking, this activity on www.bom.gov.au
from Wednesday, 3 March 2021&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and there was no way to get to the data nicely. This was extremely frustrating,
especially since we (taxpayers) technically pay for this data.&lt;/p&gt;
&lt;p&gt;All was not lost, however - Adam continued to develop package infrastructure and
found a new resource in the form of &lt;a href=&#34;https://www.longpaddock.qld.gov.au/silo/&#34;&gt;SILO&lt;/a&gt;.
Adam built a new package {weatherOz} and submitted a paper to &lt;a href=&#34;https://joss.theoj.org/papers/10.21105/joss.06717&#34;&gt;JOSS&lt;/a&gt;
including all the original authors as contributors to both - I can’t claim to have
contributed to the new package, so I’m somewhat hopeful that a detailed blog post
can help repay some of that kindness.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;{weatherOz}&lt;/code&gt; has now been accepted onto &lt;a href=&#34;https://cran.r-project.org/package=weatherOz&#34;&gt;CRAN&lt;/a&gt;
(&lt;a href=&#34;https://rstats.me/@adamhsparks/112855926571892452&#34;&gt;announcement&lt;/a&gt;) and so can be installed with&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;install.packages(&amp;quot;weatherOz&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Adam also has a nice blog post exploring some temperature data
&lt;a href=&#34;https://adamhsparks.netlify.app/2024/06/02/plotting-perth-month-of-may-high-temperatures-with-weatheroz/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now it’s my turn!&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(weatherOz)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are many weather stations within capital cities, so I need to narrow down
to just one. I can get the station information from SILO with&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;adl_stations &amp;lt;- get_stations_metadata(station_name = &amp;quot;Adelaide&amp;quot;, which_api = &amp;quot;silo&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;adl_stations&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##    station_code                       station_name      start        end
## 1        014092         Adelaide River Post Office 1956-01-01 2024-07-27
## 2        023034                   Adelaide Airport 1955-01-01 2024-07-27
## 3        023005               Adelaide Glen Osmond 1883-01-01 2024-07-27
## 4        023096     Adelaide Hope Valley Reservoir 1979-01-01 2024-07-27
## 5        023732             Adelaide Morphett Vale 1886-01-01 2024-07-27
## 6        023098  Adelaide Morphettville Racecourse 1947-01-01 2024-07-27
## 7        023026                   Adelaide Pooraka 1876-01-01 2024-07-27
## 8        023023    Adelaide Salisbury Bowling Club 1870-01-01 2024-07-27
## 9        023024                    Adelaide Seaton 1912-01-01 2024-07-27
## 10       023000 Adelaide West Terrace Ngayirdapira 1839-01-01 2024-07-27
## 11       023011                     North Adelaide 1883-01-01 2024-07-27
##    latitude longitude state elev_m                      source status   wmo
## 1  -13.2373  131.1042    NT   52.5 Bureau of Meteorology (BOM)   open    NA
## 2  -34.9524  138.5196    SA    2.0 Bureau of Meteorology (BOM)   open 94672
## 3  -34.9464  138.6519    SA  128.0 Bureau of Meteorology (BOM)   open    NA
## 4  -34.8564  138.6844    SA  105.0 Bureau of Meteorology (BOM)   open    NA
## 5  -35.1351  138.5274    SA   92.0 Bureau of Meteorology (BOM)   open    NA
## 6  -34.9742  138.5425    SA   11.0 Bureau of Meteorology (BOM)   open    NA
## 7  -34.8324  138.6125    SA   21.0 Bureau of Meteorology (BOM)   open    NA
## 8  -34.7674  138.6434    SA   32.0 Bureau of Meteorology (BOM)   open    NA
## 9  -34.8965  138.5103    SA   10.0 Bureau of Meteorology (BOM)   open    NA
## 10 -34.9257  138.5832    SA   29.3 Bureau of Meteorology (BOM)   open 94648
## 11 -34.9163  138.5950    SA   26.0 Bureau of Meteorology (BOM)   open    NA&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and I can select one of those - the station with code 023000 has a lot of data&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ngayirdapira &amp;lt;- adl_stations[adl_stations$station_code == &amp;quot;023000&amp;quot;, ]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dplyr::glimpse(ngayirdapira)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## Rows: 1
## Columns: 11
## $ station_code &amp;lt;fct&amp;gt; 023000
## $ station_name &amp;lt;chr&amp;gt; &amp;quot;Adelaide West Terrace Ngayirdapira&amp;quot;
## $ start        &amp;lt;date&amp;gt; 1839-01-01
## $ end          &amp;lt;date&amp;gt; 2024-07-27
## $ latitude     &amp;lt;dbl&amp;gt; -34.9257
## $ longitude    &amp;lt;dbl&amp;gt; 138.5832
## $ state        &amp;lt;chr&amp;gt; &amp;quot;SA&amp;quot;
## $ elev_m       &amp;lt;dbl&amp;gt; 29.3
## $ source       &amp;lt;chr&amp;gt; &amp;quot;Bureau of Meteorology (BOM)&amp;quot;
## $ status       &amp;lt;chr&amp;gt; &amp;quot;open&amp;quot;
## $ wmo          &amp;lt;dbl&amp;gt; 94648&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The listed start date of the data is 1839-01-01 but trying to use
that produces an error. I’ll start from the listed year of SILO data (1889).&lt;/p&gt;
&lt;p&gt;Getting the actual data from SILO doesn’t technically need an API key, it just
wants to know who is fetching the data, so asks that you use an email address as
the key. I have that set as an environment variable. I’m also saving the data to
disk since I don’t want to fetch it every time I edit this post as I’m writing
it.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;silo_data &amp;lt;- get_patched_point(
  station_code = ngayirdapira$station_code,
  start_date = &amp;quot;1889-01-01&amp;quot;,
  end_date = ngayirdapira$end,
  values = &amp;quot;all&amp;quot;,
  api_key = Sys.getenv(&amp;quot;SILO_API_KEY&amp;quot;)
)
saveRDS(silo_data, file = &amp;quot;adl_silo_data.rds&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s a lot of data here - along with the (air) temperature min and max, there
are other measurements that I’m not interested in at the moment.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dplyr::glimpse(silo_data)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## Rows: 49,515
## Columns: 46
## $ station_code               &amp;lt;fct&amp;gt; 023000, 023000, 023000, 023000, 023000, 023…
## $ station_name               &amp;lt;chr&amp;gt; &amp;quot;Adelaide West Terrace Ngayirdapira&amp;quot;, &amp;quot;Adel…
## $ year                       &amp;lt;dbl&amp;gt; 1889, 1889, 1889, 1889, 1889, 1889, 1889, 1…
## $ month                      &amp;lt;dbl&amp;gt; 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ day                        &amp;lt;int&amp;gt; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, …
## $ date                       &amp;lt;date&amp;gt; 1889-01-01, 1889-01-02, 1889-01-03, 1889-0…
## $ air_tmax                   &amp;lt;dbl&amp;gt; 34.2, 21.7, 21.6, 21.4, 20.2, 22.4, 24.8, 3…
## $ air_tmax_source            &amp;lt;int&amp;gt; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ air_tmin                   &amp;lt;dbl&amp;gt; 22.0, 20.4, 13.3, 15.0, 12.8, 14.6, 12.6, 1…
## $ air_tmin_source            &amp;lt;int&amp;gt; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ elev_m                     &amp;lt;chr&amp;gt; &amp;quot;29.3 m&amp;quot;, &amp;quot;29.3 m&amp;quot;, &amp;quot;29.3 m&amp;quot;, &amp;quot;29.3 m&amp;quot;, &amp;quot;29…
## $ et_morton_actual           &amp;lt;dbl&amp;gt; 1.9, 3.9, 4.8, 4.3, 4.1, 4.3, 4.0, 2.5, 1.3…
## $ et_morton_actual_source    &amp;lt;int&amp;gt; 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,…
## $ et_morton_potential        &amp;lt;dbl&amp;gt; 11.0, 7.1, 6.4, 7.1, 6.5, 7.3, 7.7, 10.4, 1…
## $ et_morton_potential_source &amp;lt;int&amp;gt; 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,…
## $ et_morton_wet              &amp;lt;dbl&amp;gt; 6.5, 5.5, 5.6, 5.7, 5.3, 5.8, 5.8, 6.5, 7.4…
## $ et_morton_wet_source       &amp;lt;int&amp;gt; 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,…
## $ et_short_crop              &amp;lt;dbl&amp;gt; 6.9, 4.8, 4.5, 4.8, 4.5, 5.0, 5.3, 6.7, 7.9…
## $ et_short_crop_source       &amp;lt;int&amp;gt; 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,…
## $ et_tall_crop               &amp;lt;dbl&amp;gt; 9.0, 5.8, 5.4, 5.9, 5.4, 6.0, 6.6, 8.8, 10.…
## $ et_tall_crop_source        &amp;lt;int&amp;gt; 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,…
## $ evap_comb                  &amp;lt;dbl&amp;gt; 8.8, 5.9, 6.2, 6.4, 6.1, 6.5, 7.0, 8.7, 10.…
## $ evap_comb_source           &amp;lt;int&amp;gt; 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,…
## $ evap_morton_lake           &amp;lt;dbl&amp;gt; 6.6, 5.6, 5.8, 5.9, 5.5, 6.0, 6.0, 6.6, 7.5…
## $ evap_morton_lake_source    &amp;lt;int&amp;gt; 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,…
## $ evap_pan                   &amp;lt;dbl&amp;gt; 7.9, 8.0, 8.0, 8.1, 8.1, 8.1, 8.2, 8.2, 8.2…
## $ evap_pan_source            &amp;lt;int&amp;gt; 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,…
## $ evap_syn                   &amp;lt;dbl&amp;gt; 8.8, 5.9, 6.2, 6.4, 6.1, 6.5, 7.0, 8.7, 10.…
## $ evap_syn_source            &amp;lt;int&amp;gt; 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,…
## $ extracted                  &amp;lt;date&amp;gt; 2024-07-27, 2024-07-27, 2024-07-27, 2024-0…
## $ latitude                   &amp;lt;dbl&amp;gt; -34.9257, -34.9257, -34.9257, -34.9257, -34…
## $ longitude                  &amp;lt;dbl&amp;gt; 138.5832, 138.5832, 138.5832, 138.5832, 138…
## $ mslp                       &amp;lt;dbl&amp;gt; 1013.8, 1013.9, 1014.1, 1014.5, 1014.5, 101…
## $ mslp_source                &amp;lt;int&amp;gt; 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,…
## $ radiation                  &amp;lt;dbl&amp;gt; 24.1, 23.3, 25.8, 26.1, 25.3, 26.4, 26.5, 2…
## $ radiation_source           &amp;lt;int&amp;gt; 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,…
## $ rainfall                   &amp;lt;dbl&amp;gt; 0.0, 58.4, 10.4, 0.3, 0.0, 0.3, 0.0, 0.0, 0…
## $ rainfall_source            &amp;lt;int&amp;gt; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ rh_tmax                    &amp;lt;dbl&amp;gt; 28.1, 59.7, 52.7, 49.9, 49.4, 47.3, 38.3, 2…
## $ rh_tmax_source             &amp;lt;int&amp;gt; 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,…
## $ rh_tmin                    &amp;lt;dbl&amp;gt; 57.1, 64.7, 89.1, 74.5, 79.2, 77.1, 82.3, 6…
## $ rh_tmin_source             &amp;lt;int&amp;gt; 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,…
## $ vp                         &amp;lt;dbl&amp;gt; 15.1, 15.5, 13.6, 12.7, 11.7, 12.8, 12.0, 1…
## $ vp_deficit                 &amp;lt;dbl&amp;gt; 30.2, 9.9, 9.1, 10.4, 9.4, 11.2, 14.0, 26.5…
## $ vp_deficit_source          &amp;lt;int&amp;gt; 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,…
## $ vp_source                  &amp;lt;int&amp;gt; 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,…&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s 49,515 daily weather observations
covering the last 135 or so years!&lt;/p&gt;
&lt;p&gt;I’ll add some convenience columns; the day of the year, the decade, and the
abbreviation for the month.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;silo_data$doy &amp;lt;- lubridate::yday(silo_data$date)
silo_data$decade &amp;lt;- cut(silo_data$year, 
                        breaks = seq(1880, 2030, by = 10), 
                        right = FALSE, 
                        labels = seq(1880, 2020, by = 10))
silo_data$monthabb = factor(month.abb[silo_data$month], levels = month.abb)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My original motivation for getting any of this data was Christmas 2016 - I live in
the southern hemisphere so I get to enjoy Christmas in summer (despite being
inundated with snowy imagery and having to explain to my kids why none of it is
relevant here).&lt;/p&gt;
&lt;p&gt;We still partake in some of the northern hemisphere traditions like a roast lunch
and warm puddings for dessert, but we complement that with some cold, fresh prawns
and some cold beers.&lt;/p&gt;
&lt;p&gt;2016 was a particularly hot Christmas day, and I wanted to know how it compared
historically. It’s not uncommon, I suppose, for someone in the USA to note that
it was 40 degrees on Christmas (40°F = 4°C) but here it was also
expected to hit 40… Celsius. 40°C = 104°F.&lt;/p&gt;
&lt;p&gt;We can find all the entries in the silo data where it was 40°C or more on
Christmas day&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;silo_data |&amp;gt; 
  dplyr::filter(air_tmax &amp;gt;= 40, month == 12, day == 25) |&amp;gt; 
  dplyr::select(date, air_tmin, air_tmax)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##         date air_tmin air_tmax
## 1 1941-12-25     29.7     41.4
## 2 1945-12-25     29.8     40.1
## 3 2016-12-25     15.9     40.3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, those were the hottest, but were they exceptional for that time of year?&lt;/p&gt;
&lt;p&gt;I originally produced these plots using the (now superseded) &lt;code&gt;{bomrang}&lt;/code&gt; package,
and now that I had a useful replacement, I wanted to recreate and update them with
some new data.&lt;/p&gt;
&lt;p&gt;These plots aren’t terribly fancy; they show the min or max temperature for each
day of the year, coloured by the decade. They demonstrate the range of temperature
variation throughout the year, but aren’t super useful for extracting information
necessarily - squint to see the general pattern.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)

ggplot(silo_data) +
  geom_point(aes(x = doy, y = air_tmax, col = decade), alpha = 0.2)  +
  theme_bw() +
  labs(
    title = &amp;quot;Daily Maximum Temperatures&amp;quot;,
    subtitle = &amp;quot;Adelaide, South Australia, 1889-2024&amp;quot;,
    caption = &amp;quot;source: https://www.longpaddock.qld.gov.au/silo/&amp;quot;,
    y = &amp;quot;Daily Maximum Temperature [°C]&amp;quot;,
    x = &amp;quot;Day of Year&amp;quot;
  ) +
  scale_y_continuous(
    limits = c(-5, 50),
    sec.axis = sec_axis( ~ . * 9 / 5 + 32, name = &amp;quot;Daily Maximum Temperature [°F]&amp;quot;)
  ) +
  viridis::scale_color_viridis(discrete = TRUE)&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/pmax.png&#34; alt=&#34;Daily maximum temperatures in Adelaide&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Daily maximum temperatures in Adelaide&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The same for the minimum temperatures:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;pmin &amp;lt;- ggplot(silo_data) +
  geom_point(aes(x = doy, y = air_tmin, col = decade), alpha = 0.2)  +
  theme_bw() +
  labs(
    title = &amp;quot;Daily Minimum Temperatures&amp;quot;,
    subtitle = &amp;quot;Adelaide, South Australia, 1889-2024&amp;quot;,
    caption = &amp;quot;source: https://www.longpaddock.qld.gov.au/silo/&amp;quot;,
    y = &amp;quot;Daily Minimum Temperature [°C]&amp;quot;,
    x = &amp;quot;Day of Year&amp;quot;
  ) +
  scale_y_continuous(
    limits = c(-5, 50),
    sec.axis = sec_axis( ~ . * 9 / 5 + 32, name = &amp;quot;Daily Minimum Temperature [°F]&amp;quot;)
  ) +
  viridis::scale_color_viridis(discrete = TRUE)
pmin&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/pmin.png&#34; alt=&#34;Daily minimum temperatures in Adelaide&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Daily minimum temperatures in Adelaide&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This winter (middle of the year here) feels like it’s been particularly cold - but
is it colder than usual? I saw someone demonstrate a feature of &lt;code&gt;{ggplot2}&lt;/code&gt; that
I haven’t previously made good use of; the &lt;code&gt;data&lt;/code&gt; argument to a &lt;code&gt;geom&lt;/code&gt; can take a
formula for a function as long as the result of that is another &lt;code&gt;data.frame&lt;/code&gt;, so
a &lt;code&gt;filter&lt;/code&gt; or &lt;code&gt;head&lt;/code&gt; or &lt;code&gt;slice&lt;/code&gt; operation works great here.&lt;/p&gt;
&lt;p&gt;I’ll add in the points for June onward this year in &lt;span style=&#34;color: #FF0000;&#34;&gt;red&lt;/span&gt;:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;pmin +
  geom_point(
    data = ~ dplyr::filter(.x, year == 2024, month &amp;gt; 5),
    aes(x = doy, y = air_tmin),
    col = &amp;quot;red&amp;quot;
  )&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/pmin_hl.png&#34; alt=&#34;Cold days in Winter, 2024&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Cold days in Winter, 2024&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Definitely one particularly cold day there - it got as low as -5°C in some places.&lt;/p&gt;
&lt;p&gt;In order to see how the temperatures have changed over the years, I also split out
the data for each month and plotted the max/min for every day in the month for each
year - this nicely shows that the spread is a lot tighter in winter and the days in
our summer are a lot more variable. Again I’m using the helpful &lt;code&gt;data = ~f(.x)&lt;/code&gt; pattern,
this time with &lt;code&gt;dplyr::slice_max()&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ggplot(dplyr::arrange(silo_data, monthabb), aes(x = year, y = air_tmax)) +
  geom_point(aes(col = factor(monthabb)), alpha = 0.3, show.legend = FALSE) +
  geom_point(
    data = ~ dplyr::slice_max(.x, air_tmax, n = 1, by = monthabb),
    aes(x = year, y = air_tmax),
    col = &amp;quot;red&amp;quot;
  ) +
  geom_text(
    data = ~ dplyr::slice_max(.x, air_tmax, n = 1, by = monthabb),
    aes(x = year, y = air_tmax + 5, label = year),
    col = &amp;quot;red&amp;quot;
  ) +
  facet_wrap( ~ monthabb) +
  labs(
    title = &amp;quot;Daily Maximum Temperature&amp;quot;,
    subtitle = &amp;quot;Adelaide, South Australia, 1889-2024&amp;quot;,
    caption = &amp;quot;source: https://www.longpaddock.qld.gov.au/silo/&amp;quot;,
    x = &amp;quot;Year&amp;quot;,
    y = &amp;quot;Daily Maximum Temperature [°C]&amp;quot;
  ) +
  theme_bw() +
  scale_x_continuous(breaks = seq(1880, 2030, 20)) +
  ggeasy::easy_rotate_x_labels(angle = 45, side = &amp;quot;right&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/pmax_month.png&#34; alt=&#34;Monthly maximum temperatures and hottest days&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Monthly maximum temperatures and hottest days&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The same for the minimum temperatures:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ggplot(dplyr::arrange(silo_data, monthabb), aes(x = year, y = air_tmin)) +
  geom_point(aes(col = factor(monthabb)), alpha = 0.3, show.legend = FALSE) +
  geom_point(
    data = ~ dplyr::slice_min(.x, air_tmin, n = 1, by = monthabb),
    aes(x = year, y = air_tmin),
    col = &amp;quot;blue&amp;quot;
  ) +
  geom_text(
    data = ~ dplyr::slice_min(.x, air_tmin, n = 1, by = monthabb),
    aes(x = year, y = air_tmin - 5, label = year),
    col = &amp;quot;blue&amp;quot;
  ) +
  facet_wrap( ~ monthabb) +
  labs(
    title = &amp;quot;Daily Minimum Temperature&amp;quot;,
    subtitle = &amp;quot;Adelaide, South Australia, 1889-2024&amp;quot;,
    caption = &amp;quot;source: https://www.longpaddock.qld.gov.au/silo/&amp;quot;,
    x = &amp;quot;Year&amp;quot;,
    y = &amp;quot;Daily Minimum Temperature [°C]&amp;quot;
  ) +
  theme_bw() +
  scale_x_continuous(breaks = seq(1880, 2030, 20)) +
  ggeasy::easy_rotate_x_labels(angle = 45, side = &amp;quot;right&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/pmin_month.png&#34; alt=&#34;Monthly minimum temperatures and coldest days&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Monthly minimum temperatures and coldest days&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I’m very pleased that I’m once again able to query weather data for my country,
and am deeply grateful to Adam Sparks for building and maintaining &lt;code&gt;{weatherOz}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you have comments, suggestions, or improvements, as always, feel free to use
the comment section below, or hit me up on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt;. Also let me know if you can think
of (or make) some remix or other visualization of this data!&lt;/p&gt;
&lt;p&gt;Stay cool/warm/comfortable!&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.3 (2024-02-29)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2024-07-27
##  pandoc   3.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.18    2023-06-19 [1] CRAN (R 4.3.2)
##  bookdown      0.36    2023-10-16 [1] CRAN (R 4.3.2)
##  bslib         0.6.1   2023-11-28 [3] CRAN (R 4.3.2)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [1] CRAN (R 4.3.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.3.2)
##  digest        0.6.34  2024-01-11 [3] CRAN (R 4.3.2)
##  dplyr         1.1.4   2023-11-17 [3] CRAN (R 4.3.2)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.23    2023-11-01 [3] CRAN (R 4.3.2)
##  fansi         1.0.6   2023-12-08 [1] CRAN (R 4.3.3)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  generics      0.1.3   2022-07-05 [3] CRAN (R 4.2.1)
##  glue          1.7.0   2024-01-09 [1] CRAN (R 4.3.3)
##  htmltools     0.5.7   2023-11-03 [3] CRAN (R 4.3.2)
##  htmlwidgets   1.6.2   2023-03-17 [1] CRAN (R 4.3.2)
##  httpuv        1.6.12  2023-10-23 [1] CRAN (R 4.3.2)
##  icecream      0.2.1   2023-09-27 [1] CRAN (R 4.3.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.8   2023-12-04 [3] CRAN (R 4.3.2)
##  knitr         1.45    2023-10-30 [3] CRAN (R 4.3.2)
##  later         1.3.1   2023-05-02 [1] CRAN (R 4.3.2)
##  lifecycle     1.0.4   2023-11-07 [1] CRAN (R 4.3.3)
##  lubridate     1.9.3   2023-09-27 [3] CRAN (R 4.3.1)
##  magrittr      2.0.3   2022-03-30 [1] CRAN (R 4.3.3)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.3.2)
##  pillar        1.9.0   2023-03-22 [1] CRAN (R 4.3.3)
##  pkgbuild      1.4.2   2023-06-26 [1] CRAN (R 4.3.2)
##  pkgconfig     2.0.3   2019-09-22 [1] CRAN (R 4.3.3)
##  pkgload       1.3.3   2023-09-22 [1] CRAN (R 4.3.2)
##  prettyunits   1.2.0   2023-09-24 [3] CRAN (R 4.3.1)
##  processx      3.8.3   2023-12-10 [3] CRAN (R 4.3.2)
##  profvis       0.3.8   2023-05-02 [1] CRAN (R 4.3.2)
##  promises      1.2.1   2023-08-10 [1] CRAN (R 4.3.2)
##  ps            1.7.6   2024-01-18 [3] CRAN (R 4.3.2)
##  purrr         1.0.2   2023-08-10 [3] CRAN (R 4.3.1)
##  R6            2.5.1   2021-08-19 [1] CRAN (R 4.3.3)
##  Rcpp          1.0.11  2023-07-06 [1] CRAN (R 4.3.2)
##  remotes       2.4.2.1 2023-07-18 [1] CRAN (R 4.3.2)
##  rlang         1.1.4   2024-06-04 [1] CRAN (R 4.3.3)
##  rmarkdown     2.25    2023-09-18 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.8   2023-12-06 [3] CRAN (R 4.3.2)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.3.2)
##  shiny         1.7.5.1 2023-10-14 [1] CRAN (R 4.3.2)
##  stringi       1.8.3   2023-12-11 [3] CRAN (R 4.3.2)
##  stringr       1.5.1   2023-11-14 [3] CRAN (R 4.3.2)
##  tibble        3.2.1   2023-03-20 [1] CRAN (R 4.3.3)
##  tidyselect    1.2.0   2022-10-10 [3] CRAN (R 4.2.1)
##  timechange    0.3.0   2024-01-18 [3] CRAN (R 4.3.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.3.2)
##  usethis       2.2.2   2023-07-06 [1] CRAN (R 4.3.2)
##  utf8          1.2.4   2023-10-22 [1] CRAN (R 4.3.3)
##  vctrs         0.6.5   2023-12-01 [1] CRAN (R 4.3.3)
##  withr         3.0.0   2024-01-16 [1] CRAN (R 4.3.3)
##  xfun          0.41    2023-11-01 [3] CRAN (R 4.3.2)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.3.2)
##  yaml          2.3.8   2023-12-11 [3] CRAN (R 4.3.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Constructing HTML with Functional Functions</title>
      <link>https://jcarroll.com.au/2024/06/20/constructing-html-with-functions/</link>
      <pubDate>Thu, 20 Jun 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/06/20/constructing-html-with-functions/</guid>
      <description>&lt;p&gt;I heard that learning Elm is a good way to approach learning Haskell, so I gave
it a go and was surprised early on about an approach to writing abstracted HTML.
In this post I compare the way that R and Elm generate HTML and the differences
between their approaches.&lt;/p&gt;
&lt;p&gt;I was listening to the Linux Dev Time podcast based on a recommendation and this episode
(&lt;a href=&#34;https://www.linuxdevtime.com/linux-dev-time-episode-100/&#34;&gt;episode 100&lt;/a&gt;) was about
“how many different programming languages should you learn?”&lt;/p&gt;
&lt;p&gt;One suggestion in amongst the interesting discussions was that “if you want to
learn Haskell, start by learning Elm, because Elm uses Haskell syntax but it
removes most of the most difficult concepts in Haskell.”&lt;/p&gt;
&lt;p&gt;I’ve been trying to learn Haskell this year, building on some intermittent
exposure to it in the last couple of years and partly because I joined a local
functional programming meetup group which is fortunate enough to have some
Haskell developers. I’ve read the first few chapters of
&lt;a href=&#34;https://www.learnyouahaskell.com/&#34;&gt;‘Learn You a Haskel for Great Good!’&lt;/a&gt; and Haskell is a &lt;a href=&#34;https://exercism.org/tracks/haskell&#34;&gt;supported track on Exercism&lt;/a&gt;. As you can see
from my
&lt;a href=&#34;https://github.com/jonocarroll/exercism-solutions&#34;&gt;summary of complete exercises&lt;/a&gt;
Haskell is the language I’ve solved the most exercises in, followed very closely by R.&lt;/p&gt;
&lt;p&gt;Haskell definitely feels like an academic language - even reading other people’s
solutions to puzzles and code problems I find myself struggling to understand
both the somewhat unique syntax and the approach at the same time. The fact that
there is no if-else construct in Haskell means a lot of pattern matching, and
the fact that there are no loops means a lot of recursion. All arguments to
functions are whitespace separated, so the expression &lt;code&gt;add 1 2&lt;/code&gt; is a call
of the function &lt;code&gt;add&lt;/code&gt; with arguments &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;2&lt;/code&gt; meaning that parentheses are
frequently required, or other specific syntax quirks.&lt;/p&gt;
&lt;p&gt;Rust (another language I’ve spent quite a bit of time learning) lists Haskell as
&lt;a href=&#34;https://doc.rust-lang.org/reference/influences.html&#34;&gt;one of its influences&lt;/a&gt; and
that becomes quite apparent once you see the keyword &lt;code&gt;deriving&lt;/code&gt; (for typeclasses)
in both languages, e.g. &lt;a href=&#34;https://book.realworldhaskell.org/read/using-typeclasses.html&#34; class=&#34;uri&#34;&gt;https://book.realworldhaskell.org/read/using-typeclasses.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But Rust doesn’t use Haskell syntax, and isn’t nearly as ‘pure’ (lacking side-effects).&lt;/p&gt;
&lt;p&gt;The advice to start with Elm sounded like it came from a good place, and seemed
reasonable.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://exercism.org/tracks/elm&#34;&gt;Elm is also one of the languages offered on Exercism&lt;/a&gt;
but again referring to my summary, I haven’t done much at all with it - the introduction
‘hello, world’ exercise and one other. That at least means I installed it locally
and got the toolchain working, but I certainly wasn’t familiar at all.
&lt;a href=&#34;https://github.com/jonocarroll/exercism-solutions/blob/main/elm/allergies/src/Allergies.elm&#34;&gt;My solution&lt;/a&gt;
to the problem that I did solve involved a big if-else block.&lt;/p&gt;
&lt;p&gt;I like learning languages (can you tell?) so I figured I’d give it a fair go and
started reading &lt;a href=&#34;https://www.manning.com/books/elm-in-action&#34;&gt;Elm in Action&lt;/a&gt; by
Richard Feldman. As well as an Elm core member, Richard is the author of the
&lt;a href=&#34;https://www.roc-lang.org/&#34;&gt;Roc language&lt;/a&gt; which is built in Rust and aims to be
better than both Elm and Rust in the sense of being a “fast, friendly, functional language”
with specific emphasis on each of the words in that phrase. I do plan to learn
more Roc as well, but for now I’m focussed on gaining a better understanding of
Haskell via Elm, so back to Elm…&lt;/p&gt;
&lt;p&gt;Elm isn’t a new language - it first appeared in 2012 - but it’s also considered
somewhat “stable” in that there haven’t been any big changes to it for a few
years. Some people seem to rush to the conclusion that a language not in a
constant state of change is “dead” or “stale”, but the author (of the language/compiler)
&lt;a href=&#34;https://github.com/elm/compiler/blob/master/roadmap.md&#34;&gt;makes it clear&lt;/a&gt; that&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you like what you see now, that’s pretty much what Elm is going to be for a while.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I have no problem with that.&lt;/p&gt;
&lt;p&gt;Elm comes with a REPL, something I find extremely helpful for playing with a new
language. One of the big surprises was how good the error messages are. Trying to
do something like adding a number and string produces an explanation of what
is wrong&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; 1 + &amp;quot;a&amp;quot;
-- TYPE MISMATCH ---------------------------------------------------------- REPL

I cannot do addition with String values like this one:

3|   1 + &amp;quot;a&amp;quot;
         ^^^
The (+) operator only works with Int and Float values.

Hint: Switch to the (++) operator to append strings!&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;not a screen full of stack traces (I’m looking at you, JVM languages).&lt;/p&gt;
&lt;p&gt;I think of Rust’s error messages as the most helpful; pointing out not only
&lt;em&gt;what&lt;/em&gt; went wrong, but a link to documentation explaining that pattern, and often
a code suggestion for how to fix it. The tooling can even ‘auto fix’ some of those
errors when it’s clear what the code &lt;em&gt;should&lt;/em&gt; have been. Roc aims to have even
better error messages than both of these - a high bar, but fantastic to aim for.&lt;/p&gt;
&lt;p&gt;I have tended towards dynamic languages (R being one of them) where classes of
variables might be coerced, promoted, or combined sensibly. Not every language
supports that, and for good reason - I’ve definitely seen the value in strongly
typed languages preventing the need for defensive coding such as a huge block
of assertions at the top of every function to make sure what’s passed in actually
makes sense. Some languages are less fussy…&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/typesafety.jpg&#34; alt=&#34;Javascript lets you combine just about anything&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Javascript lets you combine just about anything&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I started following along Elm in Action - properly following along; not just reading
and pretending to take things in like I’ve done all too many times with technical
books. I had the REPL open and played around with what I could do as I was
reading about each example.&lt;/p&gt;
&lt;p&gt;One of the things this book gets right is to get to building something early on. A
common complaint about Haskell books is that, since IO is a bit complicated in a
language where functions are ‘pure’ and have no side-effects such as input and output,
actually building even a ‘hello, world’ program tends to show up pretty late. Within
Chapter 2 of Elm in Action we’re building a website. Kudos on that one.&lt;/p&gt;
&lt;p&gt;One of the first examples was to output some HTML for a static site.
This is, of course, an overly simple starting point and one could absolutely say
that Elm isn’t required for this part, but it fits in nicely with what comes next -
making the site interactive.&lt;/p&gt;
&lt;p&gt;I’m old enough that in high school we had a class where we wrote a website. I don’t
mean “built” one with some framework or package, I mean opening a text file and writing
out the HTML to be rendered in a browser (Netscape). This wasn’t state-of-the-art design, but
it gave me a reasonable introduction to the essentials of HTML markup.&lt;/p&gt;
&lt;p&gt;The example code in Elm for the static site is&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;div [ class &amp;quot;content&amp;quot; ]
    [ h1 [] [ text &amp;quot;Photo Groove&amp;quot; ]                           
    , div [ id &amp;quot;thumbnails&amp;quot; ]                                 
        [ img [ src &amp;quot;http://elm-in-action.com/1.jpeg&amp;quot; ] []
        , img [ src &amp;quot;http://elm-in-action.com/2.jpeg&amp;quot; ] []
        , img [ src &amp;quot;http://elm-in-action.com/3.jpeg&amp;quot; ] []
        ]
    ]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which might need some unpacking. This is a call of the function &lt;code&gt;div&lt;/code&gt; which takes two
arguments; a list containing a call to &lt;code&gt;class&lt;/code&gt; with an argument &lt;code&gt;&#34;content&#34;&lt;/code&gt;, and
a list containing a call to &lt;code&gt;h1&lt;/code&gt; and its 2 arguments (an empty list and a call to
&lt;code&gt;text&lt;/code&gt; with a string argument), and another call to &lt;code&gt;div&lt;/code&gt; and its arguments.&lt;/p&gt;
&lt;p&gt;What blew my mind here was not that &lt;code&gt;div&lt;/code&gt; and &lt;code&gt;h1&lt;/code&gt; were functions - I’m familiar
with doing that in R via {htmltools}. Joe Cheng makes the claim in his
&lt;a href=&#34;https://youtu.be/HpqLXB_TnpI&amp;amp;t=1720&#34;&gt;rstudio::conf(2022) talk&lt;/a&gt; that “R is a
bizarrely good host language for Shiny” (R’s interactive web framework) &lt;em&gt;because&lt;/em&gt;
of the nature of positional and named arguments. It translates quite well to
HTML.&lt;/p&gt;
&lt;p&gt;But the Elm code doesn’t use named arguments (it doesn’t have those, though you
&lt;em&gt;could&lt;/em&gt; use a record as an argument and get that effect if you needed to); every
function in the Html module that creates elements takes two arguments, either of
which may be empty (&lt;code&gt;[]&lt;/code&gt;); a list of attributes, and a list of child nodes.&lt;/p&gt;
&lt;p&gt;So, &lt;code&gt;class&lt;/code&gt; is &lt;em&gt;also&lt;/em&gt; a function here, taking a string argument.&lt;/p&gt;
&lt;p&gt;I suspect I’ve spent &lt;em&gt;too&lt;/em&gt; long working with strings instead of types. The thing
that represents a class should definitely be an object of type ‘class’, and the
thing that represents some text should be of a different type - ‘text’. All of this
strong typing gets around the all-too-common problem of passing in a value to an
R function as a string and having it used in unexpected ways…&lt;/p&gt;
&lt;p&gt;Spot the difference:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nchar(&amp;quot;😀😀😀&amp;quot;, &amp;quot;char&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nchar(&amp;quot;😀😀😀&amp;quot;, &amp;quot;byte&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 12&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nchar(c(&amp;quot;😀😀😀&amp;quot;, &amp;quot;char&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nchar(c(&amp;quot;😀😀😀&amp;quot;, &amp;quot;byte&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enums get you a bit closer to not using strings to represent unique things, without
going all-in on types, but R doesn’t really have enums that are useful in that way.
&lt;a href=&#34;https://jcarroll.xyz/2024/06/06/enums-in-r.html&#34;&gt;I do wish it did&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One might have expected an error here - it might have saved a headache or two&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nchar(100)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nchar(1000)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nchar(10000)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 5&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nchar(100000)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 5&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nchar(1000000)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(to see why this happens, try entering the numbers into a console)&lt;/p&gt;
&lt;p&gt;So, how would I write the HTML generating code in R?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(htmltools)

body &amp;lt;- div(class = &amp;quot;content&amp;quot;, 
            h1(&amp;quot;Photo Groove&amp;quot;),
            div(id = &amp;quot;thumbnails&amp;quot;,
                img(src = &amp;quot;http://elm-in-action.com/1.jpeg&amp;quot;),
                img(src = &amp;quot;http://elm-in-action.com/2.jpeg&amp;quot;),
                img(src = &amp;quot;http://elm-in-action.com/3.jpeg&amp;quot;)
            )
)

body&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
  &amp;lt;h1&amp;gt;Photo Groove&amp;lt;/h1&amp;gt;
  &amp;lt;div id=&amp;quot;thumbnails&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;http://elm-in-action.com/1.jpeg&amp;quot;/&amp;gt;
    &amp;lt;img src=&amp;quot;http://elm-in-action.com/2.jpeg&amp;quot;/&amp;gt;
    &amp;lt;img src=&amp;quot;http://elm-in-action.com/3.jpeg&amp;quot;/&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I ran &lt;code&gt;browsable(body)&lt;/code&gt; in RStudio I’d get a rendered view of that HTML, i.e.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/rendered.png&#34; alt=&#34;The rendered HTML&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;The rendered HTML&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The construction of HTML attributes and child nodes gels nicely with R syntax.&lt;/p&gt;
&lt;p&gt;Compiling the Elm code and inspecting the output I get exactly that HTML in the
source, along with the reason it’s more complicated than that; the source contains
the entire Elm runtime, needed for building interactive elements. Elm compiles
down to Javascript, but since it’s strongly typed it prevents a lot of issues from
ending up in the final product, in the same way that Typescript aims to.&lt;/p&gt;
&lt;p&gt;If I wanted to interact with the images (Elm in Action walks through using these
images as thumbnails and opening a larger version alongisde, depending on which
one is clicked on) I’d need to write some Javascript into the body and/or use an
entire runtime like Shiny to handle the effects.&lt;/p&gt;
&lt;p&gt;I was a little shocked when I saw the paragraph&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Back in the Wild West days of the web, it was common to store application state primarily in the DOM itself. Is that menu expanded or collapsed? Check whether one of its DOM nodes has class=“expanded” or class=“collapsed”. Need to know what value a user has selected in a drop-down menu? Query it out of the DOM at the last possible instant.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExaG8xM2puNnhjcjYxajlsbm9uajBwdWxqbWtpcHl1cm4wdWFzczJrYiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/H5C8CevNMbpBqNqFjl/giphy.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;But… that’s how I thought it was supposed to be done. I’m not a front-end dev,
that’s for sure. I suppose I’m also old.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://guide.elm-lang.org/architecture/&#34;&gt;‘The Elm Architecture’&lt;/a&gt; involves
passing messages around in a somewhat object-oriented way (at least reminiscent
of smalltalk) but those messages are created and received by pure functional
code - the runtime itself is not pure (and can communicate with the outside world
via the browser) but that’s considered ‘tested’ and any code the user writes in
Elm still follows the pure functional paradigm.&lt;/p&gt;
&lt;p&gt;On top of all of that, it makes for (surprisingly?) &lt;a href=&#34;https://elm-lang.org/news/blazing-fast-html&#34;&gt;super fast performance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This also means that functions can be tested, since the functions will be free
of side-effects. This is so well received that it’s endorsed by
&lt;a href=&#34;https://ratatui.rs/concepts/application-patterns/the-elm-architecture/&#34;&gt;RATatui&lt;/a&gt;
for building Rust terminal user interfaces.&lt;/p&gt;
&lt;p&gt;I’m still early in the process of learning Elm, but I can definitely see that it’s
a more beginner-friendly way to ease into Haskell, and who knows, maybe I’ll build
a front-end to something. I’m curious if there’s any surface area for interop
with some of the other languages I know.&lt;/p&gt;
&lt;p&gt;I wasn’t expecting to be surprised by function layout quite so quickly, but I
think that’s part of the benefit of learning several languages (once you’re very
familiar with one to start with) - little differences with deep reasonings for them.&lt;/p&gt;
&lt;p&gt;If you have comments, suggestions, or improvements, as always, feel free to use
the comment section below, or hit me up on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.3 (2024-02-29)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2024-07-06
##  pandoc   3.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.18    2023-06-19 [1] CRAN (R 4.3.2)
##  bookdown      0.36    2023-10-16 [1] CRAN (R 4.3.2)
##  bslib         0.6.1   2023-11-28 [3] CRAN (R 4.3.2)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [1] CRAN (R 4.3.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.3.2)
##  digest        0.6.34  2024-01-11 [3] CRAN (R 4.3.2)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.23    2023-11-01 [3] CRAN (R 4.3.2)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  glue          1.7.0   2024-01-09 [1] CRAN (R 4.3.3)
##  htmltools     0.5.7   2023-11-03 [3] CRAN (R 4.3.2)
##  htmlwidgets   1.6.2   2023-03-17 [1] CRAN (R 4.3.2)
##  httpuv        1.6.12  2023-10-23 [1] CRAN (R 4.3.2)
##  icecream      0.2.1   2023-09-27 [1] CRAN (R 4.3.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.8   2023-12-04 [3] CRAN (R 4.3.2)
##  knitr         1.45    2023-10-30 [3] CRAN (R 4.3.2)
##  later         1.3.1   2023-05-02 [1] CRAN (R 4.3.2)
##  lifecycle     1.0.4   2023-11-07 [1] CRAN (R 4.3.3)
##  magrittr      2.0.3   2022-03-30 [1] CRAN (R 4.3.3)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.3.2)
##  pkgbuild      1.4.2   2023-06-26 [1] CRAN (R 4.3.2)
##  pkgload       1.3.3   2023-09-22 [1] CRAN (R 4.3.2)
##  prettyunits   1.2.0   2023-09-24 [3] CRAN (R 4.3.1)
##  processx      3.8.3   2023-12-10 [3] CRAN (R 4.3.2)
##  profvis       0.3.8   2023-05-02 [1] CRAN (R 4.3.2)
##  promises      1.2.1   2023-08-10 [1] CRAN (R 4.3.2)
##  ps            1.7.6   2024-01-18 [3] CRAN (R 4.3.2)
##  purrr         1.0.2   2023-08-10 [3] CRAN (R 4.3.1)
##  R6            2.5.1   2021-08-19 [1] CRAN (R 4.3.3)
##  Rcpp          1.0.11  2023-07-06 [1] CRAN (R 4.3.2)
##  remotes       2.4.2.1 2023-07-18 [1] CRAN (R 4.3.2)
##  rlang         1.1.4   2024-06-04 [1] CRAN (R 4.3.3)
##  rmarkdown     2.25    2023-09-18 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.8   2023-12-06 [3] CRAN (R 4.3.2)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.3.2)
##  shiny         1.7.5.1 2023-10-14 [1] CRAN (R 4.3.2)
##  stringi       1.8.3   2023-12-11 [3] CRAN (R 4.3.2)
##  stringr       1.5.1   2023-11-14 [3] CRAN (R 4.3.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.3.2)
##  usethis       2.2.2   2023-07-06 [1] CRAN (R 4.3.2)
##  vctrs         0.6.5   2023-12-01 [1] CRAN (R 4.3.3)
##  xfun          0.41    2023-11-01 [3] CRAN (R 4.3.2)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.3.2)
##  yaml          2.3.8   2023-12-11 [3] CRAN (R 4.3.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Digits Dilemma</title>
      <link>https://jcarroll.com.au/2024/06/15/digits-dilemma/</link>
      <pubDate>Sat, 15 Jun 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/06/15/digits-dilemma/</guid>
      <description>&lt;p&gt;Another day, another short riddle to be solved with several programming
languages! This one is nice because solving it doesn’t need a lot of code, but
it uses some interesting aspects of evaluation.&lt;/p&gt;
&lt;p&gt;I saw &lt;a href=&#34;https://jezenthomas.com/2022/05/solving-a-maths-riddle-with-bad-haskell/&#34;&gt;this post&lt;/a&gt;
which isn’t new (it’s from 2022) that poses a nice problem to solve:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;With the numbers 123456789, make them add up to 100.
They must stay in the same order but you can use addition, subtraction,
multiplication, division, brackets etc. All numbers must be used exactly once.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and demonstrates a solution in Haskell&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;import Control.Monad (forM)
import Language.Haskell.Interpreter

expressions :: [String]
expressions =
  let ops = [ &amp;#39;+&amp;#39;, &amp;#39;-&amp;#39;, &amp;#39;/&amp;#39;, &amp;#39;*&amp;#39; ]
   in [ [ &amp;#39;1&amp;#39;, a, &amp;#39;2&amp;#39;, b, &amp;#39;3&amp;#39;, c, &amp;#39;4&amp;#39;, d, &amp;#39;5&amp;#39;, e, &amp;#39;6&amp;#39;, f, &amp;#39;7&amp;#39;, g, &amp;#39;8&amp;#39;, h, &amp;#39;9&amp;#39; ]
        | a &amp;lt;- ops, b &amp;lt;- ops
        , c &amp;lt;- ops, d &amp;lt;- ops
        , e &amp;lt;- ops, f &amp;lt;- ops
        , g &amp;lt;- ops, h &amp;lt;- ops
        ]

result = runInterpreter $ do
  setImports [&amp;quot;Prelude&amp;quot;]
  exprs &amp;lt;- forM expressions evaluate
  pure $ filter (\(_, a) -&amp;gt; a == &amp;quot;100&amp;quot;) $ fromRight [] exprs
  where&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m trying to learn Haskell this year, so it was a great opportunity try to
follow along. I’m still working my way towards being able to run short snippets
- the &lt;code&gt;ghci&lt;/code&gt; tool for interactive use has a bit of a learning curve and doesn’t
immediately let me use the imports (or I’m doing something wrong) so while I
think I can follow the steps as presented, I can’t yet dig into them as
interactively as I’d like.&lt;/p&gt;
&lt;p&gt;The general idea, though, is to use a comprehension to expand all combinations of
the allowed operators (&lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;, and &lt;code&gt;*&lt;/code&gt;) between the values 1 to 9. I’m
somewhat familiar with comprehensions and played with them in my post&lt;br /&gt;
&lt;a href=&#34;https://jcarroll.com.au/2023/08/13/pythagorean-triples-with-comprehensions/&#34;&gt;Pythagorean Triples with Comprehensions&lt;/a&gt;
in several languages, including Haskell.&lt;/p&gt;
&lt;p&gt;I wanted to see how I might go about this problem in R, and I knew I’d need to make
some adjustments because R does not have comprehensions.&lt;/p&gt;
&lt;p&gt;One way to get all the combinations of operators between the values is to use
&lt;code&gt;expand.grid()&lt;/code&gt; which generates all combinations of its inputs&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;expand.grid(1:3, letters[1:3])&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   Var1 Var2
## 1    1    a
## 2    2    a
## 3    3    a
## 4    1    b
## 5    2    b
## 6    3    b
## 7    1    c
## 8    2    c
## 9    3    c&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Defining the operators as strings, I can generate a &lt;code&gt;data.frame&lt;/code&gt; of the values and
all combinations of operators between them&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ops &amp;lt;- c(&amp;quot;*&amp;quot;, &amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;/&amp;quot;)
combos &amp;lt;- expand.grid(1, ops, 2, ops, 3, ops, 4, ops, 5, ops, 6, ops, 7, ops, 8, ops, 9)
head(combos)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   Var1 Var2 Var3 Var4 Var5 Var6 Var7 Var8 Var9 Var10 Var11 Var12 Var13 Var14
## 1    1    *    2    *    3    *    4    *    5     *     6     *     7     *
## 2    1    +    2    *    3    *    4    *    5     *     6     *     7     *
## 3    1    -    2    *    3    *    4    *    5     *     6     *     7     *
## 4    1    /    2    *    3    *    4    *    5     *     6     *     7     *
## 5    1    *    2    +    3    *    4    *    5     *     6     *     7     *
## 6    1    +    2    +    3    *    4    *    5     *     6     *     7     *
##   Var15 Var16 Var17
## 1     8     *     9
## 2     8     *     9
## 3     8     *     9
## 4     8     *     9
## 5     8     *     9
## 6     8     *     9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This generates a lot of combinations - with 4 possible operators in 8 possible
positions there are &lt;span class=&#34;math inline&#34;&gt;\(4^8\)&lt;/span&gt; = 65,536 combinations.&lt;/p&gt;
&lt;p&gt;Pasting these numbers and operators together into expressions&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;exprs &amp;lt;- apply(combos, 1, \(x) paste0(x, collapse = &amp;quot;&amp;quot;))
head(exprs)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;1*2*3*4*5*6*7*8*9&amp;quot; &amp;quot;1+2*3*4*5*6*7*8*9&amp;quot; &amp;quot;1-2*3*4*5*6*7*8*9&amp;quot;
## [4] &amp;quot;1/2*3*4*5*6*7*8*9&amp;quot; &amp;quot;1*2+3*4*5*6*7*8*9&amp;quot; &amp;quot;1+2+3*4*5*6*7*8*9&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I get something I can evaluate as if I typed &lt;code&gt;1*2*3&lt;/code&gt; into a console. I can get
the results of evaluating those with&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;results &amp;lt;- sapply(exprs, \(x) eval(parse(text = x)))
head(results)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 1*2*3*4*5*6*7*8*9 1+2*3*4*5*6*7*8*9 1-2*3*4*5*6*7*8*9 1/2*3*4*5*6*7*8*9 
##            362880            362881           -362879             90720 
## 1*2+3*4*5*6*7*8*9 1+2+3*4*5*6*7*8*9 
##            181442            181443&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, I just need to see which of those produces a value of 100. Because &lt;code&gt;sapply&lt;/code&gt;
produced a vector with the expression itself as the name, I can extract the names
of the results which are equal to 100&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;answers &amp;lt;- names(which(results == 100))
answers&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] &amp;quot;1*2*3-4*5+6*7+8*9&amp;quot; &amp;quot;1+2+3-4*5+6*7+8*9&amp;quot; &amp;quot;1+2-3*4-5+6*7+8*9&amp;quot;
##  [4] &amp;quot;1-2*3-4-5+6*7+8*9&amp;quot; &amp;quot;1+2-3*4+5*6+7+8*9&amp;quot; &amp;quot;1-2*3-4+5*6+7+8*9&amp;quot;
##  [7] &amp;quot;1-2*3+4*5+6+7+8*9&amp;quot; &amp;quot;1*2*3+4+5+6+7+8*9&amp;quot; &amp;quot;1+2+3+4+5+6+7+8*9&amp;quot;
## [10] &amp;quot;1+2*3+4*5-6+7+8*9&amp;quot; &amp;quot;1+2*3*4*5/6+7+8*9&amp;quot; &amp;quot;1*2*3*4+5+6-7+8*9&amp;quot;
## [13] &amp;quot;1*2*3*4+5+6+7*8+9&amp;quot; &amp;quot;1-2+3*4*5-6+7*8-9&amp;quot; &amp;quot;1-2+3*4*5+6*7+8-9&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Any of those can easily be verified manually&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;1*2*3*4+5+6+7*8+9&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 100&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One thing I noticed here was that I have one more result than the Haskell post
produces&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;length(answers)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 15&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One of the answers stands out in that it contains a division, and sure enough this
is the one that doesn’t appear in the Haskell post. I’m not quite sure why - I
think the operator precedence is the same between R and Haskell, at least in terms
of these expressions&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;3 / 2 + 1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2.5&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;ghci&amp;gt; 3 / 2 + 1
2.5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But since I haven’t yet been able to actually &lt;em&gt;run&lt;/em&gt; that Haskell code myself, I can’t
verify those solutions.&lt;/p&gt;
&lt;p&gt;My R solution to this puzzle is then&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ops &amp;lt;- c(&amp;quot;*&amp;quot;, &amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;/&amp;quot;)
combos &amp;lt;- expand.grid(1, ops, 2, ops, 3, ops, 4, ops, 5, ops, 6, ops, 7, ops, 8, ops, 9)
exprs &amp;lt;- apply(combos, 1, \(x) paste0(x, collapse = &amp;quot;&amp;quot;))
results &amp;lt;- sapply(exprs, \(x) eval(parse(text = x)))
names(which(results == 100))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I did want to try a language which &lt;em&gt;does&lt;/em&gt; have comprehensions - let’s try Julia!&lt;/p&gt;
&lt;p&gt;Setting up the comprehension makes for a bit of a long line, but comes out okay&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;ops = [&amp;#39;+&amp;#39;, &amp;#39;-&amp;#39;, &amp;#39;*&amp;#39;, &amp;#39;/&amp;#39;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 4-element Vector{Char}:
##  &amp;#39;+&amp;#39;: ASCII/Unicode U+002B (category Sm: Symbol, math)
##  &amp;#39;-&amp;#39;: ASCII/Unicode U+002D (category Pd: Punctuation, dash)
##  &amp;#39;*&amp;#39;: ASCII/Unicode U+002A (category Po: Punctuation, other)
##  &amp;#39;/&amp;#39;: ASCII/Unicode U+002F (category Po: Punctuation, other)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;exprs = [&amp;#39;1&amp;#39; * a * &amp;#39;2&amp;#39; * b * &amp;#39;3&amp;#39; * c * &amp;#39;4&amp;#39; * d * &amp;#39;5&amp;#39; * e * &amp;#39;6&amp;#39; * f * &amp;#39;7&amp;#39; * g * &amp;#39;8&amp;#39; * h * &amp;#39;9&amp;#39; 
         for a in ops, b in ops, c in ops, 
             d in ops, e in ops, f in ops, 
             g in ops, h in ops];
first(exprs, 10)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 10-element Vector{String}:
##  &amp;quot;1+2+3+4+5+6+7+8+9&amp;quot;
##  &amp;quot;1-2+3+4+5+6+7+8+9&amp;quot;
##  &amp;quot;1*2+3+4+5+6+7+8+9&amp;quot;
##  &amp;quot;1/2+3+4+5+6+7+8+9&amp;quot;
##  &amp;quot;1+2-3+4+5+6+7+8+9&amp;quot;
##  &amp;quot;1-2-3+4+5+6+7+8+9&amp;quot;
##  &amp;quot;1*2-3+4+5+6+7+8+9&amp;quot;
##  &amp;quot;1/2-3+4+5+6+7+8+9&amp;quot;
##  &amp;quot;1+2*3+4+5+6+7+8+9&amp;quot;
##  &amp;quot;1-2*3+4+5+6+7+8+9&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That produces an array with many dimensions&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;size(exprs)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## (4, 4, 4, 4, 4, 4, 4, 4)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so it needs to be flattened into a vector with &lt;code&gt;vec()&lt;/code&gt;. From there, it’s similar
to the R approach and I can use a &lt;code&gt;eval(Meta.parse())&lt;/code&gt; pattern, keeping in mind
that one can ‘broadcast’ scalar operations to vector operations with the dot
(&lt;code&gt;.&lt;/code&gt;) operator&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;results = eval.(Meta.parse.(vec(exprs)));
first(results, 10)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 10-element Vector{Real}:
##  45
##  41
##  44
##  42.5
##  39
##  35
##  38
##  36.5
##  46
##  34&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finding the values equal to 100 is similar to the R approach&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;exprs[findall(results .== 100)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 15-element Vector{String}:
##  &amp;quot;1*2*3*4+5+6+7*8+9&amp;quot;
##  &amp;quot;1-2+3*4*5+6*7+8-9&amp;quot;
##  &amp;quot;1-2+3*4*5-6+7*8-9&amp;quot;
##  &amp;quot;1+2+3+4+5+6+7+8*9&amp;quot;
##  &amp;quot;1*2*3+4+5+6+7+8*9&amp;quot;
##  &amp;quot;1-2*3+4*5+6+7+8*9&amp;quot;
##  &amp;quot;1+2*3+4*5-6+7+8*9&amp;quot;
##  &amp;quot;1-2*3-4+5*6+7+8*9&amp;quot;
##  &amp;quot;1+2-3*4+5*6+7+8*9&amp;quot;
##  &amp;quot;1+2*3*4*5/6+7+8*9&amp;quot;
##  &amp;quot;1*2*3*4+5+6-7+8*9&amp;quot;
##  &amp;quot;1-2*3-4-5+6*7+8*9&amp;quot;
##  &amp;quot;1+2-3*4-5+6*7+8*9&amp;quot;
##  &amp;quot;1+2+3-4*5+6*7+8*9&amp;quot;
##  &amp;quot;1*2*3-4*5+6*7+8*9&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and again we see the 15 answers including the one with a division, confirming the
R result.&lt;/p&gt;
&lt;p&gt;This was a fun exploration - I don’t think I would want to try to solve it &lt;em&gt;without&lt;/em&gt;
code, but the code solutions were a great opportunity to use a few different
languages.&lt;/p&gt;
&lt;p&gt;I suspect there are a few different ways of solving this apart from this brute-force
expanding of every combination, perhaps with a solver or something. If you have one, I’d
love to see it. I thought &lt;code&gt;@coolbutuseless&lt;/code&gt; had done something like this but the closest
I could find was &lt;a href=&#34;https://coolbutuseless.github.io/2021/12/09/lex-parse-and-evaluate-a-simple-s-expression-with-flexo/&#34;&gt;this post&lt;/a&gt;
which is slightly different.&lt;/p&gt;
&lt;p&gt;If you have comments, suggestions, or improvements, as always, feel free to use
the comment section below, or hit me up on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.3 (2024-02-29)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2024-07-06
##  pandoc   3.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.18    2023-06-19 [1] CRAN (R 4.3.2)
##  bookdown      0.36    2023-10-16 [1] CRAN (R 4.3.2)
##  bslib         0.6.1   2023-11-28 [3] CRAN (R 4.3.2)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [1] CRAN (R 4.3.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.3.2)
##  digest        0.6.34  2024-01-11 [3] CRAN (R 4.3.2)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.23    2023-11-01 [3] CRAN (R 4.3.2)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  glue          1.7.0   2024-01-09 [1] CRAN (R 4.3.3)
##  htmltools     0.5.7   2023-11-03 [3] CRAN (R 4.3.2)
##  htmlwidgets   1.6.2   2023-03-17 [1] CRAN (R 4.3.2)
##  httpuv        1.6.12  2023-10-23 [1] CRAN (R 4.3.2)
##  icecream      0.2.1   2023-09-27 [1] CRAN (R 4.3.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.8   2023-12-04 [3] CRAN (R 4.3.2)
##  JuliaCall     0.17.5  2022-09-08 [1] CRAN (R 4.3.3)
##  knitr         1.45    2023-10-30 [3] CRAN (R 4.3.2)
##  later         1.3.1   2023-05-02 [1] CRAN (R 4.3.2)
##  lifecycle     1.0.4   2023-11-07 [1] CRAN (R 4.3.3)
##  magrittr      2.0.3   2022-03-30 [1] CRAN (R 4.3.3)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.3.2)
##  pkgbuild      1.4.2   2023-06-26 [1] CRAN (R 4.3.2)
##  pkgload       1.3.3   2023-09-22 [1] CRAN (R 4.3.2)
##  prettyunits   1.2.0   2023-09-24 [3] CRAN (R 4.3.1)
##  processx      3.8.3   2023-12-10 [3] CRAN (R 4.3.2)
##  profvis       0.3.8   2023-05-02 [1] CRAN (R 4.3.2)
##  promises      1.2.1   2023-08-10 [1] CRAN (R 4.3.2)
##  ps            1.7.6   2024-01-18 [3] CRAN (R 4.3.2)
##  purrr         1.0.2   2023-08-10 [3] CRAN (R 4.3.1)
##  R6            2.5.1   2021-08-19 [1] CRAN (R 4.3.3)
##  Rcpp          1.0.11  2023-07-06 [1] CRAN (R 4.3.2)
##  remotes       2.4.2.1 2023-07-18 [1] CRAN (R 4.3.2)
##  rlang         1.1.4   2024-06-04 [1] CRAN (R 4.3.3)
##  rmarkdown     2.25    2023-09-18 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.8   2023-12-06 [3] CRAN (R 4.3.2)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.3.2)
##  shiny         1.7.5.1 2023-10-14 [1] CRAN (R 4.3.2)
##  stringi       1.8.3   2023-12-11 [3] CRAN (R 4.3.2)
##  stringr       1.5.1   2023-11-14 [3] CRAN (R 4.3.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.3.2)
##  usethis       2.2.2   2023-07-06 [1] CRAN (R 4.3.2)
##  vctrs         0.6.5   2023-12-01 [1] CRAN (R 4.3.3)
##  xfun          0.41    2023-11-01 [3] CRAN (R 4.3.2)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.3.2)
##  yaml          2.3.8   2023-12-11 [3] CRAN (R 4.3.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Iterative Square Root</title>
      <link>https://jcarroll.com.au/2024/05/29/iterative-square-root/</link>
      <pubDate>Wed, 29 May 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/05/29/iterative-square-root/</guid>
      <description>&lt;p&gt;I saw a toot celebrating a short, clean implementation of a square root
finding algorithm and wanted to dig a bit deeper into how it works, with a
diversion into some APL.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://hachyderm.io/@jimgar/112521236754983554&#34;&gt;This&lt;/a&gt; was the toot from Jim
Gardner&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Doubly pleased with myself.&lt;/p&gt;
&lt;p&gt;Been doing the Tour of Go. Got to the section where you make a square root function, which should return once the calculated value stops changing. Struggled for ages. Trimmed and trimmed. Until finally… this!&lt;/p&gt;
&lt;p&gt;The calculation for z was given, and I don’t understand it at all. But I don’t care. It was a total mess when I started and has turned out quite neat. I’m very satisfied.&lt;/p&gt;
&lt;p&gt;But why “doubly pleased”? Because I’ve been solely using Neovim so far for Go!!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;package main 

import ( 
	&amp;quot;fmt&amp;quot; 
) 

func Sqrt(x float64) float64 {
	z := 1.0 
	for { 
		y := z 
		z -= (z*z - x) / (2 * z) 
		
		if z == y { 
			return z 
		} 
	}
} 

func main() { 
	fmt.Println(Sqrt(16)) 
} &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s a nice, not-too-complicated algorithm to play with, and I agree it’s hard to
see &lt;em&gt;why&lt;/em&gt; it works for this application, so I thought it would be neat to walk
through that.&lt;/p&gt;
&lt;p&gt;What we’re trying to solve here is the function &lt;span class=&#34;math inline&#34;&gt;\(y = x^2\)&lt;/span&gt; which we could write as
&lt;span class=&#34;math inline&#34;&gt;\(f(x) = x^2 - y\)&lt;/span&gt; for which we want the value &lt;span class=&#34;math inline&#34;&gt;\(x\)&lt;/span&gt; where &lt;span class=&#34;math inline&#34;&gt;\(f(x) = 0\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Newton%27s_method&#34;&gt;Newton’s Method&lt;/a&gt; is an iterative
method for solving equations of this type (not all equations, mind you - I have an
entire chapter of my PhD thesis discussing exactly &lt;em&gt;why&lt;/em&gt; it can’t be used to
solve the equations I was solving that my supervisor insisted it could). It works
by using the slope (derivative) at a point to guide towards a solution. The formula
for the updated value &lt;span class=&#34;math inline&#34;&gt;\(x_{n+1}\)&lt;/span&gt; given some guess &lt;span class=&#34;math inline&#34;&gt;\(x_n\)&lt;/span&gt; is&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[
x_{n+1} = x_n - \frac{f(x_n)}{f&amp;#39;(x_n)}
\]&lt;/span&gt;
where &lt;span class=&#34;math inline&#34;&gt;\(f&amp;#39;(x)\)&lt;/span&gt; is the derivative of the function &lt;span class=&#34;math inline&#34;&gt;\(f\)&lt;/span&gt; at the point &lt;span class=&#34;math inline&#34;&gt;\(x\)&lt;/span&gt;. For &lt;span class=&#34;math inline&#34;&gt;\(f(x) = x^2 - y\)&lt;/span&gt;
the derivative is &lt;span class=&#34;math inline&#34;&gt;\(f&amp;#39;(x) = 2x\)&lt;/span&gt; so we can substitute this and &lt;span class=&#34;math inline&#34;&gt;\(f(x)\)&lt;/span&gt; into the above formula&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[
x_{n+1}​=x_n​−\frac{x_n^2-y}{2x_n}
\]&lt;/span&gt;
This is what the Go code calculates; given an initial guess of &lt;span class=&#34;math inline&#34;&gt;\(x_n = 1\)&lt;/span&gt; it calculates the next value as&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;x = x - (x*x - y) / (2 * x) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where, here, &lt;code&gt;y&lt;/code&gt; is the value we’re finding the square root of.&lt;/p&gt;
&lt;p&gt;In R this could be written as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;SQRT &amp;lt;- function(x) {
  z &amp;lt;- 1
  while (TRUE) {
    y &amp;lt;- z
    z &amp;lt;- z - (z*z - x)/(2*z)
    if (abs(y -z) &amp;lt; 0.0001) return(z)
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(since &lt;code&gt;base::sqrt&lt;/code&gt; is already defined) where I’ve used a tolerance rather than
relying on exact numerical equality. The &lt;code&gt;while(TRUE)&lt;/code&gt; construct is equivalent
to Go’s &lt;code&gt;for {}&lt;/code&gt; syntax; an infinite loop.&lt;/p&gt;
&lt;p&gt;R actually has another way to write that which is even closer; &lt;code&gt;repeat {}&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;SQRT &amp;lt;- function(x) {
  z &amp;lt;- 1
  repeat {
    y &amp;lt;- z
    z &amp;lt;- z - (z*z - x)/(2*z)
    if (abs(y -z) &amp;lt; 0.0001) return(z)
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One might notice that this approach requires essentially squaring a value, which
is hardly expensive, but we can simplify and cancel out &lt;span class=&#34;math inline&#34;&gt;\(x_n\)&lt;/span&gt;, so&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[
x_{n+1}​=\frac{x_n-\frac{y}{x_n}}{2}
\]&lt;/span&gt;
in which case we have&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;SQRT &amp;lt;- function(x) {
  z &amp;lt;- 1
  repeat {
    y &amp;lt;- z
    z &amp;lt;- (z + x/z)/2
    if (abs(y -z) &amp;lt; 0.0001) return(z)
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One of the reasons I wanted to dig into this was the fact that it’s a convergence…&lt;/p&gt;
&lt;p&gt;In APL the power operator (&lt;code&gt;⍣&lt;/code&gt; &lt;a href=&#34;https://aplwiki.com/wiki/Power_(operator)&#34;&gt;aplwi&lt;/a&gt;)
applies a function some specified number of times, so&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;    f ⍣n x&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;applies &lt;code&gt;f&lt;/code&gt; to &lt;code&gt;x&lt;/code&gt; &lt;code&gt;n&lt;/code&gt; times, i.e. &lt;code&gt;(f⍣3)x&lt;/code&gt; produces &lt;code&gt;f(f(f(x)))&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It can also be used as &lt;code&gt;⍣=&lt;/code&gt; where it will continue to apply the function until
the output no longer changes (is equal). A classic example is the
&lt;a href=&#34;https://en.wikipedia.org/wiki/Golden_ratio&#34;&gt;golden ratio&lt;/a&gt;; take the reciprocal
then add 1 until it converges, i.e. &lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[
x_{n+1} = 1+\frac{1}{x_n}
\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;which you can try for yourself
&lt;a href=&#34;https://tryapl.org/?clear&amp;amp;q=1%2B%E2%88%98%C3%B7%E2%8D%A3%3D1&amp;amp;run&#34;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;    1+∘÷⍣=1
1.618033989&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this, &lt;code&gt;+∘÷&lt;/code&gt; is the (&lt;a href=&#34;https://aplwiki.com/wiki/Tacit&#34;&gt;tacit&lt;/a&gt;) function created by
composing (&lt;code&gt;∘&lt;/code&gt;) ‘addition of 1’ (&lt;code&gt;1+&lt;/code&gt;, a partial application of a function) and
‘reciprocal’ (&lt;code&gt;÷&lt;/code&gt;), which is iterated until it no longer changes (within
machine precision).&lt;/p&gt;
&lt;p&gt;Iterating until convergence is exactly what we want, since we’re looking for the
value satisfying&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[
x_n = x_{n+1}​=\frac{x_n-\frac{y}{x_n}}{2}
\]&lt;/span&gt;
APL uses &lt;code&gt;⍵&lt;/code&gt; as the right argument placeholder and &lt;code&gt;⍺&lt;/code&gt; as the left, so the
function we want to apply repeatedly to the right argument is&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;    {⍵-(((⍵×⍵)-⍺)÷(2×⍵))}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we provide &lt;code&gt;1&lt;/code&gt; as the right argument (the start value) and &lt;code&gt;16&lt;/code&gt; as the left
argument, we get&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;    16{⍵-(((⍵×⍵)-⍺)÷(2×⍵))}⍣=1
4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can try this out yourself at &lt;a href=&#34;https://tryapl.org/?clear&amp;amp;q=16%7B%E2%8D%B5-(((%E2%8D%B5%C3%97%E2%8D%B5)-%E2%8D%BA)%C3%B7(2%C3%97%E2%8D%B5))%7D%E2%8D%A3%3D1&amp;amp;run&#34;&gt;tryapl.org&lt;/a&gt;
(link should load that expression).&lt;/p&gt;
&lt;p&gt;We can turn that into a function, once again using the argument placeholder&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;    sqrt←{⍵{⍵-(((⍵×⍵)-⍺)÷(2×⍵))}⍣=1}
    sqrt 25
5
    sqrt 81
9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Taking the simplification above, we can write this a bit shorter as&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      sqrt←{⍵{(⍵+(⍺÷⍵))÷2}⍣=1}
      sqrt 144
12&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As clean as the Go code looks, I think there’s a certain beauty to being able
to write this in just 20 characters. It’s not for everyone, I get that.&lt;/p&gt;
&lt;p&gt;I love these opportunities to learn a bit more about languages.&lt;/p&gt;
&lt;p&gt;If you have comments, suggestions, or improvements, as always, feel free to use
the comment section below, or hit me up on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.3 (2024-02-29)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2024-05-29
##  pandoc   3.1.11 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.18    2023-06-19 [1] CRAN (R 4.3.2)
##  bookdown      0.36    2023-10-16 [1] CRAN (R 4.3.2)
##  bslib         0.6.1   2023-11-28 [3] CRAN (R 4.3.2)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.2   2023-12-11 [3] CRAN (R 4.3.2)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.3.2)
##  digest        0.6.34  2024-01-11 [3] CRAN (R 4.3.2)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.23    2023-11-01 [3] CRAN (R 4.3.2)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  glue          1.7.0   2024-01-09 [3] CRAN (R 4.3.2)
##  htmltools     0.5.7   2023-11-03 [3] CRAN (R 4.3.2)
##  htmlwidgets   1.6.2   2023-03-17 [1] CRAN (R 4.3.2)
##  httpuv        1.6.12  2023-10-23 [1] CRAN (R 4.3.2)
##  icecream      0.2.1   2023-09-27 [1] CRAN (R 4.3.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.8   2023-12-04 [3] CRAN (R 4.3.2)
##  knitr         1.45    2023-10-30 [3] CRAN (R 4.3.2)
##  later         1.3.1   2023-05-02 [1] CRAN (R 4.3.2)
##  lifecycle     1.0.4   2023-11-07 [3] CRAN (R 4.3.2)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.3.2)
##  pkgbuild      1.4.2   2023-06-26 [1] CRAN (R 4.3.2)
##  pkgload       1.3.3   2023-09-22 [1] CRAN (R 4.3.2)
##  prettyunits   1.2.0   2023-09-24 [3] CRAN (R 4.3.1)
##  processx      3.8.3   2023-12-10 [3] CRAN (R 4.3.2)
##  profvis       0.3.8   2023-05-02 [1] CRAN (R 4.3.2)
##  promises      1.2.1   2023-08-10 [1] CRAN (R 4.3.2)
##  ps            1.7.6   2024-01-18 [3] CRAN (R 4.3.2)
##  purrr         1.0.2   2023-08-10 [3] CRAN (R 4.3.1)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.11  2023-07-06 [1] CRAN (R 4.3.2)
##  remotes       2.4.2.1 2023-07-18 [1] CRAN (R 4.3.2)
##  rlang         1.1.3   2024-01-10 [3] CRAN (R 4.3.2)
##  rmarkdown     2.25    2023-09-18 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.8   2023-12-06 [3] CRAN (R 4.3.2)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.3.2)
##  shiny         1.7.5.1 2023-10-14 [1] CRAN (R 4.3.2)
##  stringi       1.8.3   2023-12-11 [3] CRAN (R 4.3.2)
##  stringr       1.5.1   2023-11-14 [3] CRAN (R 4.3.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.3.2)
##  usethis       2.2.2   2023-07-06 [1] CRAN (R 4.3.2)
##  vctrs         0.6.5   2023-12-01 [3] CRAN (R 4.3.2)
##  xfun          0.41    2023-11-01 [3] CRAN (R 4.3.2)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.3.2)
##  yaml          2.3.8   2023-12-11 [3] CRAN (R 4.3.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>I Patched R to Solve an Exercism Problem</title>
      <link>https://jcarroll.com.au/2024/02/26/i-patched-r-to-solve-an-exercism-problem/</link>
      <pubDate>Mon, 26 Feb 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/02/26/i-patched-r-to-solve-an-exercism-problem/</guid>
      <description>&lt;p&gt;With a serious yak shaving deviation, I have a really short “cheat” solution to
one of the featured Exercism problems. It’s been a really insightful journey
getting to this point, and as always I’ve learned a lot along the way. The fact
that I &lt;em&gt;was&lt;/em&gt; able to understand the required changes and propose them is thanks
to the open-source nature of programming languages.&lt;/p&gt;
&lt;p&gt;This all started out innocently enough - I’ve been using
&lt;a href=&#34;https://exercism.org/&#34;&gt;Exercism.org&lt;/a&gt; to get a feel for a lot of other
programming languages. Last year they hosted the 12in23 challenge where they
invited users to try out one programming language each month, solving 5
non-trivial (beyond printing &lt;code&gt;&#34;Hello, World!&#34;&lt;/code&gt;) exercises in any of a handful of
featured languages, with a different ‘theme’ (functional, object-oriented,
low-level, …) each month.&lt;/p&gt;
&lt;p&gt;I ended up earning the “polyglot” badge for completing this, but I actually ended
up doing a lot more&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/12in23.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;I found this to be an extremely useful exercise in finding out what I did and
didn’t like about different languages, and I’m diving a lot deeper into the ones
I enjoyed the most. Worthwhile, but certainly an involved challenge as I solved
all the exercises locally on my own machine, which means I had to install each
of the languages and get their test suites working. My laptop is now capable of
running code in more than 20 languages.&lt;/p&gt;
&lt;p&gt;This year, Exercism are hosting a 48in24 challenge where rather than just
needing to use one language to solve several problems in a month, it’s one
problem in three languages in a week. Spending a month to get up to speed with a
language I’d never seen (or installed) was one thing, but now I potentially need
to do that three times over in a week when the languages are all new to me. Still, I
persist, and so far I’m keeping up.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/48in24_feb.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;One of the featured problems was ‘Roman Numerals’ where we need to write an
algorithm to convert integers into Roman numerals. The featured languages were Julia
(I’m already familiar, nice), Elixir (fine, I get to learn what that looks like), and
(Pharo) smalltalk, which needs its own IDE and is a workflow entirely distinct from
anything I’ve done before. I won’t be willingly writing any more smalltalk in the
near future.&lt;/p&gt;
&lt;p&gt;When I saw that this was the challenge problem I was delighted - I know that R
already has &lt;code&gt;as.roman()&lt;/code&gt; in the standard library!&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as.roman(2024)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] MMXXIV&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It even does math with these values - I base most of my real-life conversations with
my wife around Simpsons quotes so I’m all-too familiar with this bit&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/bart_roman.jpg&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Bart enters the backstage of the lion enclosure at a zoo and sees a sign:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Caution: exit through door 7 only. All other rooms contain man-eating tigers.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;“Think, Bart. Where have you seen Roman numerals before? I know… Rocky V! That was the fifth one. So, Rocky five plus Rocky two equals… Rocky VII!”Adrian’s Revenge”!”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;R can do this math just fine&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;(five &amp;lt;- as.roman(5))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] V&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;(two &amp;lt;- as.roman(2))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] II&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;five + two&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] VII&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s more than just concatenating those, of course&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;(five + two) * 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] XIV&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I downloaded the exercise and fired up RStudio. I edited the exercise template
to just pass the input argument to &lt;code&gt;as.roman()&lt;/code&gt; and hit ‘Run Tests’… all tests
failed 😢&lt;/p&gt;
&lt;p&gt;Ah, &lt;code&gt;as.roman()&lt;/code&gt; returns an object of class &lt;code&gt;roman&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;class(as.roman(321))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;roman&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the tests have an &lt;code&gt;expect_equal()&lt;/code&gt; (not &lt;code&gt;expect_equivalent()&lt;/code&gt;)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;test_that(&amp;quot;48 is XLVIII&amp;quot;, {
  expect_equal(roman(48), &amp;quot;XLVIII&amp;quot;)
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, so it won’t be &lt;em&gt;perfectly&lt;/em&gt; clean, but it just need to be re-classed&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as.character(as.roman(2024))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;MMXXIV&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Re-run the tests, and…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;── Failure (&amp;#39;test_roman-numerals.R:105:3&amp;#39;): 3999 is MMMCMXCIX ──────────────────
roman(3999) not equal to &amp;quot;MMMCMXCIX&amp;quot;.
1/1 mismatches
x[1]: NA
y[1]: &amp;quot;MMMCMXCIX&amp;quot;

[ FAIL 1 | WARN 0 | SKIP 0 | PASS 25 ]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What? twenty-five tests pass, one fails? And produces &lt;code&gt;NA&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Back to the problem statement, it says&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For this exercise, we are only concerned about traditional Roman numerals, in which the largest number is MMMCMXCIX (or 3,999).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, why does that fail? I checked the docs for &lt;code&gt;as.roman()&lt;/code&gt; and it says&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Only numbers between 1 and 3899 have a unique representation as roman numbers, and hence others result in as.roman(NA).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Odd.&lt;/p&gt;
&lt;p&gt;I checked out some other languages. The intro video for the problem mentions another
“cheat” solution which is to use Common Lisp, because that has a formatter. Using &lt;a href=&#34;https://www.gnu.org/software/clisp/&#34;&gt;GNU
Common Lisp&lt;/a&gt;…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;(format nil &amp;quot;~@R&amp;quot; 2024)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;&amp;quot;MMXXIV&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Trying out this last value works&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;(format nil &amp;quot;~@R&amp;quot; 3999)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;&amp;quot;MMMCMXCIX&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and a too-large value produces an informative error&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;(format nil &amp;quot;~@R&amp;quot; 4000)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt; The ~@R format directive requires an integer in the range 1 - 3999, not 4000&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, the limit does seem to be 3999, not 3899. Checking &lt;a href=&#34;https://en.wikipedia.org/wiki/Roman_numerals&#34;&gt;Wikipedia&lt;/a&gt;,
that also seems to be the case. I also found a &lt;a href=&#34;https://www.oreilly.com/library/view/python-cookbook/0596001673/ch03s24.html&#34;&gt;python implementation&lt;/a&gt;
which goes up to 3999.&lt;/p&gt;
&lt;p&gt;So, why won’t R convert those last 100 numbers?&lt;/p&gt;
&lt;p&gt;I dug around the source code (an accessible copy is on &lt;a href=&#34;https://github.com/wch/r-source&#34;&gt;GitHub&lt;/a&gt;
but the “real” copy is on SVN) and found several references to the 3899 limit, none
of which could be circumvented.&lt;/p&gt;
&lt;p&gt;I posted a quick summary of the issue I saw on &lt;a href=&#34;https://jcarroll.xyz/2024/02/10/friends-romans-countrymen.html&#34;&gt;my side-blog&lt;/a&gt;
hoping that it was something I just misunderstood.&lt;/p&gt;
&lt;p&gt;I asked around on Mastodon, and no one was sure why this was the case. The next step
was to email the R-devel mailing list. I don’t do this lightly, as it has a reputation
for not being the friendliest place. Kurt Hornik, who originally wrote the
implementation back in 2006 replied and agreed that it was probably just an oversight.&lt;/p&gt;
&lt;p&gt;He asked if I could file the bug in &lt;a href=&#34;https://bugs.r-project.org/&#34;&gt;Bugzilla&lt;/a&gt; the R bug tracker
… and asked if I could also add a patch. At this point, I remembered what I was
doing in the first place - solving an Exercism problem.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/dominoes.jpg&#34; /&gt;&lt;/p&gt;
&lt;p&gt;The term “Yak Shaving” means performing some task that appears entirely unrelated to
what you were originally trying to do, usually as a result of several other related tasks. It’s
summarised well in this clip from the TV show ‘Malcolm in the Middle’&lt;/p&gt;
&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube.com/embed/8fnfeuoh4s8?si=73eXUC2-vy9NC1q2&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;!-- https://youtu.be/8fnfeuoh4s8?si=73eXUC2-vy9NC1q2 --&gt;
&lt;p&gt;where the character goes to change a lightbulb but finds that the shelf is
coming loose, so he gets a screwdriver from a drawer and notices that the drawer
isn’t running smoothly, so he gets some lubricant but it’s empty so he gets in
his car to go to the store to buy more but the car sounds funny, so he tries fixing that…
When his wife asks him “are you going to replace that lightbulb” he yells - appearing
from underneath the car covered in grease - “what does it look like I’m doing???”.&lt;/p&gt;
&lt;p&gt;The absurdity being that “before you can complete this task, you need to shave a yak.”&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/yakshaving.jpg&#34; /&gt;&lt;/p&gt;
&lt;p&gt;In this scenario, someone is asking me “are you solving that Exercism problem?” and I’m
emerging from a console typing &lt;code&gt;make check-devel&lt;/code&gt; shouting “what does it look like
I’m doing?”.&lt;/p&gt;
&lt;p&gt;So, how do I submit a patch to R itself? I recalled that I detailed some
instructions for that the &lt;a href=&#34;https://jcarroll.com.au/2019/10/12/r-bugs-file-info-object-size/&#34;&gt;last time I was trying to resolve an R-related bug&lt;/a&gt;.
I pulled the bleeding-edge SVN commit and built R locally, which means&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;./configure --with-x=no --without-recommended-packages --disable-byte-compiled-packages --disable-java  &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;make -j4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to build the source (using 4 cores).&lt;/p&gt;
&lt;p&gt;Then, I searched for the values I might need to change by running&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;grep -R 3899 &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This turns up a bunch of files&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/nmath/qnorm.c:                         2.04426310338993978564e-15 + 1.4215117583164458887e-7)*
src/library/utils/all.R:        if(upper &amp;gt; 3899L)
src/library/utils/all.R:            stop(gettextf(&amp;quot;too many list items (at most up to %d)&amp;quot;, 3899L),
src/library/utils/man/roman.Rd:  Only numbers between 1 and 3899 have a unique representation as roman
src/library/utils/man/roman.Rd:## simple consistency checks -- arithmetic when result is in  {1,2,..,3899} :
src/library/utils/man/format.Rd:    numerals (with the number of the last item maximally 3899).
src/library/utils/R/format.R:        if(upper &amp;gt; 3899L)
src/library/utils/R/format.R:            stop(gettextf(&amp;quot;too many list items (at most up to %d)&amp;quot;, 3899L),
src/library/utils/po/R-de.po:#~ msgid &amp;quot;too many list items (at most up to number 3899)&amp;quot;
src/library/utils/po/R-de.po:#~ msgstr &amp;quot;zu viele Listenelemente (höchstens 3899!)&amp;quot;
src/library/utils/po/R-fr.po:#~ msgid &amp;quot;too many list items (at most up to number 3899)&amp;quot;
src/library/utils/po/R-fr.po:#~ msgstr &amp;quot;trop d&amp;#39;entrées de liste (3899 maximum)&amp;quot;
src/library/utils/po/R-ja.po:#~ msgid &amp;quot;too many list items (at most up to number 3899)&amp;quot;
src/library/utils/po/R-ja.po:#~ msgstr &amp;quot; リストの項目が多すぎます（最大でも3899です） &amp;quot;
src/library/utils/po/R-zh_CN.po:#~ msgid &amp;quot;too many list items (at most up to number 3899)&amp;quot;
src/library/utils/po/R-zh_CN.po:#~ msgstr &amp;quot;串列项太多(最多只能有3899项(&amp;quot;
src/library/utils/po/R-ru.po:#~ msgid &amp;quot;too many list items (at most up to number 3899)&amp;quot;
grep: src/library/utils/po/R-ru.po: binary file matches
src/library/stats/tests/ppr_test.csv:&amp;quot;153&amp;quot;,0.0669524872438994,1,0.970846742038665
src/main/g_her_glyph.c:  /******** Hershey Glyphs 3800 to 3899 ********/
src/main/g_her_glyph.c:  /******** Oriental Hershey Glyphs 3800 to 3899 ********/
tests/d-p-q-r-tests.Rout: [1] 0.340823726 0.100413165 0.293668976 0.389968983 0.124439520 0.207270198
tests/reg-examples2.Rout:Zambia          0.16361 -0.07917 -0.33899  0.09406  0.228232  0.7482 0.512
tests/lm-tests.Rout.save:Zambia          0.16361 -0.07917 -0.33899  0.09406  0.228232  0.7482 0.512
tests/lm-tests.Rout:Zambia          0.16361 -0.07917 -0.33899  0.09406  0.228232  0.7482 0.512
tests/d-p-q-r-tests.Rout.save: [1] 0.340823726 0.100413165 0.293668976 0.389968983 0.124439520 0.207270198
tests/Examples/stats-Ex.Rout.save:[49]  0.29918521  0.05938999 -0.20355761 -0.02439309 -1.14548572 -0.94045141
tests/Examples/stats-Ex.Rout.save: 0.05510098  0.59958858  1.14407618  1.68856379  2.23305139  2.77753899 
tests/Examples/stats-Ex.Rout.save:9   0.7335126 -1.3468740  2.8138992
tests/Examples/stats-Ex.Rout:[49]  0.29918521  0.05938999 -0.20355761 -0.02439309 -1.14548572 -0.94045141
tests/Examples/stats-Ex.Rout: 0.05510098  0.59958858  1.14407618  1.68856379  2.23305139  2.77753899 
tests/Examples/stats-Ex.Rout:9   0.7335126 -1.3468740  2.8138992&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Many of these I could ignore - float values which happen to match. But many were familiar
from when I was digging through the source.&lt;/p&gt;
&lt;p&gt;I took the first of these &lt;code&gt;src/library/utils/all.R&lt;/code&gt; and edited the value from 3899 to 3999
then ran &lt;code&gt;svn status&lt;/code&gt; and a lot of files were marked &lt;code&gt;?&lt;/code&gt; (untracked) while none were
&lt;code&gt;M&lt;/code&gt; (modified). This confused me, until I realised that as part of the build process, R creates
these &lt;code&gt;all.R&lt;/code&gt; files which aren’t the source-of-truth for the code. Changing, instead,
&lt;code&gt;src/library/utils/R/format.R&lt;/code&gt; the changes were reflected in &lt;code&gt;svn status&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;format&lt;/code&gt; changes were from formatting functions I wasn’t previously familiar with, namely
&lt;code&gt;formatOL&lt;/code&gt; for “format ordered list” which prefixes a list of items&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;formatOL(paste0(&amp;quot;Chapter&amp;quot;, 1:5))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;1. Chapter1&amp;quot; &amp;quot;2. Chapter2&amp;quot; &amp;quot;3. Chapter3&amp;quot; &amp;quot;4. Chapter4&amp;quot; &amp;quot;5. Chapter5&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and can do the conversion&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;formatOL(paste0(&amp;quot;Chapter&amp;quot;, 1:5), type = &amp;quot;Roman&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;  I. Chapter1&amp;quot; &amp;quot; II. Chapter2&amp;quot; &amp;quot;III. Chapter3&amp;quot; &amp;quot; IV. Chapter4&amp;quot;
## [5] &amp;quot;  V. Chapter5&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and which produces an error if you try to pass in too many items (more than the critical value)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;formatOL(10:4010, type = &amp;quot;Roman&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-danger&#34;&gt;&lt;code&gt;Error in formatOL(10:4010, type = &amp;quot;roman&amp;quot;) : 
  too many list items (at most up to 3899)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In addition to the logic of the code itself, the .Rd files needed updating (base R does not
use Roxygen and automatic generation of man files) and the &lt;code&gt;.po&lt;/code&gt; files (language translations)
with the translated error messages (which I hopefully corrected accurately; my French is okay-ish and
that looks to be correct, and my Japanese is very beginner-level and I haven’t yet learned those
words).&lt;/p&gt;
&lt;p&gt;Since I had dug through the source, I knew that “3899” was not the only critical
value; there were some tests for &lt;code&gt;x &amp;gt;= 3900&lt;/code&gt; I needed to also take care of. This
was a useful point to note - if you’re going to change behaviour at a numeric
boundary, it’s probably a good idea to stick to either strictly greater than or
greater-than-or-equal if you want to make searching for that value straightforward.&lt;/p&gt;
&lt;p&gt;Searching for &lt;code&gt;3900&lt;/code&gt; again turns up a lot of false positives, but also&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src/library/utils/R/roman.R:    if(check.range) x[x &amp;lt;= 0L | x &amp;gt;= 3900L] &amp;lt;- NA
src/library/utils/R/roman.R:    ind &amp;lt;- is.na(x) | (x &amp;lt;= 0L) | (x &amp;gt;= 3900L)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so I edited those as well.&lt;/p&gt;
&lt;p&gt;Producing the requisite patch is then just&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;svn diff &amp;gt; as.roman-upper-limit.patch&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;creating the file I eventually attached to my Bugzilla report.&lt;/p&gt;
&lt;p&gt;Kurt Hornik approved these changes and merged them on my behalf (only R-core
members can merge into the source) so my changes should be reflected in the next
release.&lt;/p&gt;
&lt;p&gt;To prove to myself that this was done and dusted, I wanted to pull the latest
version again, but I didn’t want to risk that my local changes were what I was seeing.
Docker is a good option in this case (and may have been for the development itself).&lt;/p&gt;
&lt;p&gt;Beyond my previous instructions, I figured there were more up-to-date instructions out there.
&lt;a href=&#34;https://kbroman.org/blog/2020/12/03/debugging-with-docker-and-r-devel/&#34;&gt;This&lt;/a&gt;
is a slightly newer post about the process, but I eventually just copied the
&lt;a href=&#34;https://github.com/rocker-org/drd/blob/master/Dockerfile&#34;&gt;Dockerfile from rocker’s drd image&lt;/a&gt; and built the
most up-to-date image locally. This means that I was definitely running an independent installation of R
(in docker) and not my local copy (still distinct from my installed copy that RStudio sees).&lt;/p&gt;
&lt;p&gt;Using this docker image, I could confirm that my changes had been merged&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt; as.roman(3999)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[1] MMMCMXCIX&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;as well as the necessary translations; I noticed that a simple &lt;code&gt;Sys.setenv(LANGUAGE=&#34;ru&#34;)&lt;/code&gt;
worked once, but after that I couldn’t change the language again. The &lt;code&gt;{and}&lt;/code&gt; package
seemed to do the trick&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;formatOL(1:4000, type = &amp;quot;roman&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-danger&#34;&gt;&lt;code&gt;Error in formatOL(1:4000, type = &amp;quot;roman&amp;quot;) : 
  too many list items (at most up to 3999)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;and::set_language(&amp;quot;ru&amp;quot;)
formatOL(1:4000, type = &amp;quot;roman&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-danger&#34;&gt;&lt;code&gt;Ошибка в formatOL(1:4000, type = &amp;quot;roman&amp;quot;) :
  слишком много элементов в списке (самое большее 3999)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;and::set_language(&amp;quot;fr&amp;quot;)
formatOL(1:4000, type = &amp;quot;roman&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-danger&#34;&gt;&lt;code&gt;Erreur dans formatOL(1:4000, type = &amp;quot;roman&amp;quot;) : 
  trop d&amp;#39;entrées de listes (3999 maximum)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;and::set_language(&amp;quot;ja&amp;quot;)
formatOL(1:4000, type = &amp;quot;roman&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-danger&#34;&gt;&lt;code&gt; formatOL(1:4000, type = &amp;quot;roman&amp;quot;) でエラー: 
   リストの項目が多すぎます (最大でも 3999 です) &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;and::set_language(&amp;quot;de&amp;quot;)
formatOL(1:4000, type = &amp;quot;roman&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-danger&#34;&gt;&lt;code&gt;Fehler in formatOL(1:4000, type = &amp;quot;roman&amp;quot;) : 
  zu viele Listenpunkte (höchstens 3999)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;and::set_language(&amp;quot;zh_CN&amp;quot;)
formatOL(1:4000, type = &amp;quot;roman&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-danger&#34;&gt;&lt;code&gt;Error in formatOL(1:4000, type = &amp;quot;roman&amp;quot;) : 列表项太多(最多只能有3999项)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With all looking good on the R side, now I just need to wait for the changes to
be officially released and then for Exercism to update their version to that so
that I can submit my “cheat” one-line solution to the Roman Numerals exercise.&lt;/p&gt;
&lt;p&gt;I’ll be waiting!&lt;/p&gt;
&lt;p&gt;I’m hoping that the process described here can be of use to someone else who finds
a similar issue in the language; the process can be fairly straightforward, but I
believe success was dependent on a few key points;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;don’t &lt;em&gt;assume&lt;/em&gt; that the language is broken, it may be something you did wrong or
misunderstood&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;look through the source to confirm what you’re seeing and do your best to
understand it&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ask around; someone may be able to resolve the confusion or point you in the
right direction&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“it takes a village” - if you want it to get fixed, you might need to put in
some work.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And who knows, maybe it &lt;em&gt;is&lt;/em&gt; a bug that’s been there for the last 15+ years?&lt;/p&gt;
&lt;p&gt;This definitely ended up being more of an exercise than I planned, but I’m grateful
for Exercism prompting me to try out both languages I do and don’t know; for R being
open-source so I could find this bug; and for the wealth of knowledge out there
to figure out how to do all this.&lt;/p&gt;
&lt;p&gt;If you have any comments, feel free to use the comment section below, or hit me up on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.2 (2023-10-31)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2024-02-26
##  pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.18    2023-06-19 [1] CRAN (R 4.3.2)
##  bookdown      0.36    2023-10-16 [1] CRAN (R 4.3.2)
##  bslib         0.6.0   2023-11-21 [3] CRAN (R 4.3.2)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [3] CRAN (R 4.2.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.3.2)
##  digest        0.6.33  2023-07-07 [3] CRAN (R 4.3.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.23    2023-11-01 [3] CRAN (R 4.3.2)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  htmltools     0.5.7   2023-11-03 [3] CRAN (R 4.3.2)
##  htmlwidgets   1.6.2   2023-03-17 [1] CRAN (R 4.3.2)
##  httpuv        1.6.12  2023-10-23 [1] CRAN (R 4.3.2)
##  icecream      0.2.1   2023-09-27 [1] CRAN (R 4.3.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.7   2023-06-29 [3] CRAN (R 4.3.1)
##  knitr         1.45    2023-10-30 [3] CRAN (R 4.3.2)
##  later         1.3.1   2023-05-02 [1] CRAN (R 4.3.2)
##  lifecycle     1.0.4   2023-11-07 [3] CRAN (R 4.3.2)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.3.2)
##  pkgbuild      1.4.2   2023-06-26 [1] CRAN (R 4.3.2)
##  pkgload       1.3.3   2023-09-22 [1] CRAN (R 4.3.2)
##  prettyunits   1.2.0   2023-09-24 [3] CRAN (R 4.3.1)
##  processx      3.8.2   2023-06-30 [3] CRAN (R 4.3.1)
##  profvis       0.3.8   2023-05-02 [1] CRAN (R 4.3.2)
##  promises      1.2.1   2023-08-10 [1] CRAN (R 4.3.2)
##  ps            1.7.5   2023-04-18 [3] CRAN (R 4.3.0)
##  purrr         1.0.2   2023-08-10 [3] CRAN (R 4.3.1)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.11  2023-07-06 [1] CRAN (R 4.3.2)
##  remotes       2.4.2.1 2023-07-18 [1] CRAN (R 4.3.2)
##  rlang         1.1.2   2023-11-04 [3] CRAN (R 4.3.2)
##  rmarkdown     2.25    2023-09-18 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.7   2023-07-15 [3] CRAN (R 4.3.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.3.2)
##  shiny         1.7.5.1 2023-10-14 [1] CRAN (R 4.3.2)
##  stringi       1.8.2   2023-11-23 [3] CRAN (R 4.3.2)
##  stringr       1.5.1   2023-11-14 [3] CRAN (R 4.3.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.3.2)
##  usethis       2.2.2   2023-07-06 [1] CRAN (R 4.3.2)
##  vctrs         0.6.4   2023-10-12 [3] CRAN (R 4.3.1)
##  xfun          0.41    2023-11-01 [3] CRAN (R 4.3.2)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.3.2)
##  yaml          2.3.7   2023-01-23 [3] CRAN (R 4.2.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My First Julia Package - TriangulArt.jl </title>
      <link>https://jcarroll.com.au/2024/02/04/my-first-julia-package-triangulart-jl/</link>
      <pubDate>Sun, 04 Feb 2024 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2024/02/04/my-first-julia-package-triangulart-jl/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/2024/02/04/my-first-julia-package-triangulart-jl/images/triangularbird.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve tried to get this same image transformation working at least three times now, but
I can finally celebrate that it&amp;rsquo;s working! I&amp;rsquo;ve been (re-)learning Julia and I still
love the language, so it was time to take my learning to the next level and actually
build a package.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve tried to get this same image transformation working at least three times now, but
I can finally celebrate that it&amp;rsquo;s working! I&amp;rsquo;ve been (re-)learning Julia and I still
love the language, so it was time to take my learning to the next level and actually
build a package.&lt;/p&gt;
&lt;p&gt;For those not familiar, Julia is a much newer language than my daily-driver R, and with
that comes the freedom to take a lot of good features from other languages and implement
them. There are some features that R just won&amp;rsquo;t ever get, but they&amp;rsquo;re available in Julia and
they&amp;rsquo;re very nice to use.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve &lt;a href=&#34;https://github.com/jonocarroll/ProjectEuler_Julia&#34;&gt;written solutions&lt;/a&gt; to the first 20
or so &lt;a href=&#34;https://projecteuler.net/&#34;&gt;Project Euler&lt;/a&gt; problems in Julia &amp;hellip; wow, 5 years ago.&lt;/p&gt;
&lt;p&gt;More recently, I have solved the first 18 days of Advent of Code 2023 in Julia
(&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/tree/main/2023/Julia/AdventOfCode2023.jl/src&#34;&gt;my solutions&lt;/a&gt;
are in a fork of a package that I&amp;rsquo;m not using, so they more or less run independently).&lt;/p&gt;
&lt;p&gt;With those under my belt, I revisited a project I&amp;rsquo;ve tried to implement several times. I like
the &lt;a href=&#34;https://www.pinterest.com.au/pin/528961918725401844/visual-search/?x=16&amp;amp;y=16&amp;amp;w=532&amp;amp;h=532&amp;amp;surfaceType=flashlight&#34;&gt;low-poly look&lt;/a&gt; and wanted to recreate it - it&amp;rsquo;s just an image transformation,
right? I&amp;rsquo;m even somewhat familiar with &lt;a href=&#34;https://en.wikipedia.org/wiki/Delaunay_triangulation&#34;&gt;Delaunay Triangulation&lt;/a&gt;, or at least its dual the
&lt;a href=&#34;https://en.wikipedia.org/wiki/Voronoi_diagram&#34;&gt;Voronoi Tesselation&lt;/a&gt; from my days building spatial maps
of fishing areas.&lt;/p&gt;
&lt;p&gt;It &lt;em&gt;sounds&lt;/em&gt; like a simple enough problem; choose some points all over the image, triangulate between
all of them, then shade the resulting triangles with the average colour of the pixels they enclose.&lt;/p&gt;
&lt;p&gt;I found this nice image of a &lt;a href=&#34;https://www.australiangeographic.com.au/topics/wildlife/2020/12/the-most-counted-aussie-bird-of-2020/&#34;&gt;rainbow lorikeet&lt;/a&gt; (these frequent my backyard)&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/bird.jpg&#34; alt=&#34;Rainbow Lorikeet&#34;&gt;&lt;/p&gt;
&lt;p&gt;so I got to work trying to chop it up into triangles.&lt;/p&gt;
&lt;p&gt;Well, the naive approach &lt;em&gt;is&lt;/em&gt; simple enough, but it produces some terrible results. I&amp;rsquo;ve built that version into what I did eventually get working, and it&amp;rsquo;s&amp;hellip; not what I want&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/tri_bird_fast.svg&#34; alt=&#34;It works, but at what cost?&#34;&gt;&lt;/p&gt;
&lt;p&gt;The problem is that by randomly selecting points across the image, you lose all the structure. With
enough triangles you might recover some of that, but then you have a lot of triangles and lose that
low-poly vibe.&lt;/p&gt;
&lt;p&gt;After much searching for a better way to do this, I found &lt;a href=&#34;https://www.degeneratestate.org/posts/2017/May/24/images-to-triangles/&#34;&gt;this article&lt;/a&gt; from 2017. It&amp;rsquo;s
a python approach, but I figured I knew enough Julia and Python now that I could try to make
a 1:1 translation.&lt;/p&gt;
&lt;p&gt;The first step is to get the random sampling working, because it allows me to start testing
the triangulation parts quickly. Generating those is pretty clean&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-julia&#34; data-lang=&#34;julia&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;generate_uniform_random_points&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;Matrix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;RGB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;N0f8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}},&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;n_points&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;Integer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ymax&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;xmax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;rand&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;n_points&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.*&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;xmax&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ymax&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The triangulation itself is handled by &lt;code&gt;DelaunayTriangulation::triangulate()&lt;/code&gt; -
for once I&amp;rsquo;m happy that there&amp;rsquo;s so much scientific/statistical support in Julia&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rng = StableRNG(2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tri = triangulate(all_points; rng)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Slightly trickier is figuring out which points are in which triangle. For that, I am
thankful for &lt;code&gt;PolygonOps::inpolygon()&lt;/code&gt;. With the pixels for each triangle identified,
it was only a matter of averaging the R, G, and B channels to get the median colour.&lt;/p&gt;
&lt;p&gt;I got that working, but with the results above - far from pleasant. The next, much harder step,
was to weight the points towards the &amp;rsquo;edges&amp;rsquo; of the image. I couldn&amp;rsquo;t find an easy
way to translate the python code for locally sampling the entropy (via &lt;code&gt;skimage&lt;/code&gt;)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;filters&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rank&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;entropy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;im2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;morphology&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;disk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;entropy_width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;so I tried to build something of my own. I tried &lt;a href=&#34;https://juliaimages.org/stable/examples/contours/sujoy_edge_demo/&#34;&gt;edge-detection algorithms&lt;/a&gt; but
I was clearly doing something wrong with it. Partly, I suspect, not doing the down-weighting
that the python version includes.&lt;/p&gt;
&lt;p&gt;Since the pixels we want to up-weight are all along lines, choosing these at random can
end up with several right next to each other, which we don&amp;rsquo;t want. The python version does
something a little clever - it selects one point, then reduces the weighting of the entire image
with a Gaussian around that point, so that nearby points are unlikely to also be selected.&lt;/p&gt;
&lt;p&gt;In the end, I failed to find a good Julia alternative, but calling python code is (almost) as
simple as &lt;code&gt;using PyCall; @pyimport skimage as skimage&lt;/code&gt; (with slight modifications to use in a
package, as I would later discover).&lt;/p&gt;
&lt;p&gt;With that in place, I was able to successfully weight towards high-entropy regions; regions
where a larger number of bytes are required to encode a histogram of the grayscale pixels, i.e.
where there&amp;rsquo;s a lot going on. The results are much more pleasing&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/tri_bird.png&#34; alt=&#34;Entropy-weighted Delaunay Triangulation&#34;&gt;&lt;/p&gt;
&lt;p&gt;Along the way I added some debug features, such as plotting the vertices and edges of the
triangulation on top of the image&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/tri_bird_small_debug.svg&#34; alt=&#34;Debug mode&#34;&gt;&lt;/p&gt;
&lt;p&gt;With the workflow more or less working, I ran some profiling to see if I could
speed it up. Unsurprisingly, generating the weighted points was one area where a
lot of time was spent, though it&amp;rsquo;s not yet clear if that&amp;rsquo;s because it&amp;rsquo;s python
code or because that&amp;rsquo;s genuinely one of the most complex parts of the code - my
best Julia alternative was to write my own short Shannon entropy function and
make it search locally with &lt;code&gt;ImageFiltering::mapwindow&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-julia&#34; data-lang=&#34;julia&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shannon&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;AbstractMatrix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;cm&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;collect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;values&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;countmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sum&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;256&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;sum&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;log2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;mapwindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shannon&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;19&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;19&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;though, this creates a square subsampling, whereas the python version uses a nicer disk.&lt;/p&gt;
&lt;p&gt;The profiling shows a lot of blank areas, and I&amp;rsquo;m not sure how to interpret those&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/tri_profiling.png&#34; alt=&#34;Profile&amp;rsquo;s @profview output in VS Code&#34;&gt;&lt;/p&gt;
&lt;p&gt;I realised at this point that I actually didn&amp;rsquo;t know how long the python version takes
to run. I grabbed the &lt;a href=&#34;https://github.com/ijmbarr/images-to-triangles&#34;&gt;original source code&lt;/a&gt;
and tried running it (after installing the relevant python packages) but it failed -
some packages had changed their arguments and signatures since this was written. A couple
of &lt;a href=&#34;https://github.com/ijmbarr/images-to-triangles/compare/master...jonocarroll:images-to-triangles:master&#34;&gt;small updates later&lt;/a&gt;, &lt;a href=&#34;https://github.com/jonocarroll/images-to-triangles&#34;&gt;my fork&lt;/a&gt;
now runs the code. It doesn&amp;rsquo;t take terribly long to run - it doesn&amp;rsquo;t display the image,
it saves it, and I&amp;rsquo;m not sure if that&amp;rsquo;s a factor. I (naively?) expected that the Julia
version would be a lot faster, and I&amp;rsquo;m hopeful that there&amp;rsquo;s performance I&amp;rsquo;ve left on the
table.&lt;/p&gt;
&lt;p&gt;If anyone is interested in playing with a small-ish Julia package, feel free to poke at
this - it&amp;rsquo;s definitely not being used for anything critical.&lt;/p&gt;
&lt;p&gt;For now, I&amp;rsquo;m enjoying throwing images at this and getting some nice looking results&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/alarm_cmp.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/butterfly_cmp.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/monalisa_cmp.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in having a play with this package or helping to improve it,
it&amp;rsquo;s on &lt;a href=&#34;https://github.com/jonocarroll/TriangulArt.jl&#34;&gt;GitHub&lt;/a&gt; - I&amp;rsquo;m not planning
to publish it to the registry any time soon, but that&amp;rsquo;s perhaps something to look
forward to in the future. For now, the main issues I see with this package are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The white border around the produced image remains - I have tried setting
&lt;code&gt;margin=0mm&lt;/code&gt; but that doesn&amp;rsquo;t appear to help&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Performance is not as good as it can be, I suspect; the entropy calculation
(calling python) is definitely a bottleneck.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To speed up the processing, only every 10th pixel is used to determine the
average colour of the triangle - this may fail to identify an entire triangle.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CI - I generated this package in VSCode using &lt;code&gt;PkgTemplates&lt;/code&gt; and it is the
first Julia package I&amp;rsquo;ve built. CI failed immediately, so I&amp;rsquo;ve probably done
something wrong.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I am still somewhat of a beginner in Julia, so there are probably many places
in which improvements can be made - feel free to suggest them!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As always, I can be found on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; and
the comment section below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
  &lt;summary&gt;
    &lt;tt&gt;devtools::session_info()&lt;/tt&gt;
  &lt;/summary&gt;
```{r sessionInfo, echo = FALSE}
devtools::session_info()
```
&lt;/details&gt;
&lt;br /&gt;</description>
    </item>
    
    <item>
      <title>Making Links a Little Less Hyper</title>
      <link>https://jcarroll.com.au/2023/12/17/making-links-a-little-less-hyper/</link>
      <pubDate>Sun, 17 Dec 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/12/17/making-links-a-little-less-hyper/</guid>
      <description>&lt;p&gt;Hyperlinks are great - they add value to a block of text by adding additional
links out to more things to read - but they&amp;rsquo;re a distraction if you&amp;rsquo;re trying to
read an in-depth piece of text and comprehend it linearly. Let&amp;rsquo;s hack the web!&lt;/p&gt;
&lt;p&gt;Hyperlinks are great - they add value to a block of text by adding additional
links out to more things to read - but they&amp;rsquo;re a distraction if you&amp;rsquo;re trying to
read an in-depth piece of text and comprehend it linearly. Let&amp;rsquo;s hack the web!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been reading the updated edition of &lt;a href=&#34;https://www.goodreads.com/book/show/9778945-the-shallows&#34;&gt;The Shallows: What the Internet Is
Doing to Our Brains&lt;/a&gt;
and one particular point resonated with me - on discussing the differences
between print books and web content, the author notes that the proliferation of
hyperlinks throughout the latter distract us from reading because we constantly
assess whether or not we will click a link, or worse, we click it and read that
instead.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m very familiar with this distraction from reading long-form articles, and I
typically end up with a backlog of open tabs that I plan to get to later so that
I&amp;rsquo;m not too distracted from what I&amp;rsquo;m currently reading. With that said, I do
reflect on the fact that I don&amp;rsquo;t think this is a &lt;em&gt;new&lt;/em&gt; thing - I eventually
stopped reading the footnotes in several non-fiction books recently because I
felt it was too hard to keep flipping between the text and the itemized notes at
either the end of the chapter or book.&lt;/p&gt;
&lt;p&gt;Footnotes, with a number next to a word or at the end of a phrase, can be
overlooked a bit easier than inline hyperlinks, where some stretch of text
serves as the anchor to some other page, e.g. this link to
&lt;a href=&#34;https://www.wikipedia.org/&#34;&gt;Wikipedia&lt;/a&gt; without having to show the actual URL
of the page.&lt;/p&gt;
&lt;p&gt;I started thinking - what if we just turn the hyperlinks off, temporarily? We
can do a full reading of some content, then come back with the hyperlinks back
on to see what additional content there is to read, knowing that we&amp;rsquo;ve already
parsed the primary content and are now available to investigate the secondary
components. I think that distinction is significant - if it was primary content,
it would be in the main text, but by using a hyperlink or a footnote, it is
deemed secondary.&lt;/p&gt;
&lt;p&gt;Web content has the benefit that, while it&amp;rsquo;s presented in one particular way on
your screen, the instructions for doing so come along for the ride behind the scenes
in the form of HTML, JavaScript, CSS, and other browser-related things. With the
right knowledge, they&amp;rsquo;re malleable, and we can change them. What if we just find
all the hyperlinks and make them look like regular text?&lt;/p&gt;
&lt;p&gt;I searched for whether or not such a thing already exists, and sure enough one
of the first results I found was a post from someone who came to exactly the
same conclusion after reading the same book! In &lt;a href=&#34;https://onestepcode.com/hide-link-extension/&#34;&gt;their
post&lt;/a&gt; they describe building a
Firefox extension that does what I want - turns off styling by overriding the
CSS of anchor tags so that they inherit their parent styling&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;hover&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;focus&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;active&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;visited&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;text-decoration&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;none&lt;/span&gt; &lt;span class=&#34;cp&#34;&gt;!important&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;inherit&lt;/span&gt; &lt;span class=&#34;cp&#34;&gt;!important&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;background-color&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;inherit&lt;/span&gt; &lt;span class=&#34;cp&#34;&gt;!important&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;border-bottom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;initial&lt;/span&gt; &lt;span class=&#34;cp&#34;&gt;!important&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works for that person on that browser, but I want something a bit more general.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t exactly know why they fell out of favor, but &lt;a href=&#34;https://en.wikipedia.org/wiki/Bookmarklet&#34;&gt;JavaScript bookmarklets&lt;/a&gt; are
great - a bookmark containing JavaScript code you can run on any page. This seemed
like what I wanted, so I started hacking away and eventually came up with this function&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;ql&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getElementById&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;quietlinks&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;ql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;parentNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;removeChild&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;createElement&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;style&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;quietlinks&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;innerText&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;a, a:hover, a:focus, a:active, a:visited { text-decoration: none !important; color: inherit !important; background-color: inherit !important; border-bottom: initial !important;}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;appendChild&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;})();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It checks to see if there is an element with the ID &lt;code&gt;&amp;quot;quietlinks&amp;quot;&lt;/code&gt; and if not, it
creates a new overriding style element with the above CSS and appends that to the
page&amp;rsquo;s head. If it &lt;em&gt;does&lt;/em&gt; find such an element, it removes it from the page. This
function therefore toggles between applying custom CSS and removing it.&lt;/p&gt;
&lt;p&gt;To work in a bookmarklet it needs to all be one line and quotes need to be translated,
and the minifier I used shortens variable names, so it ends up looking like this&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;javascript&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:!&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(){&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ql&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getElementById&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;quietlinks&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;parentNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;removeChild&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;createElement&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;style&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=%&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;quietlinks&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;innerText&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=%&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hover&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;focus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;active&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;visited&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;decoration&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;none&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;important&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;inherit&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;important&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;background&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;inherit&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;important&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;border&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bottom&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;initial&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;important&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;}&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;appendChild&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)}}();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To save this bookmarklet, drag this link into your bookmarks bar (or just click it
to try it on this page)&lt;/p&gt;
&lt;div align=&#34;center&#34;&gt;
&lt;a href=&#34;javascript:!function(){if(ql=document.getElementById(%22quietlinks%22),ql)ql.parentNode.removeChild(ql);else{var e=document.createElement(%22style%22);e.id=%22quietlinks%22,e.innerText=%22a, a:hover, a:focus, a:active, a:visited { text-decoration: none !important; color: inherit !important; background-color: inherit !important; border-bottom: initial !important;}%22,document.head.appendChild(e)}}();&#34;&gt;QuietLinks&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Now you can use it - here are a few links to nowhere that are styled. Click on
the saved bookmarklet, and they should lose their styling. Click on it again and
the styling will return.&lt;/p&gt;
&lt;p&gt;When &lt;a href=&#34;javascript:;&#34;&gt;text&lt;/a&gt; contains &lt;a href=&#34;javascript:;&#34;&gt;a lot of links&lt;/a&gt; it can be
&lt;a href=&#34;javascript:;&#34;&gt;difficult&lt;/a&gt; to read because we &lt;a href=&#34;javascript:;&#34;&gt;continually&lt;/a&gt; need to
stop to &lt;a href=&#34;javascript:;&#34;&gt;decide&lt;/a&gt; whether or not we will &lt;a href=&#34;javascript:;&#34;&gt;follow&lt;/a&gt; the
link. Disabling the &lt;a href=&#34;javascript:;&#34;&gt;hyperlink&lt;/a&gt; &lt;a href=&#34;javascript:;&#34;&gt;decoration&lt;/a&gt; could
be helpful.&lt;/p&gt;
&lt;p&gt;These are all fake links that go literally nowhere, so they don&amp;rsquo;t have the
domain suffix (inserted via JavaScript, as described in &lt;a href=&#34;https://jcarroll.com.au/2023/06/02/hyperlink-annotations-in-javascript-and-css/&#34;&gt;this
post&lt;/a&gt;)
but on a regular site, the result should look something like this&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/quietlinks-small.gif&#34; alt=&#34;Removing hyperlink styling and recovering it again&#34;&gt;&lt;/p&gt;
&lt;p&gt;Note that the hyperlinks remain - they&amp;rsquo;re still clickable - but they no longer have
special styling applied to them (commonly blue with underline) so they just read like
regular text.&lt;/p&gt;
&lt;p&gt;There are some edge cases I discovered already, e.g. the links on Mastodon are all
&lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; elements, not &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;, so they aren&amp;rsquo;t affected. My intention was for reading
long articles, though, so that doesn&amp;rsquo;t bother me too much. This approach is also a bit
greedy in finding anchors, so the &amp;lsquo;share&amp;rsquo; icons below disappear as their styling is
disrupted. I&amp;rsquo;ll keep using this for a while and see if it really helps me comprehend
what I&amp;rsquo;m reading.&lt;/p&gt;
&lt;p&gt;Comments and improvements most welcome. I can be found on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; or use the comments below.&lt;/p&gt;
&lt;p&gt;P.S. I&amp;rsquo;m conscious of the irony in writing a post filled with hyperlinks while at the
same time disparaging them, but with this tool at hand, it&amp;rsquo;s fine!&lt;/p&gt;
&lt;br /&gt;</description>
    </item>
    
    <item>
      <title>Advent of Array Elegance (AoC2023 Day 7)</title>
      <link>https://jcarroll.com.au/2023/12/10/advent-of-array-elegance/</link>
      <pubDate>Sun, 10 Dec 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/12/10/advent-of-array-elegance/</guid>
      <description>&lt;p&gt;I’m solving &lt;a href=&#34;https://adventofcode.com/&#34;&gt;Advent of Code&lt;/a&gt; this year using a
relaxed criteria compared to &lt;a href=&#34;https://jcarroll.com.au/2023/11/28/advent-of-code-2022/&#34;&gt;last
year&lt;/a&gt; in that I’m
allowing myself to use packages where they’re helpful, rather than &lt;em&gt;strictly&lt;/em&gt;
base R. Last year I re-solved half of the exercises using Rust which helped me
learn a lot about Rust. This year I’m enamored with APL, and I wanted to share a
particularly beautiful solution.&lt;/p&gt;
&lt;p&gt;⚠⚠⚠⚠⚠&lt;/p&gt;
&lt;p&gt;Spoilers ahead for Day 7, in case you haven’t yet completed it yourself.&lt;/p&gt;
&lt;p&gt;⚠⚠⚠⚠⚠&lt;/p&gt;
&lt;p&gt;I solved Day 7 of Advent of Code using base R by testing whether or not a given
hand was of each type with an individual function, either returning 0 (if it was
not of that type) or &lt;code&gt;N&lt;/code&gt; + a score, where &lt;code&gt;N&lt;/code&gt; was sufficiently different between
each type that they would sort nicely. For the score, I initially tried
offsetting each card in a poor-man’s base-15 as &lt;code&gt;15^(4:0)*card_score&lt;/code&gt; but later
improved on that by using hex digits (which automatically sort nicer). The large &lt;code&gt;N&lt;/code&gt;
values ensured that ‘type’ would be sorted before the first/second/etc.. card.&lt;/p&gt;
&lt;p&gt;That was sufficient to do an &lt;code&gt;apply(strength, hands)&lt;/code&gt;, calculate the &lt;code&gt;order&lt;/code&gt; of
those, and multiply by the relevant bids. Aside from a bug not caught by the
test case (the difference between &lt;code&gt;bid*order(x)&lt;/code&gt; and
&lt;code&gt;bid[order(x)]*seq_along(x)&lt;/code&gt;) it was an okay solution to the problem, and it
worked.&lt;/p&gt;
&lt;p&gt;After solving each day, I’ve been trying to re-solve using APL; in particular Dyalog
APL. For those who don’t know, APL is an old language (circa 1960s) borne from a
mathematical notation in which a single glyph (symbol) represents some operation
or application of a function. This makes it look very different to more modern
languages, partly because of the glyphs, but also because it requires no boilerplate
whatsoever. As an array language, it deals with vectors and matrices without needing
to “loop over columns” or “for i in values”. It looks scary at first, but it’s really
not - once you’re familiar with the glyphs it’s actually beautiful!&lt;/p&gt;
&lt;p&gt;Let’s say you have a matrix &lt;code&gt;m&lt;/code&gt; which contains the values &lt;code&gt;1&lt;/code&gt; through &lt;code&gt;9&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    m
1 2 3
4 5 6
7 8 9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and you want to sum the columns. Chances are, the language you normally use will
require you to first calculate the size of the matrix, maybe even perform a loop. In
APL, it’s&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    +⌿m
12 15 18&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;⌿&lt;/code&gt; is the glyph for “reduce along first axis”, or perform some operation
(supplied as its left argument) to its right argument. &lt;code&gt;+⌿&lt;/code&gt; is therefore “sum
columns”. No boilerplate, just a direct explanation (the glyphs themselves are
better names than any word you could attach to them) of what needs to be done.&lt;/p&gt;
&lt;p&gt;Sure, you need to learn the glyphs, and potentially even how to enter them; one option
being a prefix key then a corresponding key. How committed am I to learning
those, you ask? Well, here’s my laptop&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/aplkeyboard_800.jpg&#34; alt=&#34;My laptop with APL stickers on the keys&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;My laptop with APL stickers on the keys&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I considered using APL for my Day 7 solution, but it was so many functions
defined, and fiddly if/else logic, I figured it was just ill-suited to APL. Then
I saw a &lt;a href=&#34;https://www.youtube.com/watch?v=C395wCEDvOQ&#34;&gt;video recap of an APL solution for Day
7&lt;/a&gt; and my mind was blown.&lt;/p&gt;
&lt;p&gt;Meanwhile, I saw a post from &lt;a href=&#34;https://fosstodon.org/@loke@functional.cafe&#34;&gt;Elias
Mårtenson&lt;/a&gt;, creator of the Kap
language, promoting some examples of Kap and was even more interested given that
it can do some things that (Dyalog) APL can’t, like produce graphics.&lt;/p&gt;
&lt;p&gt;Can your APL do this?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;    chart:line mtcars 
┌→──────────────────────────────────────────────────────────────┐
↓1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1│
│4 4 4 3 3 3 3 4 4 4 4 3 3 3 3 3 3 4 4 4 3 3 3 3 3 4 5 5 5 5 5 4│
│4 4 1 1 2 1 4 2 2 4 4 3 3 3 4 4 4 1 2 1 1 2 2 4 2 1 2 2 4 6 8 2│
└───────────────────────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/kap_mtcars.png&#34; alt=&#34;chart:line mtcars in Kap&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;chart:line mtcars in Kap&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href=&#34;https://kapdemo.dhsdevelopments.com/&#34;&gt;Kap&lt;/a&gt; is a fairly new APL-based language
(written in Kotlin) that supports most of Dyalog APL, but adds some cool
extensions and alterations like lazy evaluation and parallel execution.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.uiua.org/&#34;&gt;Uiua&lt;/a&gt; is another new language on the scene (written in
Rust) which also supports graphics; the Uiua logo itself is written in Uiua&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Xy ← °⍉⊞⊟. ÷÷2: -÷2,⇡.200
Rgb ← [:°⊟×.Xy ↯△⊢Xy0.5]
u ← ↥&amp;lt;0.2:&amp;gt;0.7.+×2 ×.:°⊟Xy
c ← &amp;lt;:⍜°√/+ Xy
⍉⊂:-¬u c1 +0.1 ↧¤c0.95Rgb&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/uiua.png&#34; alt=&#34;Uiua logo, coded in Uiua&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Uiua logo, coded in Uiua&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The online editor for Uiua uses colours to distinguish different
functions/operators, and the author has the flexibility to do what they want
with that, so it’s awesome to see what they’ve used for “all” (&lt;code&gt;⋔&lt;/code&gt;) and
“&lt;strong&gt;trans&lt;/strong&gt;pose” (&lt;code&gt;⍉&lt;/code&gt;)…&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/uaua_all_trans.png&#34; alt=&#34;Uiua coloured glyphs for ‘all’ and ‘transpose’&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Uiua coloured glyphs for ‘all’ and ‘transpose’&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I figured I’d try to reproduce the APL solution in Kap as a way to learn more
about that language. The APL/Kap solution is so elegant! Additionally, I tried
writing equivalent R code. I’ll interleave all three in this post (a nice excuse
to get &lt;a href=&#34;https://yihui.org/en/2023/10/section-tabsets/&#34;&gt;tabsets&lt;/a&gt; working!).&lt;/p&gt;
&lt;div id=&#34;reading-input&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Reading Input&lt;/h2&gt;
&lt;p&gt;To start with, get the data into the workspace - this reads in a vector with
each element representing a row of input&lt;/p&gt;
&lt;div class=&#34;tabset&#34;&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;APL&lt;/p&gt;
&lt;p&gt;Reading from a file is performed using &lt;code&gt;⎕NGET&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;    ⊃⎕NGET&amp;#39;p07.txt&amp;#39;1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt; 32T3K 765  T55J5 684  KK677 28  KTJJT 220  QQQJA 483&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kap&lt;/p&gt;
&lt;p&gt;Kap uses some namespaces, which makes reading in a bit nicer, and the output is
boxed, with explicit quotes for strings&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p ← io:read &amp;quot;p07.txt&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃&amp;quot;32T3K 765&amp;quot; &amp;quot;T55J5 684&amp;quot; &amp;quot;KK677 28&amp;quot; &amp;quot;KTJJT 220&amp;quot; &amp;quot;QQQJA 483&amp;quot;┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;R&lt;/p&gt;
&lt;p&gt;&lt;code&gt;readLines&lt;/code&gt; reads in each line as an element of a vector&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p &amp;lt;- readLines(&amp;quot;example07.txt&amp;quot;)
p&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;32T3K 765&amp;quot; &amp;quot;T55J5 684&amp;quot; &amp;quot;KK677 28&amp;quot;  &amp;quot;KTJJT 220&amp;quot; &amp;quot;QQQJA 483&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&#34;preprocessing&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Preprocessing&lt;/h2&gt;
&lt;p&gt;The input consists of hands of cards juxtaposed with a bid value, separated by
a space. The approach here is not to treat them individually, but to create a
matrix containing columns of hands and columns of bids.&lt;/p&gt;
&lt;div class=&#34;tabset&#34;&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;APL&lt;/p&gt;
&lt;p&gt;Partition (&lt;code&gt;(≠⊆⊢)&lt;/code&gt;) on spaces (&lt;code&gt;&#39; &#39;&lt;/code&gt;) for each (&lt;code&gt;¨&lt;/code&gt;) row&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;    &amp;#39; &amp;#39;(≠⊆⊢)¨⊃⎕NGET&amp;#39;p07.txt&amp;#39;1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt; 32T3K  765    T55J5  684    KK677  28    KTJJT  220    QQQJA  483&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s not entirely clear from this layout, but this is a vector of length-2 vectors.&lt;/p&gt;
&lt;p&gt;These are “mixed” (stacked; &lt;code&gt;↑&lt;/code&gt;), and the result assigned (&lt;code&gt;←&lt;/code&gt;) to &lt;code&gt;p&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p←↑&amp;#39; &amp;#39;(≠⊆⊢)¨⊃⎕NGET&amp;#39;p07.txt&amp;#39;1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt; 32T3K  765 
 T55J5  684 
 KK677  28  
 KTJJT  220 
 QQQJA  483 &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is now a matrix, where the first column contains the hands, the second
(last) column contains the bids.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kap&lt;/p&gt;
&lt;p&gt;Rather than the partition idiom, Kap has regex support, so splitting the
components involes &lt;code&gt;regex:split&lt;/code&gt; for each (&lt;code&gt;¨&lt;/code&gt;) element of input&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p←⊃{&amp;quot; &amp;quot; regex:split ⍵}¨p&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;┌→────────────┐
↓&amp;quot;32T3K&amp;quot; &amp;quot;765&amp;quot;│
│&amp;quot;T55J5&amp;quot; &amp;quot;684&amp;quot;│
│&amp;quot;KK677&amp;quot;  &amp;quot;28&amp;quot;│
│&amp;quot;KTJJT&amp;quot; &amp;quot;220&amp;quot;│
│&amp;quot;QQQJA&amp;quot; &amp;quot;483&amp;quot;│
└─────────────┘&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;R&lt;/p&gt;
&lt;p&gt;The boilerplate of R’s matrix construction takes a toll after using APL/Kap…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p &amp;lt;- matrix(unlist(strsplit(p, &amp;quot; &amp;quot;)), ncol = 2, byrow = TRUE)
p&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1]    [,2] 
## [1,] &amp;quot;32T3K&amp;quot; &amp;quot;765&amp;quot;
## [2,] &amp;quot;T55J5&amp;quot; &amp;quot;684&amp;quot;
## [3,] &amp;quot;KK677&amp;quot; &amp;quot;28&amp;quot; 
## [4,] &amp;quot;KTJJT&amp;quot; &amp;quot;220&amp;quot;
## [5,] &amp;quot;QQQJA&amp;quot; &amp;quot;483&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&#34;extraction&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Extraction&lt;/h2&gt;
&lt;p&gt;The hands and bids can be extracted into their own variables.&lt;/p&gt;
&lt;div class=&#34;tabset&#34;&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;APL&lt;/p&gt;
&lt;p&gt;This can be achieved several ways, but a clean way is by reducing (&lt;code&gt;/&lt;/code&gt;) with
either the ‘leftmost’ (&lt;code&gt;⊣&lt;/code&gt;) or ‘rightmost’ (&lt;code&gt;⊢&lt;/code&gt;) operator, and evaluating
(executing &lt;code&gt;⍎&lt;/code&gt;) each (&lt;code&gt;¨&lt;/code&gt;) of the bids to convert from strings to numbers&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;hands←⊣/p
bids←⍎¨⊢/p&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kap&lt;/p&gt;
&lt;p&gt;Kap uses exactly the same approach as APL for this&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;hands←⊣/p
bids←⍎¨⊢/p&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;R&lt;/p&gt;
&lt;p&gt;R’s ‘subset by index’ works just fine, but if this was generalised I’d use
something like &lt;code&gt;p[, ncol(p)]&lt;/code&gt; to get to the last column&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;hands &amp;lt;- p[,1]
hands&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;32T3K&amp;quot; &amp;quot;T55J5&amp;quot; &amp;quot;KK677&amp;quot; &amp;quot;KTJJT&amp;quot; &amp;quot;QQQJA&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;bids &amp;lt;- as.integer(p[,2])
bids&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 765 684  28 220 483&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&#34;tabulate&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Tabulate&lt;/h2&gt;
&lt;p&gt;Now comes the interesting part! Rather than deal with the types separately, one
approach is to identify them by their relative counts; a five-of-a-kind has 5 of
one card and nothing elese; a four-of-a-kind has four of one and one of another.&lt;/p&gt;
&lt;div class=&#34;tabset&#34;&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;APL&lt;/p&gt;
&lt;p&gt;APL has a “key” (&lt;code&gt;⌸&lt;/code&gt;) which takes a function as a left argument, which can be to
count the occurrences of each element with “tally” (&lt;code&gt;≢&lt;/code&gt;)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;      {⍺,≢⍵}⌸&amp;#39;TGGATAACTTGAAC&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;T 4
G 3
A 5
C 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, we can get just the tallied count of each card in the hand with&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;    {⊢∘≢⍵}⌸¨hands&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;2 1 1 1  1 3 1  2 1 2  1 2 2  3 1 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then sort (&lt;code&gt;⍵[⍒⍵]&lt;/code&gt;) these, take just the first two values (&lt;code&gt;2↑&lt;/code&gt;), and
decode (&lt;code&gt;⊥&lt;/code&gt;) using base 10 to a single number. A nice feature of APL is that
trying to take the “first N” elements of a single element pads to the full N
with zeroes.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;    f←{10⊥2↑{⍵[⍒⍵]}⊢∘≢⌸⍵}
    f¨hands&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;21 31 22 22 31&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kap&lt;/p&gt;
&lt;p&gt;Kap doesn’t have the equivalent Key, but after some discussion with the creator,
it’s entirely possible to get something that does the same&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;  key⇐(⍪+⌿≡⌻)∘∪ ⍝ using outer product - see the R solution
  key2⇐{u←∪⍵ ⋄ c←⍸˝∧u⍳⍵} ⍝ using inverse &amp;#39;where&amp;#39; and &amp;#39;index of&amp;#39;

  key2¨hands&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;┌→────────────────────────────────────────┐
│┌→──────┐ ┌→────┐ ┌→────┐ ┌→────┐ ┌→────┐│
││2 1 1 1│ │1 3 1│ │2 1 2│ │1 2 2│ │3 1 1││
│└───────┘ └─────┘ └─────┘ └─────┘ └─────┘│
└─────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The rest is the same as APL, except Kap uses a dedicated sort (&lt;code&gt;∨&lt;/code&gt;)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;    handrank⇐{10⊥2↑∨⊢/key ⍵}
    handrank¨hands&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;┏━━━━━━━━━━━━━━┓
┃21 31 22 22 31┃
┗━━━━━━━━━━━━━━┛&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;R&lt;/p&gt;
&lt;p&gt;I wanted to recreate the above approach in R, so this will take the long way ’round.&lt;/p&gt;
&lt;p&gt;First, we need a ‘key’ function&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;key &amp;lt;- function(x) {
  l &amp;lt;- strsplit(x, &amp;quot;&amp;quot;)[[1]]
  setNames(colSums(outer(l, unique(l), &amp;quot;==&amp;quot;)), unique(l))
}

sapply(hands, key)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## $`32T3K`
## 3 2 T K 
## 2 1 1 1 
## 
## $T55J5
## T 5 J 
## 1 3 1 
## 
## $KK677
## K 6 7 
## 2 1 2 
## 
## $KTJJT
## K T J 
## 1 2 2 
## 
## $QQQJA
## Q J A 
## 3 1 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The idea of this is to create an outer product between the set of
unique letters in the string, and the individual letters, performing
an &lt;code&gt;==&lt;/code&gt; check on each combination&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;y &amp;lt;- strsplit(hands[2], &amp;quot;&amp;quot;)[[1]]
outer(y, unique(y), &amp;quot;==&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##       [,1]  [,2]  [,3]
## [1,]  TRUE FALSE FALSE
## [2,] FALSE  TRUE FALSE
## [3,] FALSE  TRUE FALSE
## [4,] FALSE FALSE  TRUE
## [5,] FALSE  TRUE FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is, of course, unnecessary as R has a way to do this&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;table(y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## y
## 5 J T 
## 3 1 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but I wanted to see how to do it from scratch.&lt;/p&gt;
&lt;p&gt;Applying this over the hands, we can sort each of the counts again, but now
taking the first two values fails for the five-of-a-kind which only has a &lt;code&gt;5&lt;/code&gt;,
so in that case I add the missing 0. Decoding as base 10 can be done a couple
of ways, but pasting and converting seems to work fine.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;handrank &amp;lt;- function(x) {
  rank &amp;lt;- sort(sapply(x, key), decreasing = TRUE)
  if (length(rank) == 1) rank &amp;lt;- c(rank, 0)
  as.integer(paste(rank[1:2], collapse = &amp;quot;&amp;quot;))
}

sapply(hands, handrank)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 32T3K T55J5 KK677 KTJJT QQQJA 
##    21    31    22    22    31&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&#34;subsequent-rankings-and-answer&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Subsequent Rankings and Answer&lt;/h2&gt;
&lt;p&gt;Finally, the part where the ‘array’ approach shines! Rather than constructing some
sortable number for each hand, we can just score each card and use an array.&lt;/p&gt;
&lt;div class=&#34;tabset&#34;&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;APL&lt;/p&gt;
&lt;p&gt;Creating a vector of all the cards is aided by the ‘numbers as a string’
helper &lt;code&gt;⎕D&lt;/code&gt;. Drop the first two of these (&lt;code&gt;2↓&lt;/code&gt;) then append the ‘face’ cards&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;    r←&amp;#39;TJQKA&amp;#39;,⍨2↓⎕D
    r&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;23456789TJQKA&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Stacking the hands into a matrix of cards&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;    ↑hands&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;32T3K
T55J5
KK677
KTJJT
QQQJA&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;we can ask for the index of matches to the individual cards with &lt;code&gt;⍳&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;    r⍳↑hands&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt; 2  1  9  2 12
 9  4  4 10  4
12 12  5  6  6
12  9 10 10  9
11 11 11 10 13&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Prepending (&lt;code&gt;,&lt;/code&gt;) each column with the tabulated type of each hand&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;    r{⍵,⍺⍳↑hands}f¨hands&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;21  2  1  9  2 12
31  9  4  4 10  4
22 12 12  5  6  6
22 12  9 10 10  9
31 11 11 11 10 13&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, some real magic… APL support &lt;a href=&#34;https://aplwiki.com/wiki/Total_array_ordering&#34;&gt;“total array
ordering”&lt;/a&gt; which means we can just
sort the entire thing - it will sort by the first column, using the second and
subsequent columns for ties. Given that the first column is the ‘type’ of hand,
and subsequent columns are values of each card in order, that’s precisely
the sorting we need!&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;    r{⍋⍋⍵,⍺⍳↑hands}f¨hands&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;1 4 3 2 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s a nice discussion about why the double grading from
&lt;a href=&#34;https://github.com/mlochbaum/BQN/blob/master/doc/order.md#ordinals&#34;&gt;BQN&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Finally, multiplying by the bids themselves, and sum-reducing gives the final
answer&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;  +/r{bids×⍋⍋⍵,⍺⍳↑hands}f¨hands&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;6440&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kap&lt;/p&gt;
&lt;p&gt;This is mostly the same solution as APL, except I couldn’t find the ‘numbers
as string’ so i just typed it out. Kap also uses ‘disclose’ (&lt;code&gt;⊃&lt;/code&gt;) in place of
mix (&lt;code&gt;↑&lt;/code&gt;)
(&lt;a href=&#34;https://kapdemo.dhsdevelopments.com/kap-comparison.html#_enclose_and_disclose:~:text=If%20%E2%8A%83%20is%20called%20on%20an%20array%2C&#34;&gt;ref&lt;/a&gt;).&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;    ranks←&amp;quot;23456789TJQKA&amp;quot;
    +/ranks{bids×1+⍋⍋⍵,⍺⍳⊃hands}handrank¨hands&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;6440&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;R&lt;/p&gt;
&lt;p&gt;R doesn’t support Total Array Ordering, but it does seem to have a way to do it,
so say the documentation examples for &lt;code&gt;order&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## or along 1st column, ties along 2nd, ... *arbitrary* no.{columns}:
dd[ do.call(order, dd), ]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That only works for a &lt;code&gt;data.frame&lt;/code&gt;, which &lt;em&gt;is&lt;/em&gt; a &lt;code&gt;list&lt;/code&gt; (per &lt;code&gt;do.call&lt;/code&gt;’s requirement). We
can still work with that. First, smoosh together all the hands and convert the
individual cards to a matrix - again, a long line of commands for what is reasonably
straightforward in APL… &lt;code&gt;3 3⍴&#39;abcdefghi&#39;&lt;/code&gt; reshapes those 9 letters into a 3x3 matrix.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m &amp;lt;- matrix(strsplit(paste0(hands, collapse = &amp;quot;&amp;quot;), &amp;quot;&amp;quot;)[[1]], ncol = 5, byrow = TRUE)
m&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3] [,4] [,5]
## [1,] &amp;quot;3&amp;quot;  &amp;quot;2&amp;quot;  &amp;quot;T&amp;quot;  &amp;quot;3&amp;quot;  &amp;quot;K&amp;quot; 
## [2,] &amp;quot;T&amp;quot;  &amp;quot;5&amp;quot;  &amp;quot;5&amp;quot;  &amp;quot;J&amp;quot;  &amp;quot;5&amp;quot; 
## [3,] &amp;quot;K&amp;quot;  &amp;quot;K&amp;quot;  &amp;quot;6&amp;quot;  &amp;quot;7&amp;quot;  &amp;quot;7&amp;quot; 
## [4,] &amp;quot;K&amp;quot;  &amp;quot;T&amp;quot;  &amp;quot;J&amp;quot;  &amp;quot;J&amp;quot;  &amp;quot;T&amp;quot; 
## [5,] &amp;quot;Q&amp;quot;  &amp;quot;Q&amp;quot;  &amp;quot;Q&amp;quot;  &amp;quot;J&amp;quot;  &amp;quot;A&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The individual cards vector benefits from coercing the digits to characters&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ranks &amp;lt;- c(2:9, &amp;quot;T&amp;quot;, &amp;quot;J&amp;quot;, &amp;quot;Q&amp;quot;, &amp;quot;K&amp;quot;, &amp;quot;A&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The index mapping does actually work nicely with &lt;code&gt;match&lt;/code&gt;, except it returns a single
vector, not a matrix, so we need to reshape yet again. Plus, this time, the matches went
down columns not along rows, so we need to use &lt;code&gt;byrow = FALSE&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mm &amp;lt;- matrix(match(m, ranks), ncol = 5, byrow = FALSE)
mm&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3] [,4] [,5]
## [1,]    2    1    9    2   12
## [2,]    9    4    4   10    4
## [3,]   12   12    5    6    6
## [4,]   12    9   10   10    9
## [5,]   11   11   11   10   13&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Prepending with the type rankings does work nicely via &lt;code&gt;cbind&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;g &amp;lt;- cbind(sapply(hands, handrank), mm)
g&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##       [,1] [,2] [,3] [,4] [,5] [,6]
## 32T3K   21    2    1    9    2   12
## T55J5   31    9    4    4   10    4
## KK677   22   12   12    5    6    6
## KTJJT   22   12    9   10   10    9
## QQQJA   31   11   11   11   10   13&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then ordering with the &lt;code&gt;do.call&lt;/code&gt; idiom&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;gdf &amp;lt;- as.data.frame(g)
gdf[do.call(order, gdf), ]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##       V1 V2 V3 V4 V5 V6
## 32T3K 21  2  1  9  2 12
## KTJJT 22 12  9 10 10  9
## KK677 22 12 12  5  6  6
## T55J5 31  9  4  4 10  4
## QQQJA 31 11 11 11 10 13&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Putting this all together into a function&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sortrank &amp;lt;- function(x, y) {
  m &amp;lt;- matrix(strsplit(paste0(y, collapse = &amp;quot;&amp;quot;), &amp;quot;&amp;quot;)[[1]], ncol = 5, byrow = TRUE)
  mm &amp;lt;- matrix(match(m, x), ncol = 5, byrow = FALSE)
  g &amp;lt;- cbind(sapply(y, handrank), mm)
  do.call(order, as.data.frame(g))
}

sortrank(ranks, hands)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 4 3 2 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This &lt;em&gt;isn’t&lt;/em&gt; the double sorting that APL and Kap used, and that little
difference is what held me up for all too long trying to figure out why my
solution passed tests but gave the wrong answer. Annoyingly, this mistake
doesn’t show up in the test case because the ranks only differ by a switched
place. The true input was not so kind.&lt;/p&gt;
&lt;p&gt;This result &lt;em&gt;is&lt;/em&gt; the order in which we need to place the bids, so doing that, then
multiplying by the position (since it’s sorted, this is just a vector from &lt;code&gt;1&lt;/code&gt; to the
number of elements) we get the answer&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sum(bids[sortrank(ranks, hands)]*seq_along(bids))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 6440&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&#34;summary&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;So, how do these solutions all look? I’ll stop with the tabsets for a side-by-side comparison.&lt;/p&gt;
&lt;p&gt;Compacting the APL solution (which does involve some duplication) it’s as simple as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p←↑&amp;#39; &amp;#39;(≠⊆⊢)¨⊃⎕NGET&amp;#39;p07.txt&amp;#39;1
+/(&amp;#39;TJQKA&amp;#39;,⍨2↓⎕D){(⍎¨⊢/p)×⍋⍋⍵,⍺⍳↑⊣/p}{10⊥2↑{⍵[⍒⍵]}⊢∘≢⌸⍵}¨⊣/p&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which, admittedly, requires a fair amount of unpacking to read. In full form, it’s&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p←↑&amp;#39; &amp;#39;(≠⊆⊢)¨⊃⎕NGET&amp;#39;p07.txt&amp;#39;1
hands←⊣/p
bids←⍎¨⊢/p
f←{10⊥2↑{⍵[⍒⍵]}⊢∘≢⌸⍵}
r←&amp;#39;TJQKA&amp;#39;,⍨2↓⎕D
+/r{bids×⍋⍋⍵,⍺⍳↑hands}f¨hands&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is still pretty nice, considering what it’s doing.&lt;/p&gt;
&lt;p&gt;The R solution, somewhat minimally, and leveraging &lt;code&gt;table&lt;/code&gt;, is&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;handrank &amp;lt;- function(x) {
  rank &amp;lt;- sort(sapply(strsplit(x, &amp;quot;&amp;quot;), table), decreasing = TRUE)
  if (length(rank) == 1) rank &amp;lt;- c(rank, 0)
  as.integer(paste(rank[1:2], collapse = &amp;quot;&amp;quot;))
}

sortrank &amp;lt;- function(x, y) {
  m &amp;lt;- matrix(strsplit(paste0(y, collapse = &amp;quot;&amp;quot;), &amp;quot;&amp;quot;)[[1]], ncol = 5, byrow = TRUE)
  mm &amp;lt;- matrix(match(m, x), ncol = 5, byrow = FALSE)
  g &amp;lt;- cbind(sapply(y, handrank), mm)
  do.call(order, as.data.frame(g))
}

solve &amp;lt;- function(x) {
  p &amp;lt;- matrix(unlist(strsplit(x, &amp;quot; &amp;quot;)), ncol = 2, byrow = TRUE)
  hands &amp;lt;- p[,1]
  bids &amp;lt;- as.integer(p[,2])
  ranks &amp;lt;- c(2:9, &amp;quot;T&amp;quot;, &amp;quot;J&amp;quot;, &amp;quot;Q&amp;quot;, &amp;quot;K&amp;quot;, &amp;quot;A&amp;quot;)
  sum(bids[sortrank(ranks, hands)]*seq_along(bids))
}

solve(readLines(&amp;quot;example07.txt&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Certainly more typing, but still a much shorter solution than the one I originally
came up with.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;takeaways&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;Both APL and Kap (and so many other languages) benefit greatly from treating a string
as an array of characters. This always hurts in R, where &lt;code&gt;strsplit(x, &#34;&#34;)&lt;/code&gt; is needed.&lt;/p&gt;
&lt;p&gt;The array approach here highlights how one can think differently about a problem, provided
the tools are at hand.&lt;/p&gt;
&lt;p&gt;Kap has a lot to offer - it’s (vastly) newer, which comes with both advantages
(can do new things) and disadvantages (things need to be implemented, and they
won’t necessarily carry over 1:1).&lt;/p&gt;
&lt;p&gt;Advent of Code once again proves to be a useful exercise.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;one-more-thing&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;One more thing&lt;/h2&gt;
&lt;p&gt;I saw &lt;a href=&#34;https://mastodon.social/@jstepien/111549757943773283&#34;&gt;a solution in Uiua on
Mastodon&lt;/a&gt; and had to give
it a go, too…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Input ← ⊜(⊜□≠@ .)≠@\n.&amp;amp;fras&amp;quot;p07.txt&amp;quot;
Label ← ⇌&amp;quot;AKQJT98765432&amp;quot;
Bids ← ⋕⊢↘1⍉
Cards ← ⊐≡(⊗:Label)⊢⍉
Types ← 0_1_2_4_8_5_10_9_3_6_12_11_13_7_14_15⊚1_4_3_3_2_2_1
TypeStr ← ⊏⊗⊙Types≡(°⋯≡/=◫2⊏⍏.)
/+×+1⍏⍏/+×ⁿ⇌⇡6⧻Label⊂⊃TypeStr⍉⊃Cards Bids Input&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I &lt;em&gt;think&lt;/em&gt; this is taking the same approach, though unpacking this is even
trickier.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Comments and improvements most welcome. I can be found on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; or use the comments below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.2 (2023-10-31)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-12-10
##  pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.18    2023-06-19 [1] CRAN (R 4.3.2)
##  bookdown      0.36    2023-10-16 [1] CRAN (R 4.3.2)
##  bslib         0.5.1   2023-08-11 [3] CRAN (R 4.3.1)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [3] CRAN (R 4.2.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.3.2)
##  digest        0.6.33  2023-07-07 [3] CRAN (R 4.3.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.22    2023-09-29 [3] CRAN (R 4.3.1)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  htmltools     0.5.6.1 2023-10-06 [3] CRAN (R 4.3.1)
##  htmlwidgets   1.6.2   2023-03-17 [1] CRAN (R 4.3.2)
##  httpuv        1.6.12  2023-10-23 [1] CRAN (R 4.3.2)
##  icecream      0.2.1   2023-09-27 [1] CRAN (R 4.3.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.7   2023-06-29 [3] CRAN (R 4.3.1)
##  knitr         1.44    2023-09-11 [3] CRAN (R 4.3.1)
##  later         1.3.1   2023-05-02 [1] CRAN (R 4.3.2)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.3.2)
##  pkgbuild      1.4.2   2023-06-26 [1] CRAN (R 4.3.2)
##  pkgload       1.3.3   2023-09-22 [1] CRAN (R 4.3.2)
##  prettyunits   1.2.0   2023-09-24 [3] CRAN (R 4.3.1)
##  processx      3.8.2   2023-06-30 [3] CRAN (R 4.3.1)
##  profvis       0.3.8   2023-05-02 [1] CRAN (R 4.3.2)
##  promises      1.2.1   2023-08-10 [1] CRAN (R 4.3.2)
##  ps            1.7.5   2023-04-18 [3] CRAN (R 4.3.0)
##  purrr         1.0.2   2023-08-10 [3] CRAN (R 4.3.1)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.11  2023-07-06 [1] CRAN (R 4.3.2)
##  remotes       2.4.2.1 2023-07-18 [1] CRAN (R 4.3.2)
##  rlang         1.1.1   2023-04-28 [3] CRAN (R 4.3.0)
##  rmarkdown     2.25    2023-09-18 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.7   2023-07-15 [3] CRAN (R 4.3.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.3.2)
##  shiny         1.7.5.1 2023-10-14 [1] CRAN (R 4.3.2)
##  stringi       1.7.12  2023-01-11 [3] CRAN (R 4.2.2)
##  stringr       1.5.0   2022-12-02 [3] CRAN (R 4.3.0)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.3.2)
##  usethis       2.2.2   2023-07-06 [1] CRAN (R 4.3.2)
##  vctrs         0.6.4   2023-10-12 [3] CRAN (R 4.3.1)
##  xfun          0.40    2023-08-09 [3] CRAN (R 4.3.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.3.2)
##  yaml          2.3.7   2023-01-23 [3] CRAN (R 4.2.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Advent of Code 2022</title>
      <link>https://jcarroll.com.au/2023/11/28/advent-of-code-2022/</link>
      <pubDate>Tue, 28 Nov 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/11/28/advent-of-code-2022/</guid>
      <description>&lt;p&gt;In the lead up to Christmas each year, &lt;a href=&#34;https://adventofcode.com/&#34;&gt;Advent of Code&lt;/a&gt;
offers a series of 25 puzzles which start out reasonably simple, but get progressively harder, eventually requiring knowledge of algorithms and dynamic programming techniques. Last year
I solved these in (strictly) base R on the day they were released (or as close to as
I could). I then (starting Dec 27) went back and re-solved (13 of) them in Rust.&lt;/p&gt;
&lt;p&gt;This post details what I learned along the way and some fun visualisations I made.&lt;/p&gt;
&lt;p&gt;As I eventually ran out of time before the 2023 AoC event, some of the latter
solutions are just links to my GitHub repo without comment. I’ll try to update those
at some point.&lt;/p&gt;
&lt;br /&gt;
&lt;details open&gt;
&lt;summary&gt;
Quicklinks (click here to hide):
&lt;/summary&gt;
&lt;ul style=&#34;columns: 3; -webkit-columns: 3; -moz-columns: 3;&#34;&gt;
&lt;li&gt;
&lt;a href=&#34;#day1&#34;&gt;Day 1: Calorie Counting&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day2&#34;&gt;Day 2: Rock Paper Scissors&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day3&#34;&gt;Day 3: Rucksack Reorganization&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day4&#34;&gt;Day 4: Camp Cleanup&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day5&#34;&gt;Day 5: Supply Stacks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day6&#34;&gt;Day 6: Tuning Trouble&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day7&#34;&gt;Day 7: No Space Left On Device&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day8&#34;&gt;Day 8: Treetop Tree House&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day9&#34;&gt;Day 9: Rope Bridge&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day10&#34;&gt;Day 10: Cathode-Ray Tube&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day11&#34;&gt;Day 11: Monkey in the Middle&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day12&#34;&gt;Day 12: Hill Climbing Algorithm&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day13&#34;&gt;Day 13: Distress Signal&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day14&#34;&gt;Day 14: Regolith Reservoir&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day15&#34;&gt;Day 15: Beacon Exclusion Zone&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day16&#34;&gt;Day 16: Proboscidea Volcanium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day17&#34;&gt;Day 17: Pyroclastic Flow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day18&#34;&gt;Day 18: Boiling Boulders&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day19&#34;&gt;Day 19: Not Enough Minerals&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day20&#34;&gt;Day 20: Grove Positioning System&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day21&#34;&gt;Day 21: Monkey Math&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day22&#34;&gt;Day 22: Monkey Map&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day23&#34;&gt;Day 23: Unstable Diffusion&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day24&#34;&gt;Day 24: Blizzard Basin&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&#34;#day25&#34;&gt;Day 25: Full of Hot Air&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div id=&#34;day-1-calorie-counting&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day1&#34; href=&#34;#day1&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 1: Calorie Counting&lt;/h1&gt;
&lt;div id=&#34;r&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day01.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I hadn’t participated in AoC before this, so part of this day involved setting up
a clean way to get the puzzle into R and figure out how I was going to run/test
my solutions. The &lt;a href=&#34;https://github.com/tjmahr/aoc&#34;&gt;{aoc}&lt;/a&gt; package makes this quite smooth
by using a session cookie to fetch the puzzle from the website and scaffold the input and
functions for a given day.&lt;/p&gt;
&lt;p&gt;Each puzzle has a small worked example, which requires a small example data input. For the
first two weeks I painstakingly copied this input from the puzzle text to the templated
&lt;code&gt;example_input_xx&lt;/code&gt; function. The actual input for the puzzle is typically much larger
and I believe is randomised from a handful of variants so that not everyone gets the
exact same input, which makes sharing solutions less of a problem. This input is
stored in a &lt;code&gt;.txt&lt;/code&gt; file in the &lt;code&gt;inst/&lt;/code&gt; directory by the {aoc} package, which also
templates a &lt;code&gt;run-dayxx.R&lt;/code&gt; file which reads said input.&lt;/p&gt;
&lt;p&gt;All that’s left for the user is to fill in the &lt;code&gt;fxxa&lt;/code&gt; and &lt;code&gt;fxxb&lt;/code&gt; functions which
solve the part a and part b of each day’s puzzle.&lt;/p&gt;
&lt;p&gt;Solving the puzzle begins with parsing the input data, which may be a newline-delimited
series of numbers, or something more complex. In this case, groups of numbers
delimited by a blank line. This puzzle asks us to find the group with the largest total.
With the data loaded as a long string containing newlines &lt;code&gt;\n&lt;/code&gt; I split at a double-newline,
then spit within each group at the remaining newline, trimmed the string, converted
to an integer, and summed the result, which gives a total value per group. Finally, I
determined the largest value from the groups with the pattern &lt;code&gt;x[which.max(x)]&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f01a &amp;lt;- function(x) {
  xvec &amp;lt;- strsplit(x, &amp;quot;\n\n&amp;quot;)[[1]]
  tots &amp;lt;- unlist(lapply(xvec, \(y) sum(as.integer(trimws(strsplit(y, &amp;quot;\n&amp;quot;)[[1]])))))
  tots[which.max(tots)]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An alternative would have been to sort &lt;code&gt;tots&lt;/code&gt; and take the first value.&lt;/p&gt;
&lt;p&gt;The second part of each puzzle expands the problem - in this case, rather than just the
largest value from a group, it asks for the largest three groups&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f01b &amp;lt;- function(x) {
  xvec &amp;lt;- strsplit(x, &amp;quot;\n\n&amp;quot;)[[1]]
  tots &amp;lt;- unlist(lapply(xvec, \(y) sum(as.integer(trimws(strsplit(y, &amp;quot;\n&amp;quot;)[[1]])))))
  res &amp;lt;- 0
  for (i in 1:3) {
    n &amp;lt;- which.max(tots)
    res &amp;lt;- res + tots[n]
    tots &amp;lt;- tots[-n]
  }
  res
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In hindsight, &lt;code&gt;sum(head(sort(tots, decreasing = TRUE), 3))&lt;/code&gt; looks like it would have been clearer.&lt;/p&gt;
&lt;p&gt;I wasn’t interested in the performance of my solutions, but for the sake of comparison
later, here is how long these take to run over the real input, which contains &lt;code&gt;2251&lt;/code&gt; lines&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;microbenchmark::microbenchmark(f01a(x), f01b(x), times = 100, check = NULL)
Unit: milliseconds
    expr      min       lq     mean   median       uq      max neval cld
 f01a(x) 21.21986 21.50103 22.26573 21.63479 21.82128 31.41858   100   a
 f01b(x) 21.18393 21.52034 22.29896 21.67297 21.87063 32.98093   100   a&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running the final solutions from the templated &lt;code&gt;inst/run-dayxx.R&lt;/code&gt; file involves building the
package (so that the daily functions are available) and running&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(adventofcode22)
x &amp;lt;- readLines(&amp;quot;./inst/input01.txt&amp;quot;)
x &amp;lt;- paste(x, collapse = &amp;quot;\n&amp;quot;)

p1 &amp;lt;- f01a(x)
p2 &amp;lt;- f01b(x)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;rust&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/Rust/src/bin/01.rs&#34;&gt;Rust&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Returning to these puzzles from Rust presents the same issue - how do I get the inputs
and parse them? The equivalent to the {aoc} package in Rust is a template repository
&lt;a href=&#34;https://github.com/fspoettel/advent-of-code-rust&#34;&gt;{advent-of-code-rust}&lt;/a&gt; which adds some
functionality to &lt;code&gt;cargo&lt;/code&gt; to scaffold and solve each day’s puzzle.&lt;/p&gt;
&lt;p&gt;This crate also adds some helper functions for reading in the inputs and some tests for
confirming that the solutions successfully solve with the example data.&lt;/p&gt;
&lt;p&gt;Working with arbitrary data in Rust was a bit of a learning experience for me - until
this point I’d worked with known structures where I knew exactly what size and shape
to expect, and as such I could define what needed to happen. With the puzzle input,
I needed to learn how to work with unknown lengths and anticipate what might not work.&lt;/p&gt;
&lt;p&gt;I learned from my R solutions that a shared ‘helper’ function to read the data is
quite useful, so I started there. As with the R solution, splitting the data into
groups at a double newline produces the ‘elf’ groups. Splitting each of those groups
involved a &lt;code&gt;map&lt;/code&gt; which splits each group’s text into &lt;code&gt;lines()&lt;/code&gt;, converts to integers (&lt;code&gt;u32&lt;/code&gt;)
with &lt;code&gt;parse()&lt;/code&gt;, then &lt;code&gt;sum()&lt;/code&gt;s each group, &lt;code&gt;collect()&lt;/code&gt;ing the result from each group back
into a vector. The &lt;code&gt;unwrap()&lt;/code&gt; in the middle of this is because &lt;code&gt;parse()&lt;/code&gt; can fail -
something may not be representable as an integer - so &lt;code&gt;parse()&lt;/code&gt; returns a &lt;code&gt;Result&lt;/code&gt; type,
which can be either a value, or an error. &lt;code&gt;unwrap()&lt;/code&gt; simply says “this will never fail, but
if it does, crash the entire program”.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fn parse01(input: &amp;amp;str) -&amp;gt; Vec&amp;lt;u32&amp;gt; {
    let elf = input.split(&amp;quot;\n\n&amp;quot;).collect::&amp;lt;Vec&amp;lt;&amp;amp;str&amp;gt;&amp;gt;();
    let calories: Vec&amp;lt;u32&amp;gt; = elf
        .into_iter()
        .map(|x| x.lines().map(|l| l.parse::&amp;lt;u32&amp;gt;().unwrap()).sum())
        .collect();
    calories
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Actually solving the first part is then just converting the vector to an iterator and
taking the maximum value&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;pub fn part_one(input: &amp;amp;str) -&amp;gt; Option&amp;lt;u32&amp;gt; {
    let calories = parse01(input);
    calories.into_iter().max()
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This returns an &lt;code&gt;Option&lt;/code&gt; because a) that’s what the solution template requires, and b)
&lt;code&gt;into_iter()&lt;/code&gt; needs to be able to run out of values.&lt;/p&gt;
&lt;p&gt;For the second part I took advantage of the idea I should have had for the R solution
and sorted the result (in-place), reversed it (in-place), took the first 3 values,
and summed them&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;pub fn part_two(input: &amp;amp;str) -&amp;gt; Option&amp;lt;u32&amp;gt; {
    let mut calories = parse01(input);
    calories.sort();
    calories.reverse();
    let top3 = calories.iter().take(3);
    Some(top3.sum())
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running this solution, the timing seems impressive&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cargo solve 01
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/01`
🎄 Part 1 🎄
72718 (elapsed: 1.01ms)
🎄 Part 2 🎄
213089 (elapsed: 1.07ms)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(about 20x faster than the R solution) except that this is the debug build -
it still has debug symbols and some other things
that make it not as fast as it can be. Using a &lt;code&gt;release&lt;/code&gt; build…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cargo solve 01 --release
    Finished release [optimized + debuginfo] target(s) in 0.02s
     Running `target/release/01`
🎄 Part 1 🎄
72718 (elapsed: 115.74µs)
🎄 Part 2 🎄
213089 (elapsed: 116.51µs)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes - one hundred microseconds. 🤯&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-2-rock-paper-scissors&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day2&#34; href=&#34;#day2&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 2: Rock Paper Scissors&lt;/h1&gt;
&lt;div id=&#34;r-1&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day02.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This puzzle involves combinations of A, B, C and X, Y, Z which lead to different
configurations. I don’t know if it’s quite cheating, but I just hardcoded the
results into some helper functions&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f02_helper &amp;lt;- function(x) {
  switch(x,
         AX = 1 + 3,
         AY = 2 + 6,
         AZ = 3 + 0,
         BX = 1 + 0,
         BY = 2 + 3,
         BZ = 3 + 6,
         CX = 1 + 6,
         CY = 2 + 0,
         CZ = 3 + 3)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and summed the matching values, dropping spaces&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f02a &amp;lt;- function(x) {
  x &amp;lt;- gsub(&amp;quot; &amp;quot;, &amp;quot;&amp;quot;, x)
  sum(sapply(x, f02_helper))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second part is just a variation on this, so another helper and the same idea&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f02b_helper &amp;lt;- function(x) {
  switch(x,
         AX = 3 + 0,
         AY = 1 + 3,
         AZ = 2 + 6,
         BX = 1 + 0,
         BY = 2 + 3,
         BZ = 3 + 6,
         CX = 2 + 0,
         CY = 3 + 3,
         CZ = 1 + 6)
}

f02b &amp;lt;- function(x) {
  x &amp;lt;- gsub(&amp;quot; &amp;quot;, &amp;quot;&amp;quot;, x)
  sum(sapply(x, f02b_helper))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There was probably an algorithmic way to achieve this, but the answer works.&lt;/p&gt;
&lt;p&gt;For comparison sake…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;microbenchmark::microbenchmark(f02a(x), f02b(x), times = 100, check = NULL)
Unit: milliseconds
    expr      min       lq     mean   median       uq      max neval cld
 f02a(x) 4.814174 4.921636 5.225773 4.992835 5.259293 8.873809   100   a
 f02b(x) 4.837843 4.918625 5.142451 4.984148 5.117036 7.762490   100   a&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;rust-1&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/Rust/src/bin/02.rs&#34;&gt;Rust&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I could do similar with Rust, using a &lt;code&gt;match&lt;/code&gt; clause inside a &lt;code&gt;map&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;pub fn part_one(input: &amp;amp;str) -&amp;gt; Option&amp;lt;u32&amp;gt; {
    let guide = parse02(input);
    let res: Vec&amp;lt;u32&amp;gt; = guide
        .into_iter()
        .map(|x| match x.as_str() {
            &amp;quot;AX&amp;quot; =&amp;gt; 1 + 3,
            &amp;quot;AY&amp;quot; =&amp;gt; 2 + 6,
            &amp;quot;AZ&amp;quot; =&amp;gt; 3 + 0,
            &amp;quot;BX&amp;quot; =&amp;gt; 1 + 0,
            &amp;quot;BY&amp;quot; =&amp;gt; 2 + 3,
            &amp;quot;BZ&amp;quot; =&amp;gt; 3 + 6,
            &amp;quot;CX&amp;quot; =&amp;gt; 1 + 6,
            &amp;quot;CY&amp;quot; =&amp;gt; 2 + 0,
            &amp;quot;CZ&amp;quot; =&amp;gt; 3 + 3,
            _ =&amp;gt; 0,
        })
        .collect();
    Some(res.iter().sum())
}

pub fn part_two(input: &amp;amp;str) -&amp;gt; Option&amp;lt;u32&amp;gt; {
    let guide = parse02(input);
    let res: Vec&amp;lt;u32&amp;gt; = guide
        .into_iter()
        .map(|x| match x.as_str() {
            &amp;quot;AX&amp;quot; =&amp;gt; 3 + 0,
            &amp;quot;AY&amp;quot; =&amp;gt; 1 + 3,
            &amp;quot;AZ&amp;quot; =&amp;gt; 2 + 6,
            &amp;quot;BX&amp;quot; =&amp;gt; 1 + 0,
            &amp;quot;BY&amp;quot; =&amp;gt; 2 + 3,
            &amp;quot;BZ&amp;quot; =&amp;gt; 3 + 6,
            &amp;quot;CX&amp;quot; =&amp;gt; 2 + 0,
            &amp;quot;CY&amp;quot; =&amp;gt; 3 + 3,
            &amp;quot;CZ&amp;quot; =&amp;gt; 1 + 6,
            _ =&amp;gt; 0,
        })
        .collect();
    Some(res.iter().sum())
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time, the difference in timing wasn’t so pronounced&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cargo solve 02 --release
    Finished release [optimized + debuginfo] target(s) in 0.02s
     Running `target/release/02`
🎄 Part 1 🎄
15422 (elapsed: 699.20µs)
🎄 Part 2 🎄
15442 (elapsed: 527.74µs)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Still faster, but now we’re dealing with string comparisons.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-3-rucksack-reorganization&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day3&#34; href=&#34;#day3&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 3: Rucksack Reorganization&lt;/h1&gt;
&lt;div id=&#34;r-2&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day03.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This puzzle involves ‘rucksacks’ containing letters so we’re going to be doing more
string comparisons. The problem statement says that we need to find the single
character that is common between the first and second halves of a string. As will be
a common theme, I approached this by first solving it for one input as a helper, then mapping
over all the inputs. My solution involves splitting the first and second halves of the
string with &lt;code&gt;strsplit()&lt;/code&gt;, finding the intersection of these (which should be a single
character), and matching that to either lowercase or uppercase letters, which R nicely
has as inbuilt data structures &lt;code&gt;letters&lt;/code&gt; and &lt;code&gt;LETTERS&lt;/code&gt;, respectively. This makes for, I
believe, a fairly compact solution&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f03a &amp;lt;- function(x) {
  sum(sapply(x, f03_helper))
}

f03_helper &amp;lt;- function(x) {
  half &amp;lt;- nchar(x)/2
  comp1 &amp;lt;- strsplit(substring(x, 1, half), &amp;quot;&amp;quot;)[[1]]
  comp2 &amp;lt;- strsplit(substring(x, half+1), &amp;quot;&amp;quot;)[[1]]
  solo &amp;lt;- intersect(comp1, comp2)
  prio &amp;lt;- match(solo, c(letters, LETTERS))
  prio
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second part expands to using 3 groups instead of the two halves. I needed a
way to split the input (one string per line) into groups of 3. I haven’t used this
in a very long time, but I remembered learning about “&lt;strong&gt;g&lt;/strong&gt;enerate factor &lt;strong&gt;l&lt;/strong&gt;evels” &lt;code&gt;gl()&lt;/code&gt; back
when I first learned R. This produces a sequence of factors which can be passed to &lt;code&gt;split()&lt;/code&gt;,
so splitting 12 lines into blocks of 3 would produce 4 levels:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;gl(12/3, 3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] 1 1 1 2 2 2 3 3 3 4 4 4
## Levels: 1 2 3 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Aside from that, the only other difference was the double intersection - it’s a shame
that &lt;code&gt;intersect&lt;/code&gt; only takes two arguments, so I just need to perform it twice&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f03b &amp;lt;- function(x) {
  grps &amp;lt;- split(x, as.integer(gl(length(x)/3, 3)))
  sum(sapply(grps, f03b_helper))
}

f03b_helper &amp;lt;- function(x) {
  x1 &amp;lt;- strsplit(x[1], &amp;quot;&amp;quot;)[[1]]
  x2 &amp;lt;- strsplit(x[2], &amp;quot;&amp;quot;)[[1]]
  x3 &amp;lt;- strsplit(x[3], &amp;quot;&amp;quot;)[[1]]
  comm &amp;lt;- intersect(intersect(x1, x2), x3)
  prio &amp;lt;- match(comm, c(letters, LETTERS))
  prio
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;rust-2&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/Rust/src/bin/03.rs&#34;&gt;Rust&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Figuring out how to do this in Rust took a bit more effort. I don’t know if it was
the &lt;em&gt;best&lt;/em&gt; way, but I found I could take an intersection of a &lt;code&gt;HashSet&lt;/code&gt; object. Rust
has a nice &lt;code&gt;split_at()&lt;/code&gt; method which helps split the strings, and (as with the &lt;code&gt;lines()&lt;/code&gt; used
earlier) a &lt;code&gt;chars()&lt;/code&gt; method to split into individual characters. No inbuilt &lt;code&gt;letters&lt;/code&gt;,
though, so I used an ASCII lookup trick to calculate the priority.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;use std::collections::HashSet;

fn parse03(input: &amp;amp;str) -&amp;gt; Vec&amp;lt;String&amp;gt; {
    input.lines().map(|x| x.to_string()).collect()
}

fn shared_item(rucksack: String) -&amp;gt; Vec&amp;lt;char&amp;gt; {
    let l = rucksack.len();
    let (str1, str2) = rucksack.split_at(l / 2);

    let comp1: HashSet&amp;lt;char&amp;gt; = HashSet::from_iter(str1.chars());
    let comp2: HashSet&amp;lt;char&amp;gt; = HashSet::from_iter(str2.chars());

    let common = comp1.intersection(&amp;amp;comp2);

    common.copied().collect()
}

fn priority(item: char) -&amp;gt; u32 {
    match item {
        lowercase @ &amp;#39;a&amp;#39;..=&amp;#39;z&amp;#39; =&amp;gt; lowercase as u32 - (&amp;#39;a&amp;#39; as u32) + 1,
        uppercase @ &amp;#39;A&amp;#39;..=&amp;#39;Z&amp;#39; =&amp;gt; uppercase as u32 - (&amp;#39;A&amp;#39; as u32) + 27,
        _ =&amp;gt; 0,
    }
}

pub fn part_one(input: &amp;amp;str) -&amp;gt; Option&amp;lt;u32&amp;gt; {
    let parsed = parse03(&amp;amp;input);
    let repeated: Vec&amp;lt;_&amp;gt; = parsed.iter().map(|x| shared_item(x.to_owned())).collect();
    let mut s = 0;
    for c in repeated {
        s += priority(c[0])
    }
    Some(s)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Definitely not as clean as the R solution, here. For the second part, I found
some help in &lt;a href=&#34;https://www.reddit.com/r/rust/comments/zbikje/comment/iys0sgr/&#34;&gt;a Reddit thread&lt;/a&gt;
about a three-way intersection. Here, the &lt;code&gt;chunks(n)&lt;/code&gt; method nicely produces the three
groups&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fn badge(rucksacks: Vec&amp;lt;String&amp;gt;) -&amp;gt; Vec&amp;lt;char&amp;gt; {
    let mut badges = vec![];

    for group in rucksacks.chunks(3) {
        let h1: HashSet&amp;lt;char&amp;gt; = HashSet::from_iter(group[0].chars());
        let h2: HashSet&amp;lt;char&amp;gt; = HashSet::from_iter(group[1].chars());
        let h3: HashSet&amp;lt;char&amp;gt; = HashSet::from_iter(group[2].chars());

        let common: Vec&amp;lt;_&amp;gt; = h1
            .iter()
            .filter(|e| h2.contains(e) &amp;amp;&amp;amp; h3.contains(e))
            .collect();
        badges.push(*common[0]);
    }

    badges
}

pub fn part_two(input: &amp;amp;str) -&amp;gt; Option&amp;lt;u32&amp;gt; {
    let parsed = parse03(&amp;amp;input);
    let badge: Vec&amp;lt;_&amp;gt; = badge(parsed);
    let mut s = 0;
    for c in badge {
        s += priority(c)
    }
    Some(s)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-4-camp-cleanup&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day4&#34; href=&#34;#day4&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 4: Camp Cleanup&lt;/h1&gt;
&lt;p&gt;Now the parsing gets harder. This puzzle involves finding where ranges overlap, so&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;5-7: ....567..  
7-9: ......789  &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;overlap at the 7, while&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2-6: .23456...  
4-8: ...45678.  &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;overlaps at 4, 5, and 6.&lt;/p&gt;
&lt;div id=&#34;r-3&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day04.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Again, taking the “do it once, then map” approach, I converted the format &lt;code&gt;a-b&lt;/code&gt; into
&lt;code&gt;a:b&lt;/code&gt; and then &lt;code&gt;eval(parse(text))&lt;/code&gt;’d the result. This worked surprisingly well. The
puzzle then asks how many times one of the pair is entirely contained within the other,
so &lt;code&gt;all()&lt;/code&gt; and &lt;code&gt;%in%&lt;/code&gt; are great help here.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f04a &amp;lt;- function(x) {
  sum(sapply(x, f04_helper))
}

f04_helper &amp;lt;- function(x) {
  both &amp;lt;- sapply(sub(&amp;quot;-&amp;quot;, &amp;quot;:&amp;quot;, strsplit(x, &amp;quot;,&amp;quot;)[[1]]), \(y) eval(parse(text = y)), simplify = FALSE, USE.NAMES = FALSE)
  all(both[[1]] %in% both[[2]]) || all(both[[2]] %in% both[[1]])
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second part asks for how many overlap at all, so it’s just a change from &lt;code&gt;all()&lt;/code&gt; to &lt;code&gt;any()&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f04b &amp;lt;- function(x) {
  sum(sapply(x, f04b_helper))
}

f04b_helper &amp;lt;- function(x) {
  both &amp;lt;- sapply(sub(&amp;quot;-&amp;quot;, &amp;quot;:&amp;quot;, strsplit(x, &amp;quot;,&amp;quot;)[[1]]), \(y) eval(parse(text = y)), simplify = FALSE, USE.NAMES = FALSE)
  any(both[[1]] %in% both[[2]]) || any(both[[2]] %in% both[[1]])
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;rust-3&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/Rust/src/bin/04.rs&#34;&gt;Rust&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I created a structure to contain the ranges, parsed out the strings into
actual ranges, and parsed the input&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;#[derive(Debug)]
struct Assignments {
    sections: String,
}

impl Assignments {
    fn ids(&amp;amp;self) -&amp;gt; std::ops::Range&amp;lt;u32&amp;gt; {
        let rangelimits = &amp;amp;self.sections.split_once(&amp;#39;-&amp;#39;).unwrap();
        let start = rangelimits.0.parse::&amp;lt;u32&amp;gt;().unwrap();
        let end = rangelimits.1.parse::&amp;lt;u32&amp;gt;().unwrap();
        start..end
    }
}

fn create_assignments(line: &amp;amp;str) -&amp;gt; Vec&amp;lt;Assignments&amp;gt; {
    let pair = line.split_once(&amp;#39;,&amp;#39;).unwrap();
    let p1 = Assignments {
        sections: pair.0.to_string(),
    };
    let p2 = Assignments {
        sections: pair.1.to_string(),
    };
    vec![p1, p2]
}

fn parse04(input: &amp;amp;str) -&amp;gt; Vec&amp;lt;Vec&amp;lt;Assignments&amp;gt;&amp;gt; {
    let l = input.lines();
    l.into_iter().map(|x| create_assignments(x)).collect()
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Having to do this in Rust made me a happy that R has an &lt;code&gt;intersect()&lt;/code&gt; function, because now I
needed one and had to code it by hand (I think…)&lt;/p&gt;
&lt;p&gt;To determine if one range is fully contained within another, I compared the start
and end values. Iterating over the pairs I just incremented a counter for those
which were fully overlapping&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fn fully_contains(pairs: Vec&amp;lt;Assignments&amp;gt;) -&amp;gt; bool {
    let p1 = pairs[0].ids();
    let p2 = pairs[1].ids();
    if p1.len() &amp;gt;= p2.len() {
        return p1.start &amp;lt;= p2.start &amp;amp;&amp;amp; p1.end &amp;gt;= p2.end;
    } else {
        return p2.start &amp;lt;= p1.start &amp;amp;&amp;amp; p2.end &amp;gt;= p1.end;
    }
}

pub fn part_one(input: &amp;amp;str) -&amp;gt; Option&amp;lt;u32&amp;gt; {
    let all_assignments = parse04(input);
    let mut overlapping = 0;
    for ass in all_assignments {
        if fully_contains(ass) {
            overlapping += 1;
        }
    }
    Some(overlapping)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the second part, I needed another algorithm, so &lt;a href=&#34;https://stackoverflow.com/a/325964/4168169&#34;&gt;StackOverflow&lt;/a&gt; to the rescue&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fn overlap_at_all(pairs: Vec&amp;lt;Assignments&amp;gt;) -&amp;gt; bool {
    let p1 = pairs[0].ids();
    let p2 = pairs[1].ids();
    // https://stackoverflow.com/a/325964/4168169
    // (StartA &amp;lt;= EndB) and (EndA &amp;gt;= StartB)
    p1.start &amp;lt;= p2.end &amp;amp;&amp;amp; p1.end &amp;gt;= p2.start
}

pub fn part_two(input: &amp;amp;str) -&amp;gt; Option&amp;lt;u32&amp;gt; {
    let all_assignments = parse04(input);
    let mut overlapping = 0;
    for ass in all_assignments {
        if overlap_at_all(ass) {
            overlapping += 1;
        }
    }
    Some(overlapping)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-5-supply-stacks&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day5&#34; href=&#34;#day5&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 5: Supply Stacks&lt;/h1&gt;
&lt;div id=&#34;r-4&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day05.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This one made me a little more afraid as it involved parsing ASCII-art-like input&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    [D]
[N] [C]
[Z] [M] [P]
 1   2   3

move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Starting with the “stacks”, I realised that a “crate” involved 4 characters and
possibly a space (e.g. &lt;code&gt;[A]&lt;/code&gt;) so I could substring into those. I reversed them
so that the top “crate” was first&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;extract_stack &amp;lt;- function(x) {
  # split into stacks
  n &amp;lt;- seq(1, nc &amp;lt;- nchar(x), by = 4)
  stack &amp;lt;- substring(x, n, c(n[-1]-1, nc))
  stack &amp;lt;- trimws(sub(&amp;quot;]&amp;quot;, &amp;quot;&amp;quot;, sub(&amp;quot;[&amp;quot;, &amp;quot;&amp;quot;, stack, fixed = TRUE), fixed = TRUE))
  stack
}

get_stacks &amp;lt;- function(x) {
  x &amp;lt;- x[1:(grep(&amp;quot;^$&amp;quot;, x)-1)]
  y &amp;lt;- t(sapply(x, extract_stack, USE.NAMES = FALSE))
  stackno &amp;lt;- y[nrow(y), ]
  y &amp;lt;- y[-nrow(y), ]
  z &amp;lt;- as.list(as.data.frame(y))
  z &amp;lt;- lapply(z, rev)
  z &amp;lt;- lapply(z, \(w) w[w != &amp;quot;&amp;quot;])
  z
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Parsing the instructions was a great opportunity for something like &lt;a href=&#34;https://github.com/moodymudskipper/unglue&#34;&gt;&lt;code&gt;{unglue}&lt;/code&gt;&lt;/a&gt;, if only I wasn’t limiting
myself to strictly base R. Nonetheless, the instructions formed a straightforward
pattern, so it wasn’t too hard to work with&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;get_instruction &amp;lt;- function(x) {
  x &amp;lt;- sub(&amp;quot;move &amp;quot;, &amp;quot;&amp;quot;, x)
  n &amp;lt;- as.integer(sub(&amp;quot;([0-9]+).*&amp;quot;, &amp;quot;\\1&amp;quot;, x))
  x &amp;lt;- sub(&amp;quot;^.*?from &amp;quot;, &amp;quot;&amp;quot;, x)
  from = as.integer(sub(&amp;quot;([0-9]+).*&amp;quot;, &amp;quot;\\1&amp;quot;, x))
  to &amp;lt;- as.integer(sub(&amp;quot;^.*?to &amp;quot;, &amp;quot;&amp;quot;, x))
  data.frame(n, from, to)
}

get_instructions &amp;lt;- function(x) {
  x &amp;lt;- x[(grep(&amp;quot;^$&amp;quot;, x)+1):length(x)]
  y &amp;lt;- lapply(x, get_instruction)
  do.call(rbind, y)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Performing the crane operations only involved selecting some number (1 or several)
of elements from the &lt;code&gt;head&lt;/code&gt; of some list and appending it to another&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;crane &amp;lt;- function(stack, inst, model) {
  for (r in seq_len(nrow(inst))) {
    stack &amp;lt;- .crane(stack, inst[r, ], model)
  }
  stack
}

.crane &amp;lt;- function(stack, inst, model) {
  sfrom &amp;lt;- paste0(&amp;quot;V&amp;quot;, inst$from)
  sto &amp;lt;- paste0(&amp;quot;V&amp;quot;, inst$to)
  pick &amp;lt;- tail(stack[[sfrom]], inst$n)
  if (model == 9000) {
    pick &amp;lt;- rev(pick)
  }
  stack[[sfrom]] &amp;lt;- head(stack[[sfrom]], -inst$n)
  stack[[sto]] &amp;lt;- c(stack[[sto]], pick)
  stack
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The flexibility and symmetry of &lt;code&gt;head(n)&lt;/code&gt;, &lt;code&gt;head(-n)&lt;/code&gt;, &lt;code&gt;tail(n)&lt;/code&gt;, and &lt;code&gt;tail(-n)&lt;/code&gt; made
this particularly nice. This was one instance where I re-used my solution to the first
part with an argument for the second part.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;rust-4&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/Rust/src/bin/05.rs&#34;&gt;Rust&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If I thought the input parsing was hard in R, I wasn’t looking forward to doing it
in Rust. I implemented the stacks in much the same way - taking 4 &lt;code&gt;chars&lt;/code&gt; at a time&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;#[derive(Debug)]
struct Stacks {
    stacks: String,
}

impl Stacks {
    fn crates(&amp;amp;self) -&amp;gt; Vec&amp;lt;Vec&amp;lt;char&amp;gt;&amp;gt; {
        let stacklines = &amp;amp;self
            .stacks
            .lines()
            .into_iter()
            .map(|x| x.chars().collect::&amp;lt;Vec&amp;lt;char&amp;gt;&amp;gt;())
            .collect::&amp;lt;Vec&amp;lt;Vec&amp;lt;char&amp;gt;&amp;gt;&amp;gt;();
        let mut stackentries = vec![];
        for l in stacklines.iter() {
            stackentries.push(l.iter().skip(1).step_by(4).collect::&amp;lt;Vec&amp;lt;&amp;amp;char&amp;gt;&amp;gt;());
        }
        // reshape to stacks
        let mut stack = vec![vec![&amp;#39; &amp;#39;; 50]; stackentries[1].len()];
        for s in 0..stackentries.len() - 1 {
            for el in 0..stackentries[s].len() {
                stack[el][s] = stackentries[s][el].to_owned()
            }
        }
        for s in 0..stack.len() {
            stack[s].reverse();
            stack[s].retain(|x| *x != &amp;#39; &amp;#39;);
        }

        stack
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The instructions invited a regex solution, but I found it to be (relatively) slow.
I tried the ‘unglue’ approach&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;let re = Regex::new(r&amp;quot;move (\d*) from (\d*) to (\d*)&amp;quot;).unwrap();
let caps = re.captures(&amp;amp;self.input).unwrap();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and this ended up taking 89ms. The full R solution took 257ms which is certainly more,
but I expected a better improvement moving to Rust. I refactored to avoid using the regex,
instead just filtering to chars that parsed as numbers&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;#[derive(Debug)]
struct Instructions {
    input: String,
}

impl Instructions {
    fn parse(&amp;amp;self) -&amp;gt; (usize, usize, usize) {
        let instr = String::from(&amp;amp;self.input);
        let caps = instr
            .split_whitespace()
            .filter(|c| c.parse::&amp;lt;usize&amp;gt;().is_ok())
            .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();
        let moveto = caps[0].parse::&amp;lt;usize&amp;gt;().unwrap();
        let from = caps[1].parse::&amp;lt;usize&amp;gt;().unwrap();
        let to = caps[2].parse::&amp;lt;usize&amp;gt;().unwrap();

        (moveto, from, to)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and this version ran in 403µs - much better.&lt;/p&gt;
&lt;p&gt;Putting the two pieces together as a tuple&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fn parse05(input: &amp;amp;str) -&amp;gt; (Stacks, Vec&amp;lt;Instructions&amp;gt;) {
    let parts = input.split_once(&amp;quot;\n\n&amp;quot;).unwrap();
    let stacks = Stacks {
        stacks: String::from(parts.0),
    };
    let instr = parts
        .1
        .lines()
        .map(|x| Instructions {
            input: String::from(x),
        })
        .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();
    (stacks, instr)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Actually running the simulation required a &lt;code&gt;crane&lt;/code&gt; function&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fn crane(crates: Vec&amp;lt;Vec&amp;lt;char&amp;gt;&amp;gt;, instr: (usize, usize, usize)) -&amp;gt; Vec&amp;lt;Vec&amp;lt;char&amp;gt;&amp;gt; {
    let mut tmpcrates = crates.clone();
    for _i in 0..instr.0 {
        let tomove: char = tmpcrates[instr.1 - 1].pop().unwrap();
        tmpcrates[instr.2 - 1].push(tomove);
    }
    tmpcrates
}

pub fn part_one(input: &amp;amp;str) -&amp;gt; Option&amp;lt;String&amp;gt; {
    let (stacks, instr) = parse05(&amp;amp;input);
    let mut crates = stacks.crates();
    for i in 0..instr.len() {
        crates = crane(crates, instr[i].parse());
    }
    let tops = crates.iter().map(|s| s.last().unwrap()).collect::&amp;lt;String&amp;gt;();
    Some(tops)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and, not reusing the solution, part two&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fn crane9001(crates: Vec&amp;lt;Vec&amp;lt;char&amp;gt;&amp;gt;, instr: (usize, usize, usize)) -&amp;gt; Vec&amp;lt;Vec&amp;lt;char&amp;gt;&amp;gt; {
    let mut tmpcrates = crates.clone(); 
    let new_len = tmpcrates[instr.1 - 1].len();
    let mut tomove = vec![];
    for _i in 0..instr.0 {
        tomove.push(tmpcrates[instr.1 - 1].pop().unwrap());
    }
    tomove.reverse();
    tmpcrates[instr.1 - 1].truncate(new_len - instr.0);
    for x in tomove.into_iter() {
        tmpcrates[instr.2 - 1].push(x);
    }
    tmpcrates
}

pub fn part_two(input: &amp;amp;str) -&amp;gt; Option&amp;lt;String&amp;gt; {
    let (stacks, instr) = parse05(&amp;amp;input);
    let mut crates = stacks.crates();

    for i in 0..instr.len() {
        crates = crane9001(crates, instr[i].parse());
    }
    let tops = crates.iter().map(|s| s.last().unwrap()).collect::&amp;lt;String&amp;gt;();
    Some(tops)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not as bad as it could have been. The fact that Rust treats strings as a
vector of Chars (as many other languages do) makes some of this a lot nicer. It’s
something I do wish R did differently now that I’ve used it in other places, but
strings are hard.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-6-tuning-trouble&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day6&#34; href=&#34;#day6&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 6: Tuning Trouble&lt;/h1&gt;
&lt;p&gt;After complaining about strings the previous day, parsing this one sounded potentially
tricky, but I think it worked out nicely. The problem involves finiding the first
group of 4 characters where they are all different.&lt;/p&gt;
&lt;div id=&#34;r-5&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day06.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Returning to the ’do it once, then &lt;code&gt;*apply&lt;/code&gt; approach, I was happy to know that
R’s &lt;code&gt;substring&lt;/code&gt; is vectorised, so the &lt;code&gt;first&lt;/code&gt; and &lt;code&gt;last&lt;/code&gt; arguments can be
vectors, e.g. taking 10 letters at a time of the alphabet&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;l &amp;lt;- paste0(letters, collapse = &amp;quot;&amp;quot;)
l&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;abcdefghijklmnopqrstuvwxyz&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;substring(l, seq(1, 17), seq(10, 26))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] &amp;quot;abcdefghij&amp;quot; &amp;quot;bcdefghijk&amp;quot; &amp;quot;cdefghijkl&amp;quot; &amp;quot;defghijklm&amp;quot; &amp;quot;efghijklmn&amp;quot;
##  [6] &amp;quot;fghijklmno&amp;quot; &amp;quot;ghijklmnop&amp;quot; &amp;quot;hijklmnopq&amp;quot; &amp;quot;ijklmnopqr&amp;quot; &amp;quot;jklmnopqrs&amp;quot;
## [11] &amp;quot;klmnopqrst&amp;quot; &amp;quot;lmnopqrstu&amp;quot; &amp;quot;mnopqrstuv&amp;quot; &amp;quot;nopqrstuvw&amp;quot; &amp;quot;opqrstuvwx&amp;quot;
## [16] &amp;quot;pqrstuvwxy&amp;quot; &amp;quot;qrstuvwxyz&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the exact sort of grouping I need for this puzzle. The rest is figuring
out if the group contains 4 unique characters. The offset is to account for the
number of characters since the start of the original string&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f06_helper &amp;lt;- function(x) {
  grp4 &amp;lt;- substring(x, seq(1, nchar(x)), seq(4, nchar(x)))
  4 + which(sapply(strsplit(grp4, &amp;quot;&amp;quot;), \(y) length(unique(y))) == 4)[1] - 1
}

f06a &amp;lt;- function(x) {
  sapply(x, f06_helper)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second part really could have just been adding an argument to specify the group
length, but I went the long way around&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f06b_helper &amp;lt;- function(x) {
  grp14 &amp;lt;- substring(x, seq(1, nchar(x)), seq(14, nchar(x)))
  14 + which(sapply(strsplit(grp14, &amp;quot;&amp;quot;), \(y) length(unique(y))) == 14)[1] - 1
}

f06b &amp;lt;- function(x) {
  sapply(x, f06b_helper)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;rust-5&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/Rust/src/bin/06.rs&#34;&gt;Rust&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Without R’s vectorised substring, I needed to parse 4 characters at a time - again I was
thankful that Rust treats strings as a series of Chars. To keep track of which Chars
had been seen in the last 4 Chars I used a &lt;code&gt;HashSet&lt;/code&gt;. I was pleased to learn that R does
in fact have &lt;a href=&#34;https://stat.ethz.ch/R-manual/R-devel/library/utils/html/hashtab.html&#34;&gt;such a structure in the form of &lt;code&gt;utils::hashtab()&lt;/code&gt;&lt;/a&gt;
but this is only available in newer versions of R&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;use std::collections::HashSet;

pub fn part_one(input: &amp;amp;str) -&amp;gt; Option&amp;lt;u32&amp;gt; {
    let mut i: u32 = 1;
    let mut recent = HashSet::new();
    let mut lastchars = vec![&amp;#39; &amp;#39;; 3];

    for c in input.chars() {
        for j in 0..3 {
            recent.insert(lastchars[j]);
        }
        recent.insert(c);
        if i &amp;gt; 3 &amp;amp;&amp;amp; recent.len() == 4 {
            break
        };
        for i in 0..2 {
            lastchars[i] = lastchars[i+1];
        }
        lastchars[2] = c;
        recent.clear();
        i += 1;
    }
    Some(i)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second part is again very similar, and again rather than adapting my solution
I wrote a new one for part two&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;pub fn part_two(input: &amp;amp;str) -&amp;gt; Option&amp;lt;u32&amp;gt; {
    let mut i: u32 = 1;
    let mut recent = HashSet::new();
    let mut lastchars = vec![&amp;#39; &amp;#39;; 13];

    for c in input.chars() {
        for j in 0..13 {
            recent.insert(lastchars[j]);
        }
        recent.insert(c);
        if i &amp;gt; 13 &amp;amp;&amp;amp; recent.len() == 14 {
            break
        };
        for i in 0..12 {
            lastchars[i] = lastchars[i+1];
        }
        lastchars[12] = c;
        recent.clear();
        i += 1;
    }
    Some(i)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-7-no-space-left-on-device&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day7&#34; href=&#34;#day7&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 7: No Space Left On Device&lt;/h1&gt;
&lt;p&gt;The input for this puzzle is a bit gnarly&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cd /
$ ls
dir a
14848514 b.txt
8504156 c.dat
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but it turned out a brute-force replacement approach didn’t work too badly.&lt;/p&gt;
&lt;div id=&#34;r-6&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day07.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There’s probably some good algorithm to deal with this, but instead I wrote a lot of
for-loops to see what needed to be done. The tricky part of the recursion was having
somewhere to keep track of a) which directory I was currently in, and b) what I’d already
seen. I’m sure a recursive approach could be of help here, but instead I used an
&lt;code&gt;environment&lt;/code&gt; because I knew it was somewhat memory efficient; a global list would need
to keep allocating and be slow.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f07a &amp;lt;- function(x) {
  dir_env &amp;lt;- new.env()
  current_dir &amp;lt;- &amp;quot;/&amp;quot;
  assign(current_dir, 0, envir = dir_env)
  for (inst in x) {
    if (inst == &amp;quot;$ cd /&amp;quot;) next
    if (inst == &amp;quot;$ cd ..&amp;quot;) {
      current_dir &amp;lt;- head(current_dir, -1)
      next
    }
    if (startsWith(inst, &amp;quot;$ cd&amp;quot;)) {
      dir &amp;lt;- sub(&amp;quot;$ cd &amp;quot;, &amp;quot;&amp;quot;, inst, fixed = TRUE)
      current_dir &amp;lt;- c(current_dir, dir)
        assign(paste0(current_dir, collapse = &amp;quot;/&amp;quot;), 0, envir = dir_env)
      next
    }
    if (inst == &amp;quot;$ ls&amp;quot;) next
    if (startsWith(inst, &amp;quot;dir&amp;quot;)) {
      dir &amp;lt;- sub(&amp;quot;dir &amp;quot;, &amp;quot;&amp;quot;, inst)
      next
    } else if (grepl(&amp;quot;^[0-9]&amp;quot;, inst)) {
      l &amp;lt;- strsplit(inst, &amp;quot; &amp;quot;)[[1]]
      size &amp;lt;- l[1]
      for (d in seq_along(current_dir)) {
          this.d &amp;lt;- paste0(current_dir[1:d], collapse = &amp;quot;/&amp;quot;)
          assign(this.d, dir_env[[this.d]] + as.integer(size), envir = dir_env)
      }
      next
    } else {
      stop(&amp;quot;what?&amp;quot;)
    }
  }
  sizes &amp;lt;- sapply(ls(dir_env), get, env = dir_env)
  res &amp;lt;- sum(sizes[which(sizes &amp;lt;= 100000)])
  list(del = res, env = dir_env)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This isn’t recursive, but it works. The second part is much shorter, since it
can reuse the first part&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f07b &amp;lt;- function(x) {
  alldirs &amp;lt;- f07a(x)$env
  todelete &amp;lt;- alldirs[[&amp;quot;/&amp;quot;]] - 40000000
  sizes &amp;lt;- sapply(ls(alldirs), get, env = alldirs)
  candidates &amp;lt;- sizes[which(sizes &amp;gt;= todelete)]
  smallest &amp;lt;- candidates[which.min(candidates)]
  smallest
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;rust-6&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/Rust/src/bin/08.rs&#34;&gt;Rust&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here I took the same approach, but using a &lt;code&gt;HashMap&lt;/code&gt; as the filesystem&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;use std::{collections::HashMap};

pub fn part_one(input: &amp;amp;str) -&amp;gt; Option&amp;lt;u32&amp;gt; {
    let mut dir_deque = vec![];
    let mut current_dir = String::from(&amp;quot;&amp;quot;);
    let mut filesystem = HashMap::new();
    for l in input.lines() {
        if l == &amp;quot;$ cd ..&amp;quot; {
            dir_deque.pop().unwrap();
            current_dir = dir_deque.join(&amp;quot;&amp;quot;);
            continue;
        } else if l == &amp;quot;$ cd /&amp;quot; {
            current_dir = String::from(&amp;quot;/&amp;quot;);
            filesystem.insert(current_dir.clone(), 0);
            dir_deque = vec![String::from(&amp;quot;/&amp;quot;)];
            continue;
        } else if l.starts_with(&amp;quot;dir&amp;quot;) {
            continue;
        } else if l.starts_with(&amp;quot;$ cd&amp;quot;) {
            let new_dir = l.replace(&amp;quot;$ cd &amp;quot;, &amp;quot;&amp;quot;);
            dir_deque.push(new_dir.clone() + &amp;amp;&amp;quot;/&amp;quot;);
            current_dir = current_dir + &amp;amp;new_dir.clone() + &amp;amp;&amp;quot;/&amp;quot;;
            filesystem.insert(current_dir.clone(), 0);
            continue;
        } else if char::is_digit(l.chars().nth(1).unwrap(), 10) {
            let parts = l.split_whitespace().collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();
            let dir_size = parts[0].parse::&amp;lt;u32&amp;gt;().unwrap();
            for d in 0..dir_deque.len() {
                let this_d = dir_deque[0..=d].join(&amp;quot;&amp;quot;);
                let known_size = filesystem.get(&amp;amp;this_d).unwrap();
                filesystem.insert(this_d, known_size + dir_size);
            }
            continue;
        }
    }

    let totalsize = filesystem.iter()
            .filter(|&amp;amp;(_k, v)| *v &amp;lt;= 1e5 as u32)
            .map(|(_k, v)| *v)
            .collect::&amp;lt;Vec&amp;lt;u32&amp;gt;&amp;gt;()
            .iter()
            .sum();

    Some(totalsize)
        
}

pub fn part_two(input: &amp;amp;str) -&amp;gt; Option&amp;lt;u32&amp;gt; {
    let mut dir_deque = vec![];
    let mut current_dir = String::from(&amp;quot;&amp;quot;);
    let mut filesystem = HashMap::new();
    for l in input.lines() {
        if l == &amp;quot;$ cd ..&amp;quot; {
            dir_deque.pop().unwrap();
            current_dir = dir_deque.join(&amp;quot;&amp;quot;);
            continue;
        } else if l == &amp;quot;$ cd /&amp;quot; {
            current_dir = String::from(&amp;quot;/&amp;quot;);
            filesystem.insert(current_dir.clone(), 0);
            dir_deque = vec![String::from(&amp;quot;/&amp;quot;)];
            continue;
        } else if l.starts_with(&amp;quot;dir&amp;quot;) {
            continue;
        } else if l.starts_with(&amp;quot;$ cd&amp;quot;) {
            let new_dir = l.replace(&amp;quot;$ cd &amp;quot;, &amp;quot;&amp;quot;);
            dir_deque.push(new_dir.clone() + &amp;amp;&amp;quot;/&amp;quot;);
            current_dir = current_dir + &amp;amp;new_dir.clone() + &amp;amp;&amp;quot;/&amp;quot;;
            filesystem.insert(current_dir.clone(), 0);
            continue;
        } else if char::is_digit(l.chars().nth(1).unwrap(), 10) {
            let parts = l.split_whitespace().collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();
            let dir_size = parts[0].parse::&amp;lt;u32&amp;gt;().unwrap();
            for d in 0..dir_deque.len() {
                let this_d = dir_deque[0..=d].join(&amp;quot;&amp;quot;);
                let known_size = filesystem.get(&amp;amp;this_d).unwrap();
                filesystem.insert(this_d, known_size + dir_size);
            }
            continue;
        }
    }

    let to_delete = filesystem.get(&amp;quot;/&amp;quot;).unwrap() - (4e7 as u32);
    let candidates = filesystem.iter()
        .filter(|&amp;amp;(_k, v)| *v &amp;gt;= to_delete)
        .map(|(_k, v)| *v)
        .collect::&amp;lt;Vec&amp;lt;u32&amp;gt;&amp;gt;();
    Some(*candidates.iter().min().unwrap())

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-8-treetop-tree-house&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day8&#34; href=&#34;#day8&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 8: Treetop Tree House&lt;/h1&gt;
&lt;p&gt;(see links)&lt;/p&gt;
&lt;div id=&#34;r-7&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day08.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;div id=&#34;rust-7&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/Rust/src/bin/09.rs&#34;&gt;Rust&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-9-rope-bridge&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day9&#34; href=&#34;#day9&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 9: Rope Bridge&lt;/h1&gt;
&lt;p&gt;This one involves keeping track of the positions of several ‘knots’ in a rope as it moves.&lt;/p&gt;
&lt;div id=&#34;r-8&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day09.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I wrote a &lt;em&gt;lot&lt;/em&gt; of helper functions for this one&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f09a &amp;lt;- function(x) {
  visited &amp;lt;- list()
  head_pos &amp;lt;- c(5, 1)
  tail_pos &amp;lt;- c(5, 1)
  # print_grid(head_pos, tail_pos)
  visited &amp;lt;- c(visited, list(tail_pos))
  for (instr in x) {
    tmp &amp;lt;- move_rope(head_pos, tail_pos, instr)
    head_pos &amp;lt;- tmp[[1]]
    tail_pos &amp;lt;- tmp[[2]]
    visited &amp;lt;- c(visited, tmp[[3]])
  }
  length(unique(visited))
}

print_grid &amp;lt;- function(head_pos, tail_pos, size = 6) {
  grid &amp;lt;- matrix(&amp;quot;.&amp;quot;, nrow = size, ncol = size)
  grid[matrix(tail_pos, ncol = 2)] &amp;lt;- &amp;quot;T&amp;quot;
  grid[matrix(head_pos, ncol = 2)] &amp;lt;- &amp;quot;H&amp;quot;
  print(grid)
}

print_knots &amp;lt;- function(k, size = 10) {
  grid &amp;lt;- matrix(&amp;quot;.&amp;quot;, nrow = size, ncol = size)
  for (i in seq_len(length(k))) {
    grid[matrix(k[[i]], ncol = 2)] &amp;lt;- i
  }
  print(grid)
}

move_head &amp;lt;- function(head_pos, dir) {
  if (dir == &amp;quot;L&amp;quot;) return(c(head_pos[1], head_pos[2] - 1))
  if (dir == &amp;quot;R&amp;quot;) return(c(head_pos[1], head_pos[2] + 1))
  if (dir == &amp;quot;U&amp;quot;) return(c(head_pos[1] - 1, head_pos[2]))
  if (dir == &amp;quot;D&amp;quot;) return(c(head_pos[1] + 1, head_pos[2]))
}

move_rope &amp;lt;- function(head_pos, tail_pos, x) {
  visited &amp;lt;- list()
  dir &amp;lt;- sub(&amp;quot; .*&amp;quot;, &amp;quot;&amp;quot;, x)
  dist &amp;lt;- as.integer(sub(&amp;quot;[LRUD] &amp;quot;, &amp;quot;&amp;quot;, x))
  for (i in seq_len(dist)) {
    head_pos &amp;lt;- move_head(head_pos, dir)
    tail_pos &amp;lt;- move_tail(head_pos, tail_pos)
    visited &amp;lt;- c(visited, list(tail_pos))
  }
  return(list(head_pos, tail_pos, visited))
}

move_knots &amp;lt;- function(knots, x) {
  visited &amp;lt;- list()
  dir &amp;lt;- sub(&amp;quot; .*&amp;quot;, &amp;quot;&amp;quot;, x)
  dist &amp;lt;- as.integer(sub(&amp;quot;[LRUD] &amp;quot;, &amp;quot;&amp;quot;, x))
  for (i in seq_len(dist)) {
    knots[[1]] &amp;lt;- move_head(knots[[1]], dir)
    for (i in 2:10) {
      knots[[i]] &amp;lt;- move_tail(knots[[i-1]], knots[[i]])
    }
    visited &amp;lt;- c(visited, list(knots[[10]]))
  }
  return(list(knots, visited))
}

touching &amp;lt;- function(head_pos, tail_pos) {
  (head_pos[1] == tail_pos[1] &amp;amp;&amp;amp; head_pos[2] == tail_pos[2]) ||
  (abs(head_pos[1] - tail_pos[1]) &amp;lt;= 1 &amp;amp;&amp;amp; abs(head_pos[2] - tail_pos[2]) &amp;lt;= 1)
}

move_tail &amp;lt;- function(head_pos, tail_pos) {
  if (touching(head_pos, tail_pos)) return(tail_pos)
  if (tail_pos[1] == head_pos[1]) return(c(tail_pos[1], tail_pos[2] + sign(head_pos[2] - tail_pos[2])*1))
  if (tail_pos[2] == head_pos[2]) return(c(tail_pos[1] + sign(head_pos[1] - tail_pos[1]*1), tail_pos[2]))
  return(c(tail_pos[1] + sign(head_pos[1] - tail_pos[1])*1, tail_pos[2] + sign(head_pos[2] - tail_pos[2])*1))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was also the first one I found the time to plot - here I plotted the path of the 10th knot,
as well as the positions of the other knots after each step&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/vis-day09.png&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;rust-8&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/Rust/src/bin/09.rs&#34;&gt;Rust&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-10-cathode-ray-tube&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day10&#34; href=&#34;#day10&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 10: Cathode-Ray Tube&lt;/h1&gt;
&lt;p&gt;(see links)&lt;/p&gt;
&lt;div id=&#34;r-9&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day10.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;div id=&#34;rust-9&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/Rust/src/bin/10.rs&#34;&gt;Rust&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-11-monkey-in-the-middle&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day11&#34; href=&#34;#day11&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 11: Monkey in the Middle&lt;/h1&gt;
&lt;p&gt;(see links)&lt;/p&gt;
&lt;div id=&#34;r-10&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day11.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;div id=&#34;rust-10&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/Rust/src/bin/11.rs&#34;&gt;Rust&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-12-hill-climbing-algorithm&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day12&#34; href=&#34;#day12&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 12: Hill Climbing Algorithm&lt;/h1&gt;
&lt;p&gt;This one required that I learn a pathfinding algorithm - something I hadn’t really done before. I ended up
learning (and implementing) Dijkstra’s Algorithm for finding the shortest paths between nodes in a graph.&lt;/p&gt;
&lt;div id=&#34;r-11&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day12.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f12a &amp;lt;- function(x) {
  rows &amp;lt;- strsplit(x, &amp;quot;&amp;quot;)
  grid &amp;lt;- matrix(unlist(rows), ncol = nchar(x[1]), byrow = TRUE)
  ngrid &amp;lt;- grid
  ngrid[which(grid == &amp;quot;S&amp;quot;, arr.ind = TRUE)] &amp;lt;- &amp;quot;a&amp;quot;
  ngrid[which(grid == &amp;quot;E&amp;quot;, arr.ind = TRUE)] &amp;lt;- &amp;quot;z&amp;quot;
  ngrid[] &amp;lt;- match(ngrid[], letters)
  mode(ngrid) &amp;lt;- &amp;quot;integer&amp;quot;
  startat &amp;lt;- which(t(grid) == &amp;quot;S&amp;quot;)
  endat &amp;lt;- which(t(grid) == &amp;quot;E&amp;quot;)
  min_path &amp;lt;- dijkstra(ngrid, endat, dir = -1)
  min_pathp[startat]
}

get_pos &amp;lt;- function(grid, v) {
  i &amp;lt;- floor((v-1)/ncol(grid))+1
  j &amp;lt;- ((v-1) %% ncol(grid))+1
  return(c(i, j))
}

can_reach &amp;lt;- function(ngrid, v, dir = 1) {
  x &amp;lt;- get_pos(ngrid, v)
  i &amp;lt;- x[1]
  j &amp;lt;- x[2]
  # can only move 1 row away
  res &amp;lt;- abs(floor(0:(prod(dim(ngrid))-1) / ncol(ngrid)) + 1 - i) &amp;lt;= 1 &amp;amp;
    # can only move 1 col away
    abs((0:(prod(dim(ngrid))-1)%%ncol(ngrid)) + 1 - j) &amp;lt;= 1 &amp;amp;
    # can&amp;#39;t move diagonally
    abs(floor(0:(prod(dim(ngrid))-1) / ncol(ngrid)) + 1 - i) + abs((0:(prod(dim(ngrid))-1)%%ncol(ngrid)) + 1 - j) == 1
    if (dir == 1) {
    # can only step up 1
      res &amp;lt;- res &amp;amp; c(t(ngrid - ngrid[i, j] &amp;lt;= 1))
    } else {
      res &amp;lt;- res &amp;amp; c(t(ngrid[i, j] - ngrid &amp;lt;= 1))
    }
  as.integer(res)
}

dijkstra &amp;lt;- function(grid, start, dir = -1){
  #&amp;#39; Implementation of dijkstra using on-demand query
  #&amp;#39; derived from https://www.algorithms-and-technologies.com/dijkstra/r
  #&amp;#39; This returns an array containing the length of the shortest path from the start node to each other node.
  #&amp;#39; It is only guaranteed to return correct results if there are no negative edges in the graph. Positive cycles are fine.
  #&amp;#39; This has a runtime of O(|V|^2) (|V| = number of Nodes), for a faster implementation see @see ../fast/Dijkstra.java (using adjacency lists)
  #&amp;#39; @param graph an adjacency-matrix-representation of the graph where (x,y) is the weight of the edge or 0 if there is no edge.
  #&amp;#39; @param start the node to start from.
  #&amp;#39; @param dir are we going up or down? passed to can_reach()
  #&amp;#39; @return an array containing the shortest distances from the given start node to each other node

  # This contains the distances from the start node to all other nodes
  distances = rep(Inf, prod(dim(grid)))
  paths = rep(list(), prod(dim(grid)))

  # This contains whether a node was already visited
  visited = rep(FALSE, prod(dim(grid)))

  # The distance from the start node to itself is of course 0
  distances[start] = 0
  paths[[start]] = start

  # While there are nodes left to visit...
  repeat{

    # ... find the node with the currently shortest distance from the start node...
    shortest_distance = Inf
    shortest_index = -1
    for(i in seq_along(distances)) {
      # ... by going through all nodes that haven&amp;#39;t been visited yet
      if(distances[i] &amp;lt; shortest_distance &amp;amp;&amp;amp; !visited[i]){
        shortest_distance = distances[i]
        shortest_index = i
      }
    }

    if(shortest_index == -1){
      # There was no node not yet visited --&amp;gt; We are done
      return (list(distances, paths))
    }
    # ...then, for all neighboring nodes that haven&amp;#39;t been visited yet....
    g &amp;lt;- can_reach(grid, shortest_index, dir = dir)
    for(i in seq_along(g)) {
      # ...if the path over this edge is shorter...
      if(g[i] != 0 &amp;amp;&amp;amp; distances[i] &amp;gt; distances[shortest_index] + g[i]){
        # ...Save this path as new shortest path.
        distances[i] = distances[shortest_index] + g[i]
        paths[[i]] &amp;lt;- c(paths[[shortest_index]], i)
      }
      # Lastly, note that we are finished with this node.
      visited[shortest_index] = TRUE
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With a decent amount of plotting code, I ended up with an animation showing the solution
for the test data&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/vis-day12_test.gif&#34; /&gt;&lt;/p&gt;
&lt;p&gt;which I was very pleased about. Even better, was the full solution animation&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/vis-day12.gif&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;rust-11&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/Rust/src/bin/12.rs&#34;&gt;Rust&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-13-distress-signal&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day13&#34; href=&#34;#day13&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 13: Distress Signal&lt;/h1&gt;
&lt;p&gt;This one involves comparing nested lists like &lt;code&gt;[[1],[2,3,4]]&lt;/code&gt; vs &lt;code&gt;[[1],4]&lt;/code&gt;. I really want to go back
and try this one in Haskell because those comparisons are (I believe) built-in.&lt;/p&gt;
&lt;div id=&#34;r-12&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day13.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;div id=&#34;rust-12&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/Rust/src/bin/13.rs&#34;&gt;Rust&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-14-regolith-reservoir&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day14&#34; href=&#34;#day14&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 14: Regolith Reservoir&lt;/h1&gt;
&lt;p&gt;I didn’t finish my Rust solution for this one, but I was very happy with my R solution. The goal here
is to fill the area with falling sand, allowing for some obstacles.&lt;/p&gt;
&lt;div id=&#34;r-13&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day14.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f14a &amp;lt;- function(x) {
  allrocks &amp;lt;- lapply(x, rocks)
  cave &amp;lt;- matrix(&amp;quot;.&amp;quot;, nrow = 200, ncol = 1500)
  for (r in allrocks) {
    for (rr in seq_along(r[-1])) {
      f &amp;lt;- fill_rocks(r[rr], r[rr+1])
      cave[f] &amp;lt;- &amp;quot;#&amp;quot;
    }
  }
  done &amp;lt;- FALSE
  while(!done) {
    cave &amp;lt;- fall(cave, c(1, 500+500))
    done &amp;lt;- cave[matrix(c(1,1), ncol = 2)] == &amp;quot;X&amp;quot;
  }
  sum(cave == &amp;quot;o&amp;quot;)
}

fall &amp;lt;- function(cave, sand, crit = &amp;quot;fall&amp;quot;) {
  down &amp;lt;- c(sand[1]+1, sand[2])
  if (crit == &amp;quot;fall&amp;quot; &amp;amp;&amp;amp; down[1] &amp;gt; 200) {
    cave[matrix(c(1,1), ncol = 2)] &amp;lt;- &amp;quot;X&amp;quot;
    return(cave)
  } else if (blocked(cave, c(1, 500+500))) {
    sandmat &amp;lt;&amp;lt;- rbind(sandmat, c(1, 500+500))
    cave[matrix(c(1,500+500), ncol = 2)] &amp;lt;- &amp;quot;o&amp;quot;
    cave[matrix(c(1,1), ncol = 2)] &amp;lt;- &amp;quot;X&amp;quot;
    return(cave)
  }
  if (blocked(cave, down)) {
    downleft &amp;lt;- c(sand[1]+1, sand[2]-1)
    if (blocked(cave, downleft)) {
      downright &amp;lt;- c(sand[1]+1, sand[2]+1)
      if (blocked(cave, downright)) {
        sandmat &amp;lt;&amp;lt;- rbind(sandmat, sand)
        cave[matrix(sand, ncol = 2)] &amp;lt;- &amp;quot;o&amp;quot;
      } else {
        return(fall(cave, downright))
      }
    } else {
      return(fall(cave, downleft))
    }
  } else {
    return(fall(cave, down))
  }
  return(cave)
}

blocked &amp;lt;- function(cave, x) {
  cave[matrix(x, ncol = 2)] %in% c(&amp;quot;#&amp;quot;, &amp;quot;o&amp;quot;)
}

rocks &amp;lt;- function(x) {
  rocks &amp;lt;- strsplit(x, &amp;quot; -&amp;gt; &amp;quot;)[[1]]
  rocks &amp;lt;- strsplit(rocks, &amp;quot;,&amp;quot;)
  for (r in seq_along(rocks)) {
    rocks[[r]] &amp;lt;- as.integer(rocks[[r]])
    rocks[[r]][1] &amp;lt;- rocks[[r]][1] + 500
  }
  rocks
}

fill_rocks &amp;lt;- function(x, y) {
  x &amp;lt;- x[[1]]
  x[2] &amp;lt;- x[2] + 1
  y &amp;lt;- y[[1]]
  y[2] &amp;lt;- y[2] + 1
  # horizontal
  if (x[1] == y[1]) {
    span &amp;lt;- x[2]:y[2]
    return(matrix(c(span, rep(x[1], length(span))), ncol = 2, byrow = FALSE))
  }
  # vertical
  if (x[2] == y[2]) {
    span &amp;lt;- x[1]:y[1]
    return(matrix(c(rep(x[2], length(span)), span), ncol = 2, byrow = FALSE))
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I animated the falling sand, filling up the cave, but with &lt;em&gt;so&lt;/em&gt; many particles it didn’t go very well,
especially when limiting the frames&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/vis-day14.gif&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Instead, a render of the final solution, with the sand coloured by the time at which it came to
rest, looked much cooler&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/vis-day14.png&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-15-beacon-exclusion-zone&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day15&#34; href=&#34;#day15&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 15: Beacon Exclusion Zone&lt;/h1&gt;
&lt;p&gt;(see links)&lt;/p&gt;
&lt;div id=&#34;r-14&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day15.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-16-proboscidea-volcanium&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day16&#34; href=&#34;#day16&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 16: Proboscidea Volcanium&lt;/h1&gt;
&lt;p&gt;(see links)&lt;/p&gt;
&lt;div id=&#34;r-15&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day16.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-17-pyroclastic-flow&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day17&#34; href=&#34;#day17&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 17: Pyroclastic Flow&lt;/h1&gt;
&lt;p&gt;While it was never mentioned by name, this one was essentially a game of Tetris.&lt;/p&gt;
&lt;div id=&#34;r-16&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day17.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At this point, there’s too much code to copy inline. Check out the repo links.&lt;/p&gt;
&lt;p&gt;I couldn’t help but plot this one as an animation…&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/vis-day17.gif&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-18-boiling-boulders&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day18&#34; href=&#34;#day18&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 18: Boiling Boulders&lt;/h1&gt;
&lt;p&gt;I got to learn even more algorithms for this one - this time a flood-fill algorithm.&lt;/p&gt;
&lt;div id=&#34;r-17&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day18.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I took advantage of one of coolbutuseless’ packages &lt;a href=&#34;https://github.com/coolbutuseless/isocubes&#34;&gt;{isocubes}&lt;/a&gt;
to plot the shape of the lava droplet&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/vis-day18.png&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-19-not-enough-minerals&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day19&#34; href=&#34;#day19&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 19: Not Enough Minerals&lt;/h1&gt;
&lt;p&gt;(see links)&lt;/p&gt;
&lt;div id=&#34;r-18&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day19.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-20-grove-positioning-system&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day20&#34; href=&#34;#day20&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 20: Grove Positioning System&lt;/h1&gt;
&lt;p&gt;(see links)&lt;/p&gt;
&lt;div id=&#34;r-19&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day20.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-21-monkey-math&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day21&#34; href=&#34;#day21&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 21: Monkey Math&lt;/h1&gt;
&lt;p&gt;I had no intentions of making it on to the leaderboard for timing, even though the puzzles were
released at an entirely reasonable time for me. I actually got to this one late in the
evening due to some other commitments, but I am quietly confident that my R solution could
have been one of the fastest solves…&lt;/p&gt;
&lt;p&gt;The problem is figuring out what the value of the ‘root’ monkey is, given the following operations&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root: pppw + sjmn
dbpl: 5
cczh: sllz + lgvd
zczc: 2
ptdq: humn - dvpt
dvpt: 3
lfqf: 4
humn: 5
ljgn: 2
sjmn: drzm * dbpl
sllz: 4
pppw: cczh / lfqf
lgvd: ljgn * ptdq
drzm: hmdt - zczc
hmdt: 32&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#34;r-20&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day21.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I realised fairly quickly that I could just make each of the connections a function call,
and evaluate the entire stack! This was very fast to write, and I got to my full solution
faster than most of those at the top of the leaderboard, but much later in the day.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f21a &amp;lt;- function(x) {
  defs &amp;lt;- sapply(x, parseInput)
  for (d in defs) {
    eval(parse(text = d))
  }
  format(root(), scientific = FALSE)
}

parseInput &amp;lt;- function(x) {
  monkey &amp;lt;- sub(&amp;quot;^(.*):.*&amp;quot;, &amp;quot;\\1&amp;quot;, x)
  ret &amp;lt;- sub(&amp;quot;.*: (.*)$&amp;quot;, &amp;quot;\\1&amp;quot;, x)
  if (is.na(suppressWarnings(as.integer(ret)))) {
    ret &amp;lt;- strsplit(ret, &amp;quot; &amp;quot;)[[1]]
    v1 &amp;lt;- ret[1]
    op &amp;lt;- ret[2]
    v2 &amp;lt;- ret[3]
    def &amp;lt;- paste0(monkey, &amp;quot; &amp;lt;- function() { &amp;quot;, v1, &amp;quot;() &amp;quot;, op, &amp;quot; &amp;quot;, v2, &amp;quot;() }&amp;quot;)
  } else {
    def &amp;lt;- paste0(monkey, &amp;quot; &amp;lt;- function() { &amp;quot;, ret, &amp;quot; }&amp;quot;)
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sure, sometimes (most of the time), &lt;code&gt;eval(parse(text = ))&lt;/code&gt; is a terrible idea, but in
this case it worked out great!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-22-monkey-map&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day22&#34; href=&#34;#day22&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 22: Monkey Map&lt;/h1&gt;
&lt;p&gt;(see links)&lt;/p&gt;
&lt;div id=&#34;r-21&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day22.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-23-unstable-diffusion&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day23&#34; href=&#34;#day23&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 23: Unstable Diffusion&lt;/h1&gt;
&lt;p&gt;(see links)&lt;/p&gt;
&lt;div id=&#34;r-22&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day23.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-24-blizzard-basin&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day24&#34; href=&#34;#day24&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 24: Blizzard Basin&lt;/h1&gt;
&lt;p&gt;(see links)&lt;/p&gt;
&lt;div id=&#34;r-23&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day24.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;day-25-full-of-hot-air&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;&lt;a rel=&#34;noopener&#34; target=&#34;_blank&#34; id=&#34;day25&#34; href=&#34;#day25&#34;&gt;&lt;i class=&#34;fa fa-link&#34; aria-hidden=&#34;true&#34;&gt;&lt;/i&gt;&lt;/a&gt; Day 25: Full of Hot Air&lt;/h1&gt;
&lt;p&gt;(see links)&lt;/p&gt;
&lt;div id=&#34;r-24&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day25.R&#34;&gt;R&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;summary&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;I really enjoyed advent of code, and I ended up donating as thanks for providing such
a nice experience. I’ll be having a go at AoC 2023 but won’t be so strict; I may not
solve each puzzle &lt;em&gt;on the day it’s released&lt;/em&gt; and I will be allowing myself to use whatever
libraries and whatever languages I want.&lt;/p&gt;
&lt;p&gt;Will you be participating? I’d love to compare solutions once we’re done! I can be found on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; and I’ll be commenting on the puzzles as I go.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.2 (2023-10-31)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-11-28
##  pandoc   3.1.8 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.18    2023-06-19 [1] CRAN (R 4.3.2)
##  bookdown      0.36    2023-10-16 [1] CRAN (R 4.3.2)
##  bslib         0.5.1   2023-08-11 [3] CRAN (R 4.3.1)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [3] CRAN (R 4.2.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.3.2)
##  digest        0.6.33  2023-07-07 [3] CRAN (R 4.3.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.22    2023-09-29 [3] CRAN (R 4.3.1)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  htmltools     0.5.6.1 2023-10-06 [3] CRAN (R 4.3.1)
##  htmlwidgets   1.6.2   2023-03-17 [1] CRAN (R 4.3.2)
##  httpuv        1.6.12  2023-10-23 [1] CRAN (R 4.3.2)
##  icecream      0.2.1   2023-09-27 [1] CRAN (R 4.3.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.7   2023-06-29 [3] CRAN (R 4.3.1)
##  knitr         1.44    2023-09-11 [3] CRAN (R 4.3.1)
##  later         1.3.1   2023-05-02 [1] CRAN (R 4.3.2)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.3.2)
##  pkgbuild      1.4.2   2023-06-26 [1] CRAN (R 4.3.2)
##  pkgload       1.3.3   2023-09-22 [1] CRAN (R 4.3.2)
##  prettyunits   1.2.0   2023-09-24 [3] CRAN (R 4.3.1)
##  processx      3.8.2   2023-06-30 [3] CRAN (R 4.3.1)
##  profvis       0.3.8   2023-05-02 [1] CRAN (R 4.3.2)
##  promises      1.2.1   2023-08-10 [1] CRAN (R 4.3.2)
##  ps            1.7.5   2023-04-18 [3] CRAN (R 4.3.0)
##  purrr         1.0.2   2023-08-10 [3] CRAN (R 4.3.1)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.11  2023-07-06 [1] CRAN (R 4.3.2)
##  remotes       2.4.2.1 2023-07-18 [1] CRAN (R 4.3.2)
##  rlang         1.1.1   2023-04-28 [3] CRAN (R 4.3.0)
##  rmarkdown     2.25    2023-09-18 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.7   2023-07-15 [3] CRAN (R 4.3.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.3.2)
##  shiny         1.7.5.1 2023-10-14 [1] CRAN (R 4.3.2)
##  stringi       1.7.12  2023-01-11 [3] CRAN (R 4.2.2)
##  stringr       1.5.0   2022-12-02 [3] CRAN (R 4.3.0)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.3.2)
##  usethis       2.2.2   2023-07-06 [1] CRAN (R 4.3.2)
##  vctrs         0.6.4   2023-10-12 [3] CRAN (R 4.3.1)
##  xfun          0.40    2023-08-09 [3] CRAN (R 4.3.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.3.2)
##  yaml          2.3.7   2023-01-23 [3] CRAN (R 4.2.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Print Debugging (Now with Icecream!)</title>
      <link>https://jcarroll.com.au/2023/11/07/print-debugging-now-with-icecream/</link>
      <pubDate>Tue, 07 Nov 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/11/07/print-debugging-now-with-icecream/</guid>
      <description>&lt;p&gt;Print debugging has its place. Sure, it’s not always the &lt;em&gt;best&lt;/em&gt; way to debug something,
but it can often be the fastest. In this post I describe a useful way to do this in Rust
and how we can get similar behaviour in R.&lt;/p&gt;
&lt;p&gt;I love the Rust &lt;a href=&#34;https://dev-doc.rust-lang.org/beta/std/macro.dbg.html&#34;&gt;&lt;code&gt;dbg!&lt;/code&gt;&lt;/a&gt;
macro - it wraps a value or expression and prints the result to help debug
what’s happening in the middle of some function. If we had some complicated
function that combined some values, e.g.&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;fn f(val1: i32, val2: i32) -&amp;gt; i32 {
    // do some things
    let otherval: i32 = 10;
    // final result
    val1 + val2 + otherval
}

fn main() {
    println!(&amp;quot;final result = {}&amp;quot;, f(5, 6))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running this gives just the final result, as expected&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;final result = 21&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We might want to check on what the intermediate combinations of &lt;code&gt;otherval&lt;/code&gt; and &lt;code&gt;val1&lt;/code&gt;
or &lt;code&gt;val2&lt;/code&gt; (terrible names, I know). One option is to just print them&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;fn f(val1: i32, val2: i32) -&amp;gt; i32 {
    // do some things
    let otherval: i32 = 10;
    println!(&amp;quot;{}&amp;quot;, otherval + val1);
    println!(&amp;quot;{}&amp;quot;, otherval + val2);
    // final result
    val1 + val2 + otherval
}

fn main() {
    println!(&amp;quot;final result = {}&amp;quot;, f(5, 6))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running this shows the values we printed, but with no context&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;15
16
final result = 21&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We could add some context manually&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;fn f(val1: i32, val2: i32) -&amp;gt; i32 {
    // do some things
    let otherval: i32 = 10;
    println!(&amp;quot;first temp val = {}&amp;quot;, otherval + val1);
    println!(&amp;quot;second temp val = {}&amp;quot;, otherval + val2);
    // final result
    val1 + val2 + otherval
}

fn main() {
    println!(&amp;quot;final result = {}&amp;quot;, f(5, 6))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;producing&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;first temp val = 15
second temp val = 16
final result = 21&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but across an entire codebase, this is going to get messy, fast.&lt;/p&gt;
&lt;p&gt;A better option is the &lt;code&gt;dbg!&lt;/code&gt; macro, which takes an &lt;em&gt;expression&lt;/em&gt; (a value, or
something that produces a value) and prints both the expression itself and the resulting
value&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;fn f(val1: i32, val2: i32) -&amp;gt; i32 {
    // do some things
    let otherval: i32 = 10;
    dbg!(otherval + val1);
    dbg!(otherval + val2);
    // final result
    val1 + val2 + otherval
}

fn main() {
    println!(&amp;quot;final result = {}&amp;quot;, f(5, 6))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running this produces&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[src/main.rs:15] otherval + val1 = 15
[src/main.rs:16] otherval + val2 = 16
final result = 21&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and we see we get the file/linenumber context, the expression we wrapped, and the value.&lt;/p&gt;
&lt;p&gt;This is extremely useful, and helps me to figure out what’s going on in the middle of
some implementation.&lt;/p&gt;
&lt;p&gt;One of the downsides is that even if I make a release build, these statements remain,
so I need to go through and remove them all once I’m finished debugging.&lt;/p&gt;
&lt;p&gt;A “better” solution is to use a full logging solution like the
&lt;a href=&#34;https://docs.rs/log/latest/log/&#34;&gt;&lt;code&gt;log&lt;/code&gt;&lt;/a&gt; crate which enables using different log
levels, turning off logging outside of some threshold, etc… but that seems
more suited to intentional logging, not debugging something that &lt;em&gt;isn’t&lt;/em&gt;
working.&lt;/p&gt;
&lt;p&gt;Having played with this in Rust, of course I wanted the same thing in R. I built a
minimal viable proof-of-concept which leverages {rlang} to capture the expression&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dbg &amp;lt;- function(x) {
  ex &amp;lt;- rlang::f_text(rlang::enquos(x)[[1]])
  ret &amp;lt;- rlang::eval_bare(x)
  message(glue::glue(&amp;quot;DEBUG: {ex} = {ret}&amp;quot;))
  ret
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works rather well - it postpones evaluation of the expression and prints the result
without affecting any variables&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- 1
b &amp;lt;- 3
x &amp;lt;- dbg(a + b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## DEBUG: a + b = 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;y &amp;lt;- dbg(2*x + 3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## DEBUG: 2 * x + 3 = 11&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;z &amp;lt;- 10 + dbg(y*2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## DEBUG: y * 2 = 22&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;z&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 32&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It lacks one beautiful part of the Rust solution, though - if I include this in some
functions sourced from a file, I won’t be able to tell which file the statement came from. Plus,
it doesn’t deal so well with large structures&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- dbg(head(mtcars))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## DEBUG: head(mtcars) = c(21, 21, 22.8, 21.4, 18.7, 18.1)DEBUG: head(mtcars) = c(6, 6, 4, 6, 8, 6)DEBUG: head(mtcars) = c(160, 160, 108, 258, 360, 225)DEBUG: head(mtcars) = c(110, 110, 93, 110, 175, 105)DEBUG: head(mtcars) = c(3.9, 3.9, 3.85, 3.08, 3.15, 2.76)DEBUG: head(mtcars) = c(2.62, 2.875, 2.32, 3.215, 3.44, 3.46)DEBUG: head(mtcars) = c(16.46, 17.02, 18.61, 19.44, 17.02, 20.22)DEBUG: head(mtcars) = c(0, 0, 1, 1, 0, 1)DEBUG: head(mtcars) = c(1, 1, 1, 0, 0, 0)DEBUG: head(mtcars) = c(4, 4, 4, 3, 3, 3)DEBUG: head(mtcars) = c(4, 4, 1, 1, 2, 1)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At some point I saw &lt;a href=&#34;https://turtletopia.github.io/2022/07/28/ice-cream-for-r-programmers/&#34;&gt;a blog
post&lt;/a&gt;
about a debug logging package &lt;a href=&#34;https://github.com/lewinfox/icecream&#34;&gt;{icecream}&lt;/a&gt;
which had this ability of tracing the &lt;code&gt;srcref&lt;/code&gt; of a file containing the debug
statement, so I wanted to see if I could extract that to suit my needs. Running
the &lt;code&gt;ic()&lt;/code&gt; statement as a print debugger works nicely&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f &amp;lt;- function(val1, val2) {
  otherval &amp;lt;- 10
  icecream::ic(otherval + val1)
  icecream::ic(otherval + val2)
  val1 + val2 + otherval
}
f(5, 6)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ℹ ic| `otherval + val1`: num 15&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ℹ ic| `otherval + val2`: num 16&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 21&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;it indeed wraps the expression and shows the result. After poking around at the
internals, I realised it actually does everything that I wanted, I just needed to change
some of the defaults&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;options(icecream.peeking.function = utils::head,
        icecream.max.lines = 5,
        icecream.prefix = &amp;quot;dbg:&amp;quot;,
        icecream.always.include.context = TRUE)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now it prints like the &lt;code&gt;dbg!&lt;/code&gt; macro&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f &amp;lt;- function(val1, val2) {
  otherval &amp;lt;- 10
  icecream::ic(otherval + val1)
  icecream::ic(otherval + val2)
  val1 + val2 + otherval
}
f(5, 6)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ℹ dbg: `f()` in &amp;lt;env: global&amp;gt; | `otherval + val1`: [1] 15&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ℹ dbg: `f()` in &amp;lt;env: global&amp;gt; | `otherval + val2`: [1] 16&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 21&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To make it even more like the Rust macro, I made a similar binding of &lt;code&gt;.dbg&lt;/code&gt; (so
that it doesn’t appear in my workspace by default) and added the following to my
.Rprofile&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# install.packages(&amp;quot;icecream&amp;quot;)
if (requireNamespace(&amp;quot;icecream&amp;quot;, quietly = TRUE)) {
  .dbg &amp;lt;- icecream::ic
  options(icecream.peeking.function = utils::head,
          icecream.max.lines = 5,
          icecream.prefix = &amp;quot;dbg:&amp;quot;,
          icecream.always.include.context = TRUE)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so now I can add debug statements&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f &amp;lt;- function(val1, val2) {
  otherval &amp;lt;- 10
  .dbg(otherval + val1)
  .dbg(otherval + val2)
  val1 + val2 + otherval
}
f(5, 6)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ℹ dbg: `f()` in &amp;lt;env: global&amp;gt; | `otherval + val1`: [1] 15&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ℹ dbg: `f()` in &amp;lt;env: global&amp;gt; | `otherval + val2`: [1] 16&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 21&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Better yet, I can turn them off if I don’t need them&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;icecream::ic_disable()
f(5, 6)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 21&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works as I had hoped; I can even debug partway through an expression&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;icecream::ic_enable()
3 + .dbg(4 + 6)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ℹ dbg: &amp;lt;env: global&amp;gt; | `4 + 6`: [1] 10&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 13&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and if I source a file, I get the context&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## test_dbg.R:
f &amp;lt;- function() {
  x &amp;lt;- 7
  .dbg(x + 3)
  7
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;source(&amp;quot;test_dbg.R&amp;quot;)
f()&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-info&#34;&gt;&lt;code&gt;ℹ dbg: `f()` in test_dbg.R:3:2 | `x + 3`: [1] 10&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[1] 7&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It even deals with printing larger objects, given the “peeking_function” and “max lines”
options above&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;.dbg(mtcars)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## ℹ dbg: &amp;lt;env: global&amp;gt; | `mtcars`: 
## mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That seems to be feature-equivalent to the Rust &lt;code&gt;dbg!&lt;/code&gt; macro, plus the ability to
turn off the messages, so I’m very happy with this result.&lt;/p&gt;
&lt;p&gt;Do you have a better solution? I can be found on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; or use the comments below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-11-07
##  pandoc   3.1.8 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.17    2023-05-16 [1] CRAN (R 4.1.2)
##  bookdown      0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  bslib         0.5.1   2023-08-11 [3] CRAN (R 4.3.1)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [3] CRAN (R 4.2.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest        0.6.33  2023-07-07 [3] CRAN (R 4.3.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.21    2023-05-05 [3] CRAN (R 4.3.0)
##  fansi         1.0.4   2023-01-22 [3] CRAN (R 4.2.2)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  htmltools     0.5.6   2023-08-10 [3] CRAN (R 4.3.1)
##  htmlwidgets   1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv        1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  icecream      0.2.1   2023-09-27 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.7   2023-06-29 [3] CRAN (R 4.3.1)
##  knitr         1.43    2023-05-25 [3] CRAN (R 4.3.0)
##  later         1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  pillar        1.9.0   2023-03-22 [3] CRAN (R 4.2.3)
##  pkgbuild      1.4.0   2022-11-27 [1] CRAN (R 4.1.2)
##  pkgload       1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.8.2   2023-06-30 [3] CRAN (R 4.3.1)
##  profvis       0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises      1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps            1.7.5   2023-04-18 [3] CRAN (R 4.3.0)
##  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.1.1   2023-04-28 [1] CRAN (R 4.1.2)
##  rmarkdown     2.24    2023-08-14 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.7   2023-07-15 [3] CRAN (R 4.3.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny         1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi       1.7.12  2023-01-11 [3] CRAN (R 4.2.2)
##  stringr       1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis       2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  utf8          1.2.3   2023-01-31 [3] CRAN (R 4.2.2)
##  vctrs         0.6.3   2023-06-14 [1] CRAN (R 4.1.2)
##  xfun          0.40    2023-08-09 [3] CRAN (R 4.3.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml          2.3.7   2023-01-23 [3] CRAN (R 4.2.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Hooray, Array!</title>
      <link>https://jcarroll.com.au/2023/10/09/hooray-array/</link>
      <pubDate>Mon, 09 Oct 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/10/09/hooray-array/</guid>
      <description>&lt;p&gt;If you’re reading this hoping that I’m done with droning on about
array-languages, close the tab… it only gets worse from here. If you thought
APL was unreadable, even after my &lt;a href=&#34;https://jcarroll.com.au/2023/07/07/array-languages-r-vs-apl/&#34;&gt;earlier blog posts&lt;/a&gt;, again -
close button is right there. In this post I try out a brand new &lt;em&gt;stack-based&lt;/em&gt;
array language and continue to advocate for learning such things.&lt;/p&gt;
&lt;p&gt;I subscribe to a lot of RSS feeds these days - it’s certainly making a comeback, and it’s
great to see developers returning to blogging outside of paid platforms. Keeping up with
all of those posts, however, does take quite a bit of time. So when I find one I do
really find engaging, I do my best to dig in.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://buttondown.email/hillelwayne/archive/picat-is-my-favorite-new-toolbox-language/&#34;&gt;This post&lt;/a&gt;
by Hillel Wayne wasn’t specifically interesting (my dance card for learning new languages is already
pretty full, but I can’t help looking at others) but it did present a small, bite-sized
puzzle to solve; what’s a simple way to “generate 5 random 10-character strings”. Now, that’s
pretty much a code-golf question right there. Hillel presents a solution in &lt;a href=&#34;https://raku.org/&#34;&gt;Raku&lt;/a&gt; (a.k.a. Perl 6 - note the “p” and “6” in the Raku logo) as a “quick” solution&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for ^5 {say (&amp;#39;a&amp;#39;..&amp;#39;z&amp;#39;).roll(10).join}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;dmjfpwxspu
vernmlljkw
korntotesp
rkpewsoqjn
blswvruden&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and I can’t argue with that - it’s readable (even though I don’t know much Perl/Raku), I can
reason about what and how it’s doing what it’s doing (making an educated guess about &lt;code&gt;^&lt;/code&gt; which
is indeed a &lt;a href=&#34;https://docs.raku.org/language/operators#prefix_%5E&#34;&gt;range operation&lt;/a&gt; and &lt;code&gt;say&lt;/code&gt; being
an &lt;a href=&#34;https://docs.raku.org/routine/say&#34;&gt;output method&lt;/a&gt;; &lt;code&gt;roll&lt;/code&gt; is a nice choice for &lt;a href=&#34;https://docs.raku.org/routine/roll&#34;&gt;random selection&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;When I see problems like this, I start to think through what tools I could use to solve it. I
still default to R because it’s the language I know best, but my first attempt isn’t nearly
as concise&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sapply(1:5, \(x) paste0(sample(letters, 10, replace = TRUE), collapse = &amp;quot;&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;kcqicytylm&amp;quot; &amp;quot;peybjcbumk&amp;quot; &amp;quot;bbvhibgqjs&amp;quot; &amp;quot;uzbpzrkywp&amp;quot; &amp;quot;zettlmjghm&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I &lt;em&gt;do&lt;/em&gt; like that R has &lt;code&gt;letters&lt;/code&gt; (and &lt;code&gt;LETTERS&lt;/code&gt;) as built-in structures; that makes things a
little easier. I &lt;em&gt;could&lt;/em&gt; write that just as easily as a for-loop, especially since I don’t
actually need an argument to the anonymous function&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;for (i in 1:5) {
  print(
    paste0(
      sample(letters, 10, replace = TRUE), 
      collapse = &amp;quot;&amp;quot;
    )
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;zwwpihqipr&amp;quot;
## [1] &amp;quot;cxunwvojaq&amp;quot;
## [1] &amp;quot;xlkcubjysw&amp;quot;
## [1] &amp;quot;ilpohtgcag&amp;quot;
## [1] &amp;quot;ralzlrszen&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Side-by-side, these aren’t all that different…&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/raku_r_coloured.png&#34; alt=&#34;Raku vs R solutions with common colouring&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Raku vs R solutions with common colouring&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;R defaults to &lt;code&gt;replace = FALSE&lt;/code&gt; which needs adjusting, and doesn’t like concatenating
strings quite so easily as &lt;code&gt;join()&lt;/code&gt;, but otherwise the translation is fairly
straightforward. The Raku version is shorter, for sure.&lt;/p&gt;
&lt;p&gt;I could probably go and try a few other languages, but I’m all too tempted to try APL.
Unfortunately, &lt;a href=&#34;https://tryapl.org/&#34;&gt;tryapl.org&lt;/a&gt; seems to be down, but then I remembered…
New on the scene is &lt;a href=&#34;https://www.uiua.org/&#34;&gt;Uiua&lt;/a&gt; (pronounced “wee-wuh”) following the
footsteps of other APL-descendants such as &lt;a href=&#34;https://mlochbaum.github.io/BQN/&#34;&gt;BQN&lt;/a&gt;. This
was covered by &lt;a href=&#34;https://www.arraycast.com/episodes/episode63-uiua&#34;&gt;The Array Cast panel&lt;/a&gt;
who interviewed the author, as well as Conor from the same group in
&lt;a href=&#34;https://www.youtube.com/watch?v=iTC1EiX5bM0&#34;&gt;several&lt;/a&gt; &lt;a href=&#34;https://www.youtube.com/watch?v=pq1k5USZZ9A&#34;&gt;videos&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The idea of a stack-based language is that you put some data “on the stack” then
you no longer need to refer to arguments; a monadic function just applies to whatever
is on the top of the stack. A dyadic function just applies to to the top two
pieces of data on the stack. Need another copy of your data somewhere in your processing? Just
duplicate it on the stack.&lt;/p&gt;
&lt;p&gt;The way this works in practice is you “read” from right-to-left (same as APL), so if we
put the values &lt;code&gt;2&lt;/code&gt; and &lt;code&gt;3&lt;/code&gt; on the stack then use the dyadic &lt;code&gt;+&lt;/code&gt; function&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;+ 3 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similar to APL, this language uses glyphs for primitive functions, but a really nice
feature is writing out the “name” of the function you want (in the above case, &lt;code&gt;add&lt;/code&gt;) which
the interpreter will convert to the glyph for you, so&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;add 3 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;produces the same code (with glyphs) and output.&lt;/p&gt;
&lt;p&gt;Working with a stack would certainly be something different for me, but I figured it’s
worth a try! The first hurdle came quickly; how do I get the letters of the alphabet?
Reading through the examples, I found that I can specify a string literal with &lt;code&gt;@&lt;/code&gt;, and
Uiua supports some &lt;a href=&#34;https://www.uiua.org/docs/types#:~:text=Character%20Arithmetic&#34;&gt;arithmetic on these&lt;/a&gt; so this works&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;+ @a 1
+ @a 25&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;@b
@z&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, I needed to generate all the letters, and thankfully, adding a &lt;em&gt;range&lt;/em&gt; from 1 to 25
(&lt;code&gt;⇡26&lt;/code&gt;) works&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;+@a⇡26&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;&amp;quot;abcdefghijklmnopqrstuvwxyz&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that you can also use &lt;code&gt;add @a range 26&lt;/code&gt; - the interpreter inserts the glyphs for you.&lt;/p&gt;
&lt;p&gt;Next, I need a way to sample 10 letters from this. There’s a &lt;code&gt;rand&lt;/code&gt; function
(the glyph looks like a dice - nice!) but it only produces a single value
between 0 and 1. Additionally, I need to run this several times to get the 10
values. The front page of the website has a nice example demonstrating exactly
this, so that helps. It uses &lt;code&gt;rand&lt;/code&gt; (&lt;code&gt;⚂&lt;/code&gt;) and &lt;code&gt;repeat&lt;/code&gt; (&lt;code&gt;⍥&lt;/code&gt;) to generate 5
random numbers between 0 and 1, then &lt;code&gt;mult&lt;/code&gt; (&lt;code&gt;×&lt;/code&gt;) to bring the range up to 0 to
10, then finally &lt;code&gt;floor&lt;/code&gt; (&lt;code&gt;⌊&lt;/code&gt;) to return to integers.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;⌊×10[⍥⚂5]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[5 3 7 8 4]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my case, I want to generate 10 values and I need to multiply by 26 to have the
right indices&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;⌊×26[⍥⚂10]+@a⇡26&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;&amp;quot;abcdefghijklmnopqrstuvwxyz&amp;quot;
[10 25 23 20 4 25 15 2 24 24]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The values on the stack are then the letters of the alphabet, and 10 indices to be selected.&lt;/p&gt;
&lt;p&gt;This is where I had to pause and think - how do I repeat this 5 times? There’s no loops (I
don’t think). Then I realised - this is an &lt;em&gt;array&lt;/em&gt; language… I should be leveraging that!&lt;/p&gt;
&lt;p&gt;Instead of asking for 10 indices, I can ask for 50. Then, I just need to &lt;code&gt;reshape&lt;/code&gt; (&lt;code&gt;↯&lt;/code&gt;)
these 50 values into 5 groups of 10&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;↯5_10⌊×26[⍥⚂50]+@a⇡26&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;&amp;quot;abcdefghijklmnopqrstuvwxyz&amp;quot;
╭─                               
╷ 21 19  4 18  2 24  6  1  2  6  
   0 12  1  1 12  2 12  7 12  0  
   5  1 19  6 22 19 23 18 12 25  
  20 13 10 19 17  2 12  1 16  4  
   9 24  6  9 18  6 21 18 23  1  
                                ╯&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, there are two data objects on the stack; the alphabet, and an array of indices to be
selected. A dyadic &lt;code&gt;select&lt;/code&gt; (&lt;code&gt;⊏&lt;/code&gt;) will take these two objects, and select elements of the
first based on indices of the second, and voila!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;⊏↯5_10⌊×26[⍥⚂50]+@a⇡26&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;╭─              
╷ &amp;quot;gewctqbttq&amp;quot;  
  &amp;quot;vsbvzbqiod&amp;quot;  
  &amp;quot;wpmkmnuxwz&amp;quot;  
  &amp;quot;rymyxzqibo&amp;quot;  
  &amp;quot;zxtnpadwvl&amp;quot;  
               ╯&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s a walkthrough of the glyphs in my final solution - &lt;a href=&#34;https://uiua.org/pad?src=4oqP4oavNV8xMOKMisOXMjZb4o2l4pqCNTBdK0Bh4oehMjY=&#34;&gt;you can play
with it on the website yourself&lt;/a&gt; - but one could enter those function names in full
and the interpreter will figure it out for you&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select reshape 5_10 floor mult 26[repeat rand 50] add @a range 26

...

⊏ ↯ 5_10 ⌊ × 26[⍥⚂ 50] + @a ⇡ 26&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;╭─              
╷ &amp;quot;wtyefkiavu&amp;quot;  
  &amp;quot;gfllwkuqcn&amp;quot;  
  &amp;quot;qydoiyqprk&amp;quot;  
  &amp;quot;awvdxdsymj&amp;quot;  
  &amp;quot;zzvueychem&amp;quot;  
               ╯&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I know people like to say this is “unreadable” but with a little colour, a lot of
the elements of the Raku and R solutions are here&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/uiua_coloured.png&#34; alt=&#34;Uiua solution with colours corresponding to the earlier Raku and R solutions&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Uiua solution with colours corresponding to the earlier Raku and R solutions&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So… is that more concise than the R or even Raku solutions? Gosh, no. BUT, I
had a lot more fun writing it. For certain problems, APL-like languages really
do have a lot to offer, and for all I know there’s a much better way to spell
this in very few glyphs that I’ve overlooked (feel free to send me one!).&lt;/p&gt;
&lt;p&gt;You can make quite complex things; the Uiua logo itself - made in Uiua!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;xy ← ⍘⍉⊞⊟. ÷÷2∶ -÷2,⇡.200
Rgb ← [∶⍘⊟×.xy ↯△⊢xy0.5]
u ← ↥&amp;lt;0.2∶&amp;gt;0.7.+×2 ×.∶⍘⊟xy
c ← &amp;lt;∶√/+ⁿ2 xy
⍉⊂∶-¬u c1 +0.1 ∺↧Rgb c0.95&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/uiua_logo.png&#34; alt=&#34;Uiui code to generate the Uiua logo&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Uiui code to generate the Uiua logo&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Another neat fact about this language is that it’s written in Rust, so it’s
potentially quite fast as well. Array stuff in Rust is top of mind for me at the
moment - &lt;a href=&#34;https://www.jernesto.com/articles/rapl&#34;&gt;this cool post&lt;/a&gt; from earlier
in the year covers an implementation of some APL-like array processing in Rust
which I’m keen to dig deeper into (there’s a not-too-old
&lt;a href=&#34;https://github.com/JErnestoMtz/rapl&#34;&gt;repo&lt;/a&gt; of things already built). I clearly
need to re-read my own posts, because I actually linked to that cool post above
in &lt;a href=&#34;https://jcarroll.com.au/2023/07/07/array-languages-r-vs-apl/&#34;&gt;my first APL-related post&lt;/a&gt;, but because I had searched for “rank polymorphism” and it fit the bill.&lt;/p&gt;
&lt;p&gt;The fact that R has a lot of these array-compatible functions out-of-the-box is
terribly underpromoted and undercelebrated. Bringing this back around to R, can
I use the array method there? I can certainly build a matrix of 50 letters quite
concisely, though the fact that R doesn’t concatenate characters so easily still
hurts&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m &amp;lt;- matrix(sample(letters, 50, replace = TRUE), 5, 10)
apply(m, 1, \(x) paste0(x, collapse = &amp;quot;&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;wzyfpoyegm&amp;quot; &amp;quot;xjehbspfql&amp;quot; &amp;quot;vjpvimtwkm&amp;quot; &amp;quot;uzkwmgcmix&amp;quot; &amp;quot;suakdpagvl&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m hoping to play a bit more with Uiua, and I was genuinely impressed that I managed
to solve this at all, but I’m still just beginning my journey in APL and there’s no
shortage of things to learn there. In fact, despite having no tryapl.org, I &lt;em&gt;do&lt;/em&gt; have
the Ride editor locally. A bit of searching for clues later, and I have something!&lt;/p&gt;
&lt;p&gt;In (Dyalog) APL you can create the uppercase alphabet with just&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  ⎕A&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;ABCDEFGHIJKLMNOPQRSTUVWXYZ&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;similar to &lt;code&gt;LETTERS&lt;/code&gt;. Lowercase letters can be generated with&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  819⌶⎕A&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;abcdefghijklmnopqrstuvwxyz&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or (possibly implementation-specific)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  ⎕c⎕a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;abcdefghijklmnopqrstuvwxyz&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Selecting random elements from this involves &lt;a href=&#34;https://aplwiki.com/wiki/Roll&#34;&gt;&lt;code&gt;roll&lt;/code&gt;&lt;/a&gt; with
the syntax&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  ?5 10⍴26&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;18 16  7  8 22 25 15 17 24 19
18 23 24  9 25 17  4  2 25 24
10 13  6 11 10 17 21  9 15 20
25  8  3 12  4  2 21  3  1 18
 2  5 17 19 25  3  3 21  9  4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which produces random values between 1 and the right argument (in this case, a
5x10 reshape of the value &lt;code&gt;26&lt;/code&gt; repeated over and over). That’s exactly what we need
as indices to select letters. Putting these together&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;⎕c⎕a[?5 10⍴26]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;axpyohnotq
hsrottizwk
dgecrgxbcu
qvvxszptpq
wmaktfuvwf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even better - if we store the &lt;code&gt;letters&lt;/code&gt; like R does, and define a functional
version which takes a left argument (&lt;code&gt;⍺&lt;/code&gt;; the shape of the
array), a right argument (&lt;code&gt;⍵&lt;/code&gt;; the letters to sample from), and automatically
calculates the length as &lt;code&gt;≢⍵&lt;/code&gt;, then the entire solution is&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;letters←⎕c⎕a
randstrings←{⍵[?⍺⍴≢⍵]}
5 10 randstrings letters&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;npentutsdo
jttcnqeuqm
imgrtupyfx
eliiqnishu
jonkovlmcn&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, &lt;em&gt;that’s&lt;/em&gt; concise! And, provided you know what &lt;code&gt;?&lt;/code&gt;, &lt;code&gt;⍴&lt;/code&gt;, and &lt;code&gt;≢&lt;/code&gt; do, it’s
fairly readable (in my opinion, at least).&lt;/p&gt;
&lt;p&gt;Can you make a better/shorter/more interesting solution to the random strings
problem? Or can improve the Uiua solution? I can be found on
&lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; or use the comments below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-10-09
##  pandoc   3.1.8 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.17    2023-05-16 [1] CRAN (R 4.1.2)
##  bookdown      0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  bslib         0.5.1   2023-08-11 [3] CRAN (R 4.3.1)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [3] CRAN (R 4.2.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest        0.6.33  2023-07-07 [3] CRAN (R 4.3.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.21    2023-05-05 [3] CRAN (R 4.3.0)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  htmltools     0.5.6   2023-08-10 [3] CRAN (R 4.3.1)
##  htmlwidgets   1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv        1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.7   2023-06-29 [3] CRAN (R 4.3.1)
##  knitr         1.43    2023-05-25 [3] CRAN (R 4.3.0)
##  later         1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  pkgbuild      1.4.0   2022-11-27 [1] CRAN (R 4.1.2)
##  pkgload       1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.8.2   2023-06-30 [3] CRAN (R 4.3.1)
##  profvis       0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises      1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps            1.7.5   2023-04-18 [3] CRAN (R 4.3.0)
##  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.1.1   2023-04-28 [1] CRAN (R 4.1.2)
##  rmarkdown     2.24    2023-08-14 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.7   2023-07-15 [3] CRAN (R 4.3.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny         1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi       1.7.12  2023-01-11 [3] CRAN (R 4.2.2)
##  stringr       1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis       2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  vctrs         0.6.3   2023-06-14 [1] CRAN (R 4.1.2)
##  xfun          0.40    2023-08-09 [3] CRAN (R 4.3.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml          2.3.7   2023-01-23 [3] CRAN (R 4.2.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Four Filters for Functional (Programming) Friends</title>
      <link>https://jcarroll.com.au/2023/08/30/four-filters-for-functional-programming-friends/</link>
      <pubDate>Wed, 30 Aug 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/08/30/four-filters-for-functional-programming-friends/</guid>
      <description>&lt;p&gt;I’m part of a local Functional Programming Meetup group which hosts talks, but also
coordinates social meetings where we discuss all sorts of FP-related topics including
Haskell and other languages. We’ve started running challenges where we all solve a
given problem in a language of our choosing then discuss over drinks how they compare.&lt;/p&gt;
&lt;p&gt;This month we went with an “easy” problem with a wrinkle - we would solve the ‘strain’
exercise from Exercism (&lt;a href=&#34;https://exercism.org/tracks/haskell/exercises/strain&#34;&gt;Haskell&lt;/a&gt;,
&lt;a href=&#34;https://exercism.org/tracks/python/exercises/strain&#34;&gt;Python&lt;/a&gt; - your access to these is
likely conditional on you being enrolled in that language track) with an extension:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The problem is trivial; the challenge is to solve it in 4 different ways using your language of choice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The problem itself is given as&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Implement the &lt;code&gt;keep&lt;/code&gt; and &lt;code&gt;discard&lt;/code&gt; operation on collections. Given a collection and a predicate on the collection’s elements, &lt;code&gt;keep&lt;/code&gt; returns a new collection containing those elements where the predicate is true, while &lt;code&gt;discard&lt;/code&gt; returns a new collection containing those elements where the predicate is false.&lt;/p&gt;
&lt;p&gt;For example, given the collection of numbers:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;1, 2, 3, 4, 5&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;And the predicate:&lt;/p&gt;
&lt;p&gt;“is the number even?”&lt;/p&gt;
&lt;p&gt;Then your keep operation should produce:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;2, 4&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;While your discard operation should produce:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;1, 3, 5&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;but with a restriction:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Keep your hands off that filter/reject/whatchamacallit functionality provided by your standard library! Solve this one yourself using other basic tools instead.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I figured it’s a good opportunity to write as I solve it, so here’s my R solutions.&lt;/p&gt;
&lt;p&gt;I’ll define a test case so I can try out things as I go&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;test_vec &amp;lt;- c(1, 2, 3, 4, 5)
test_vec&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 2 3 4 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the predicates related to ‘even’ and ‘odd’ as functions which return &lt;code&gt;TRUE&lt;/code&gt; or &lt;code&gt;FALSE&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_even &amp;lt;- function(x) {
  x %% 2 == 0
}

is_even(7)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_even(8)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_odd &amp;lt;- function(x) {
  !is_even(x)
}

is_odd(7)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_odd(8)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Firstly, the restriction doesn’t seem to worry me because when I think of “filter” in R
I immediately think of &lt;code&gt;dplyr::filter()&lt;/code&gt; which works on &lt;code&gt;data.frame&lt;/code&gt; (or &lt;code&gt;tibble&lt;/code&gt;)
objects, and (given the examples) we’re aiming to work with vectors (the problem is stated
the same in several languages, so “collection” is a generalisation).&lt;/p&gt;
&lt;p&gt;What about &lt;code&gt;base::Filter()&lt;/code&gt;? The help states&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Filter&lt;/code&gt; extracts the elements of a vector for which a predicate (logical) function gives true.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Filter(is_even, test_vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Filter(is_odd, test_vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 3 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yep, that works exactly as I hoped, but is also a built-in “filter” so I can’t use it.&lt;/p&gt;
&lt;p&gt;When I think of &lt;code&gt;keep&lt;/code&gt; and &lt;code&gt;discard&lt;/code&gt; I do think of the &lt;code&gt;purrr&lt;/code&gt; functions, and while these, too
do exactly what I want&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;purrr::keep(test_vec, is_even)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;purrr::discard(test_vec, is_even)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 3 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;They’re in a library, so I’m going to say they don’t count.&lt;/p&gt;
&lt;p&gt;One of the things I like about the way R does subsetting (via the square-bracket &lt;code&gt;[&lt;/code&gt;
which &lt;em&gt;is by itself&lt;/em&gt; a function, but requires a matching &lt;code&gt;]&lt;/code&gt; to satisfy the parser) is that you
can use a logical vector to subset another vector,&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;c(3, 5, 8, 12)[c(TRUE, FALSE, FALSE, TRUE)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]  3 12&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which means that if I can &lt;em&gt;produce&lt;/em&gt; such a logical vector, say, by applying a predicate function, I can do subsetting that way&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;test_vec[is_even(test_vec)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;test_vec[is_odd(test_vec)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 3 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of using &lt;code&gt;is_odd()&lt;/code&gt; I can just &lt;em&gt;negate&lt;/em&gt; the logical vector to get the same effect&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;test_vec[!is_even(test_vec)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 3 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can make those into functions that take a predicate and a vector&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;keep_1 &amp;lt;- function(f, x) {
  x[f(x)]
}

discard_1 &amp;lt;- function(f, x) {
  x[!f(x)]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Testing these&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;keep_1(is_even, test_vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;discard_1(is_even, test_vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 3 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One down!&lt;/p&gt;
&lt;p&gt;One thing to note with this approach is that R is &lt;em&gt;vectorised&lt;/em&gt; - I’ve discussed this
a few times on this blog (&lt;a href=&#34;https://jcarroll.com.au/2023/08/29/now-you-re-thinking-with-arrays/&#34;&gt;most recently&lt;/a&gt;) - which
means that these predicate functions will gladly take a vector, not just a single value. This
works for the &lt;code&gt;is_even()&lt;/code&gt; function because inside that, the modulo operator &lt;code&gt;%%&lt;/code&gt; is itself
vectorised, so&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is_even(c(2, 4, 6, 9, 11, 13))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]  TRUE  TRUE  TRUE FALSE FALSE FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As I wrote in my previous post, thinking like this just becomes so natural in R that I
have to force myself to remember that not every language does that.&lt;/p&gt;
&lt;p&gt;It’s also worth mentioning that I’m passing a reference to the function &lt;code&gt;is_even&lt;/code&gt; to our
&lt;code&gt;keep&lt;/code&gt; and &lt;code&gt;discard&lt;/code&gt; functions - that is serving as our predicate because I need a way to
state “is the number even?” which references the number, so I need a function. That &lt;em&gt;doesn’t&lt;/em&gt;
have to be a named function, though - it could be an “anonymous” function (a “lambda”) if
I wanted&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;keep_1(function(z) z %% 2 == 0, test_vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;discard_1(function(z) z %% 2 == 0, test_vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 3 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can subset a vector with a logical vector of the same length, specifying whether or not
to include that element, but I can &lt;em&gt;also&lt;/em&gt; subset by position (keeping in mind that R is a
1-based language which means the first element is indexed by a &lt;code&gt;1&lt;/code&gt; - why would any language
do anything different? 😜)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;c(3, 5, 8, 12)[c(1, 4)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]  3 12&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function &lt;code&gt;which()&lt;/code&gt; takes a logical vector and returns which indices are &lt;code&gt;TRUE&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;which(c(TRUE, FALSE, FALSE, TRUE))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so I can use this with our predicate to keep elements&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;keep_2 &amp;lt;- function(f, x) {
  x[which(f(x))]
}

keep_2(is_even, test_vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, discarding elements by index doesn’t use a logical negation, it uses a
negative sign (&lt;code&gt;-&lt;/code&gt;)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;discard_2 &amp;lt;- function(f, x) {
  x[-which(f(x))]
}

discard_2(is_even, test_vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 3 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you look at the source of &lt;code&gt;Filter()&lt;/code&gt;, you’ll see that I wasn’t far off of exactly
that&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Filter&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## function (f, x) 
## {
##     ind &amp;lt;- as.logical(unlist(lapply(x, f)))
##     x[which(ind)]
## }
## &amp;lt;bytecode: 0x55da1b321ad8&amp;gt;
## &amp;lt;environment: namespace:base&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but it still counts.&lt;/p&gt;
&lt;p&gt;Another option would be to unpack the elements themselves and do some stepwise
comparisons in a loop. For each element &lt;code&gt;el&lt;/code&gt; in the vector &lt;code&gt;x&lt;/code&gt;, test if &lt;code&gt;f(el)&lt;/code&gt; is &lt;code&gt;TRUE&lt;/code&gt;,
and if it is, concatenate &lt;code&gt;el&lt;/code&gt; to the end of the accumulating &lt;code&gt;result&lt;/code&gt; vector&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;keep_3 &amp;lt;- function(f, x) {
  result &amp;lt;- c()
  for (el in x) {
    if (f(el)) {
      result &amp;lt;- c(result, el)
    }
  }
  result
}

keep_3(is_even, test_vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;discard_3 &amp;lt;- function(f, x) {
  result &amp;lt;- c()
  for (el in x) {
    if (!f(el)) {
      result &amp;lt;- c(result, el)
    }
  }
  result
}

discard_3(is_even, test_vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 3 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, this approach is a Bad Idea™ in general but I’m not optimising anything here. This
approach &lt;em&gt;does&lt;/em&gt; have the advantage that it isn’t relying on R’s vectorised capabilities, since
each element is passed to the predicate function individually, so if I did have a non-vectorized
predicate function, this would still work.&lt;/p&gt;
&lt;p&gt;I really want a “weird” way to do this. R has plenty of weird to go around, but since I’ve
been learning some Haskell, and the challenge originally referenced the Haskell solution,
what if I code a Haskell-esque solution?&lt;/p&gt;
&lt;p&gt;Haskell makes good use of recursive functions. Any loop can be written as a recursion
(and vice-versa) so the previous solution is a good starting point. First, I define
a base case; if I run out of numbers to process, return &lt;code&gt;NULL&lt;/code&gt;. A convenient feature
of R vectors is that &lt;code&gt;NULL&lt;/code&gt;s are dropped&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;c(1, 2, NULL, 3, 4, NULL, 5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 2 3 4 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Otherwise, I can take the first value in the vector and test it with the predicate. If it
returns &lt;code&gt;TRUE&lt;/code&gt; I can append it to what I’ve calculated so far, and recursively
call the function again with the rest of the vector. That could look like&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;keep_4 &amp;lt;- function(f, x) {
  if (!length(x)) return(NULL)
  if (f(x[1])) {
    return(c(x[1], Recall(f, x[-1])))
  } else {
    return(Recall(f, x[-1]))
  }
}

keep_4(is_even, test_vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some interesting points about this: the &lt;code&gt;Recall()&lt;/code&gt; function is nice for defining a recursive
function. I could have used &lt;code&gt;keep_4&lt;/code&gt; there, but the advantage of this implementation is
that I can rename the function and it still works as expected&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;keep_4_also &amp;lt;- keep_4
rm(&amp;quot;keep_4&amp;quot;)

keep_4_also(is_even, test_vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I had explicitly referenced &lt;code&gt;keep_4&lt;/code&gt; inside itself, that recursion would fail with this
renaming.&lt;/p&gt;
&lt;p&gt;The negative subsetting works as described above; &lt;code&gt;x[-1]&lt;/code&gt; means “not including the first
element”. Lastly, testing &lt;code&gt;if (!length(x))&lt;/code&gt; works because &lt;code&gt;0&lt;/code&gt; can be coerced to &lt;code&gt;FALSE&lt;/code&gt; and
any other value to &lt;code&gt;TRUE&lt;/code&gt;, so if the &lt;code&gt;length&lt;/code&gt; of &lt;code&gt;x&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; &lt;code&gt;0&lt;/code&gt;, this condition is met.&lt;/p&gt;
&lt;p&gt;The discarding variant is similar, just with the two &lt;code&gt;returns()&lt;/code&gt; around the other way, or&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;discard_4 &amp;lt;- function(f, x) {
  if (!length(x)) return(NULL)
  if (!f(x[1])) {
    return(c(x[1], Recall(f, x[-1])))
  } else {
    return(Recall(f, x[-1]))
  }
}

discard_4(is_even, test_vec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 3 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There we go; 4 hand-coded implementations of &lt;code&gt;keep&lt;/code&gt; and &lt;code&gt;discard&lt;/code&gt; in R.&lt;/p&gt;
&lt;p&gt;Can you think of another that doesn’t use &lt;code&gt;Filter()&lt;/code&gt; or an external library? Let me
know in the comments below or on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt;. I’m
looking forward to seeing how people solved this in other languages.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-08-30
##  pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.17    2023-05-16 [1] CRAN (R 4.1.2)
##  bookdown      0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  bslib         0.5.0   2023-06-09 [3] CRAN (R 4.3.1)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [3] CRAN (R 4.2.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest        0.6.33  2023-07-07 [3] CRAN (R 4.3.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.21    2023-05-05 [3] CRAN (R 4.3.0)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  htmltools     0.5.6   2023-08-10 [3] CRAN (R 4.3.1)
##  htmlwidgets   1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv        1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.7   2023-06-29 [3] CRAN (R 4.3.1)
##  knitr         1.43    2023-05-25 [3] CRAN (R 4.3.0)
##  later         1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  pkgbuild      1.4.0   2022-11-27 [1] CRAN (R 4.1.2)
##  pkgload       1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.8.2   2023-06-30 [3] CRAN (R 4.3.1)
##  profvis       0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises      1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps            1.7.5   2023-04-18 [3] CRAN (R 4.3.0)
##  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.1.1   2023-04-28 [1] CRAN (R 4.1.2)
##  rmarkdown     2.23    2023-07-01 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.7   2023-07-15 [3] CRAN (R 4.3.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny         1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi       1.7.12  2023-01-11 [3] CRAN (R 4.2.2)
##  stringr       1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis       2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  vctrs         0.6.3   2023-06-14 [1] CRAN (R 4.1.2)
##  xfun          0.40    2023-08-09 [3] CRAN (R 4.3.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml          2.3.7   2023-01-23 [3] CRAN (R 4.2.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Now You&#39;re Thinking with Arrays</title>
      <link>https://jcarroll.com.au/2023/08/29/now-you-re-thinking-with-arrays/</link>
      <pubDate>Tue, 29 Aug 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/08/29/now-you-re-thinking-with-arrays/</guid>
      <description>&lt;p&gt;I keep hearing the assertion that “writing APL/Haskell/etc… makes you think
differently” and I kept wondering why I agreed with the statement but at the same time
didn’t think too much of it. I believe I’ve figured out that it’s &lt;em&gt;because&lt;/em&gt; I happened to have
been using Array-aware languages this whole time! It turns out R is an even better
language for beginners than I thought.&lt;/p&gt;
&lt;p&gt;Let’s start with some basics. A “scalar” value is just a number by itself. That might
have some units that may or may not be represented well in what you’re doing, but it’s
a single value on its own, like &lt;code&gt;42&lt;/code&gt;. A “vector” in R is just a collection of these “scalar”
values and is constructed with the &lt;code&gt;c()&lt;/code&gt; operator&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;c(3, 4, 5, 6)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3 4 5 6&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Going right back to basics, the &lt;code&gt;[1]&lt;/code&gt; output at the start of the line indicates the index
of the element directly to its right, in this case the first element. If we had more elements,
then the newline starts with the index of the first element on that line. Here I’ve set the line width smaller than usual so that it wraps sooner&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;1:42&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1]  1  2  3  4  5  6  7  8  9 10 11 12
## [13] 13 14 15 16 17 18 19 20 21 22 23 24
## [25] 25 26 27 28 29 30 31 32 33 34 35 36
## [37] 37 38 39 40 41 42&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The quirk of how R works with vectors is the there aren’t actually &lt;em&gt;any&lt;/em&gt; scalar values - if
you try to create a vector with only a single element, it’s still a vector&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- c(42)
x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 42&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.vector(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(note the &lt;code&gt;[1]&lt;/code&gt; indicating the first index of the vector &lt;code&gt;x&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; the vector &lt;code&gt;TRUE&lt;/code&gt;). Even if you don’t &lt;em&gt;try&lt;/em&gt; to make it a vector, it still is one&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- 42
x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 42&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.vector(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mike Mahoney has
&lt;a href=&#34;https://www.mm218.dev/posts/2023-08-07-vector/&#34;&gt;a great post&lt;/a&gt; detailing the term
“vector” and how it relates to an R vector as well as the more mathematical definition
which involves constructing an “arrow” in some space so that you describe both “magnitude”
and “direction” at the same time.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/vector.jpg&#34; alt=&#34;“Direction and magnitude”&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;“Direction and magnitude”&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So, we &lt;em&gt;always&lt;/em&gt; have a vector if we have a 1-dimensional collection of data. But wait,
you say, there’s also &lt;code&gt;list&lt;/code&gt;!&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- list(a = 42)
x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## $a
## [1] 42&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.vector(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A nice try, but lists are also vectors, it’s just that they’re “recursive”&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.recursive(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.recursive(c(42))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fine, what about a matrix, then?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- matrix(1:9, nrow = 3, ncol = 3)
x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.vector(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No, but that still makes sense - a matrix isn’t a vector. It &lt;em&gt;is&lt;/em&gt; however, an “array” - the
naming convention in R is a bit messy because, while “matrix” and “array” are often the
same thing, as the dimensions increase, more things expect an “array” class, so R tags
a “matrix” with both&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;class(matrix())&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;matrix&amp;quot; &amp;quot;array&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This recently surprised Josiah Parry leading to &lt;a href=&#34;https://josiahparry.com/posts/2023-06-11-matrix-bug&#34;&gt;this post&lt;/a&gt; explaining some of the internal
inconsistencies of this class of object.&lt;/p&gt;
&lt;p&gt;Now that we have vectors figured out, I can get to the point of this post - that
thinking about data with a “vector” or even “array” mindset works differently.&lt;/p&gt;
&lt;p&gt;I started learning some APL because I loved some videos by &lt;a href=&#34;https://www.youtube.com/@code_report&#34;&gt;code_report&lt;/a&gt;. The person
behind those is Conor Hoekstra. I didn’t realise that I’d actually heard a
&lt;a href=&#34;https://corecursive.com/065-competitive-coding-with-conor-hoekstra/&#34;&gt;CoRecursive&lt;/a&gt;
podcast episode interviewing him, so now I need to go back and re-listen to that one. Conor
also hosts &lt;a href=&#34;https://www.arraycast.com/&#34;&gt;The Array Cast&lt;/a&gt; podcast that I heard him
mention in yet another &lt;a href=&#34;https://adspthepodcast.com/&#34;&gt;of his podcasts&lt;/a&gt; (how do
people have the time to make all of these!?!). I was listening to the &lt;a href=&#34;https://www.arraycast.com/episodes/episode60-rob-pike&#34;&gt;latest of these;
an interview with Rob Pike&lt;/a&gt;, one
of the co-creators of Go and UTF-8 - it’s a really interesting interview full of history,
insights, and a lot of serious name dropping.&lt;/p&gt;
&lt;p&gt;Anyway, Rob is describing what it is he really likes about APL and says&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“I saw a talk some time ago, I wish I could remember where it was, where somebody said, this is why programming languages are so difficult for people. Let’s say that I have a list of numbers and I want to add seven to every number on that list. And he went through about a dozen languages showing how you create a list of numbers and then add seven to it. Right? And it went on and on and on. And he said,”Wouldn’t it be nice if you could just type 7+ and then write the list of numbers?” And he said, “Well, you know what? There’s one language that actually does that, and that’s APL.” And I think there’s something really profound in that, that there’s no ceremony in APL. If you want to add two numbers together in any language, you can add two numbers together. But if you want to add a matrix and a matrix, or a matrix and a vector, or a vector and a scaler or whatever, there’s no extra ceremony involved. You just write it down.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(&lt;a href=&#34;https://www.arraycast.com/episode-60-transcript#:~:text=I%20saw%20a%20talk%20some%20time%20ago&#34;&gt;link to shownotes&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;The talk he mentions is linked in the shownotes as &lt;a href=&#34;https://youtu.be/8Ab3ArE8W3s&amp;amp;t=434&#34;&gt;“Stop Writing Dead Programs” by Jack Rusher (Strange Loop 2022)&lt;/a&gt; (linked to the relevant timestamp, and
which I’m pretty sure I’ve watched before - it’s a great talk!) where
Jack shows how to add &lt;code&gt;1&lt;/code&gt; to a vector of values in a handful of languages. He demonstrates that in
some languages there’s lots you need to write that has &lt;strong&gt;nothing&lt;/strong&gt; to do with the problem itself;
allocating memory, looping to some length, etc… then leads to demonstrating that the way to
do this in APL is&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;1 + 1 2 3 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with &lt;strong&gt;none&lt;/strong&gt; of the overhead - just the declaration of what operation should occur.&lt;/p&gt;
&lt;p&gt;The excitement with which Rob explains this in the podcast spoke to how important this
idea is; that you can work with more than just scalar values in the mathematical sense
without having to explain to the language &lt;em&gt;what you mean&lt;/em&gt; and write a loop around a vector.&lt;/p&gt;
&lt;p&gt;Two questions were buzzing at the back of my mind, though:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;&lt;p&gt;Why isn’t this such a revelation to me?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is this not a common feature?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I &lt;em&gt;know&lt;/em&gt; R does work this way because I’m very familiar with it, and perhaps that &lt;em&gt;is&lt;/em&gt;
the answer to the first question - I know R better than any other language I know, and
perhaps I’ve just become accustomed to being able to do things like “add two vectors”.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- c(1, 2, 3, 4, 5) # or 1:5
a + 7&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]  8  9 10 11 12&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/portals.jpg&#34; alt=&#34;Now you’re thinking with portals vectors!&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Now you’re thinking with &lt;s&gt;portals&lt;/s&gt; vectors!&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The ideas of “add two vectors” and “add a number to a vector” are one in the same, as discussed above. The ability to do so is called &lt;a href=&#34;https://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Rank_polymorphism&#34;&gt;“rank polymorphism”&lt;/a&gt; and
R has a weak version of it - not everything works for every dimension, but single values, vectors, and matrices do generalise for many functions. I can add a value to every element of a matrix, too&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m &amp;lt;- matrix(1:12, nrow = 3, ncol = 4)
m&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m + 7&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3] [,4]
## [1,]    8   11   14   17
## [2,]    9   12   15   18
## [3,]   10   13   16   19&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and adding a vector to a matrix repeats the operation over rows&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m &amp;lt;- matrix(1, nrow = 3, ncol = 4)
m&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3] [,4]
## [1,]    1    1    1    1
## [2,]    1    1    1    1
## [3,]    1    1    1    1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;v &amp;lt;- c(11, 22, 33)
m + v&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3] [,4]
## [1,]   12   12   12   12
## [2,]   23   23   23   23
## [3,]   34   34   34   34&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sidenote: the distinction between “repeat over rows” and “repeat over columns” is also
discussed in the Array Cast episode - if you want to know more, there’s &lt;a href=&#34;https://aplwiki.com/wiki/Leading_axis_theory&#34;&gt;“leading axis theory”&lt;/a&gt;. R uses column-major order which
is why the matrix &lt;code&gt;m&lt;/code&gt; filled the sequential values down the first column, and why you need
to specify &lt;code&gt;byrow = TRUE&lt;/code&gt; if you want to fill the other way. It’s also why &lt;code&gt;m + v&lt;/code&gt; repeats
over rows, although if you are expecting it to repeat over columns and try to use a &lt;code&gt;v&lt;/code&gt; with 4
elements it will (silently) work, recycling the vector &lt;code&gt;v&lt;/code&gt;, and giving you something you
didn’t expect&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;v &amp;lt;- c(11, 22, 33, 44)
m + v&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3] [,4]
## [1,]   12   45   34   23
## [2,]   23   12   45   34
## [3,]   34   23   12   45&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;{reticulate} has a really &lt;a href=&#34;https://cran.r-project.org/web/packages/reticulate/vignettes/arrays.html&#34;&gt;nice explainer&lt;/a&gt;
of the differences between R (column-major) and python (row-major), and importantly,
the interop between these two.&lt;/p&gt;
&lt;p&gt;So, is working with arrays actually so uncommon? I first thought of Julia,
and since it’s much newer than R and took a lot of inspiration from a variety
of languages, perhaps it works&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;a = [1, 2, 3, 4, 5]
a + 7&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-danger&#34;&gt;&lt;code&gt;ERROR: MethodError: no method matching +(::Vector{Int64}, ::Int64)
For element-wise addition, use broadcasting with dot syntax: array .+ scalar&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not quite, but the error message is extremely helpful. Julia wants to perform
element-wise addition using the broadcasting operator &lt;code&gt;.&lt;/code&gt; so it needs to be&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;a .+ 7&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;5-element Vector{Int64}:
  8
  9
 10
 11
 12&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Still, that’s a “know the language” thing that’s outside of “add a number to a vector”,
so no credit.&lt;/p&gt;
&lt;p&gt;Well, what about python?&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;a = [1, 2, 3, 4, 5]
a + 7&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-danger&#34;&gt;&lt;code&gt;Traceback (most recent call last):
  File &amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;, line 1, in &amp;lt;module&amp;gt;
TypeError: can only concatenate list (not &amp;quot;int&amp;quot;) to list&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The canonical way, I believe, is to use a list comprehension&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;a = [1, 2, 3, 4, 5]
[i + 7 for i in a]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[8, 9, 10, 11, 12]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and we’re once more using a language feature that’s outside of “add a number to a
vector” so again, no credit. For the pedants: there is library support for this
if you use numpy&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;import numpy as np

a = [1, 2, 3, 4, 5]
np.array(a) + 7&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;array([ 8,  9, 10, 11, 12])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but I wouldn’t call that a success.&lt;/p&gt;
&lt;p&gt;I asked ChatGPT what other languages could do this and it suggested MATLAB. Now,
that’s a proprietary language I don’t have access to, but octave is an open-source
alternative that is more or less the same, so I tried that&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a = [1, 2, 3, 4, 5];
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;a =

   1   2   3   4   5&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a + 7&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;ans =

    8    9   10   11   12&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, yeah - a win for MATLAB. I remember using MATLAB back at Uni in
an early (second year?) Maths (differential equations?) course and it was
probably the very first time I was actually
introduced to a programming language. IIRC, “everything is a matrix” (which works
out okay for engineering and maths use-cases) so this a) probably isn’t surprising that
it works, and b) makes sense that it gets lumped in with the “array languages”.&lt;/p&gt;
&lt;p&gt;Thinking back to the other programming languages I’ve learned sufficiently, I wondered how Fortran
dealt with this - I used Fortran (90) for all of my PhD and postdoc calculations.
I loved that Fortran had vectors (and n-dimensional arrays) without
having to do any manual memory allocation, and for that reason alone it was well-suited to
theoretical physics modeling. I’ve been re-learning some Fortran via Exercism, so
I gave that a go&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;$ cat array.f90&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;program add_to_array

  implicit none
  integer, dimension(5) :: a

  a = (/1, 2, 3, 4, 5/)
  print *, a + 7

end program add_to_array&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compiling and running this…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;$ gfortran -o array array.f90
$ ./array&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;           8           9          10          11          12&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A win! Okay, a little ceremony to declare the vector itself, but that’s strict
typing for you.&lt;/p&gt;
&lt;p&gt;With these results at hand, I think back to the question&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why isn’t this such a revelation to me?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I learned MATLAB, Fortran, then R, over the course of about a decade, and barely
touched other languages with any seriousness while doing so… I’ve been using
array languages more or less exclusively all this time.&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/bane.jpg&#34; alt=&#34;“You merely learned to use arrays, I was born in them, molded by them”&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;“You merely learned to use arrays, I was born in them, molded by them”&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Better still, they’re all &lt;em&gt;column-major&lt;/em&gt; array languages.&lt;/p&gt;
&lt;p&gt;I think &lt;em&gt;this&lt;/em&gt; is why APL seems to beautiful to me - it does what I &lt;em&gt;know&lt;/em&gt; I want and
it does it with the least amount of ceremony.&lt;/p&gt;
&lt;p&gt;I wrote a bit about this in &lt;a href=&#34;https://jcarroll.com.au/2023/07/07/array-languages-r-vs-apl/&#34;&gt;a previous post&lt;/a&gt; - that a language
can hide some complexity for you, like the fact that it &lt;em&gt;does&lt;/em&gt; need to internally do a loop
over some elements in order to add two vectors, but when the language itself provides
an interface where you don’t have to worry about that, things get beautiful.&lt;/p&gt;
&lt;p&gt;At PyConAU this year there was a keynote &lt;a href=&#34;https://youtu.be/zUyR-Qbr4Yg&#34;&gt;“The Complexity of Simplicity”&lt;/a&gt; which reminded me a lot of another post
&lt;a href=&#34;https://ferd.ca/complexity-has-to-live-somewhere.html&#34;&gt;“Complexity Has to Live Somewhere”&lt;/a&gt;.
I think APL really nailed removing a lot of the syntax complexity of a language, leaving
mainly just the operations you wish to perform. Haskell does similar but adds back in
(albeit, useful) language features that involve syntax.&lt;/p&gt;
&lt;p&gt;Of the languages I did learn first, I would have to say that R wins over MATLAB and Fortran
in terms of suitability as a first programming language, but now that I recognise that the
“array” way of thinking comes along with that, I really do think it has a big advantage
over, say, python in terms of shaping that mindset. Sure, if you start out with numpy you
may gain that same advantage, but either way I would like to think there’s a lot to be
gained from starting with an “array-aware” language.&lt;/p&gt;
&lt;p&gt;Did I overlook another language that can work so nicely with arrays? Have you reflected on
how you think in terms of arrays and programming in general? Let me know in the comments or
on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-08-29
##  pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.17    2023-05-16 [1] CRAN (R 4.1.2)
##  bookdown      0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  bslib         0.5.0   2023-06-09 [3] CRAN (R 4.3.1)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [3] CRAN (R 4.2.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest        0.6.33  2023-07-07 [3] CRAN (R 4.3.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.21    2023-05-05 [3] CRAN (R 4.3.0)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  htmltools     0.5.6   2023-08-10 [3] CRAN (R 4.3.1)
##  htmlwidgets   1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv        1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.7   2023-06-29 [3] CRAN (R 4.3.1)
##  knitr         1.43    2023-05-25 [3] CRAN (R 4.3.0)
##  later         1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  pkgbuild      1.4.0   2022-11-27 [1] CRAN (R 4.1.2)
##  pkgload       1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.8.2   2023-06-30 [3] CRAN (R 4.3.1)
##  profvis       0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises      1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps            1.7.5   2023-04-18 [3] CRAN (R 4.3.0)
##  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.1.1   2023-04-28 [1] CRAN (R 4.1.2)
##  rmarkdown     2.23    2023-07-01 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.7   2023-07-15 [3] CRAN (R 4.3.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny         1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi       1.7.12  2023-01-11 [3] CRAN (R 4.2.2)
##  stringr       1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis       2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  vctrs         0.6.3   2023-06-14 [1] CRAN (R 4.1.2)
##  xfun          0.40    2023-08-09 [3] CRAN (R 4.3.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml          2.3.7   2023-01-23 [3] CRAN (R 4.2.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Taking from Infinite Sequences</title>
      <link>https://jcarroll.com.au/2023/08/18/taking-from-infinite-sequences/</link>
      <pubDate>Fri, 18 Aug 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/08/18/taking-from-infinite-sequences/</guid>
      <description>&lt;p&gt;One thing that has really caught my attention as I learn more programming
languages is the idea of &lt;em&gt;generators&lt;/em&gt; or infinite sequences of values. Yes, &lt;em&gt;infinite&lt;/em&gt;.
Coming from R, that seems unlikely, but in at least several other languages,
it’s entirely possible thanks to iterators and lazy evaluation.&lt;/p&gt;
&lt;p&gt;I saw &lt;a href=&#34;https://youtu.be/7fylNa2wZaU&#34;&gt;this video&lt;/a&gt; which solves a codewars challenge
using an infinite list, which references &lt;a href=&#34;https://youtu.be/bnRNiE_OVWA&#34;&gt;this one&lt;/a&gt;
on the same topic.&lt;/p&gt;
&lt;p&gt;First, a diversion into recursion&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/recursive.png&#34; alt=&#34;A timely combination. @rverbsr&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;A timely combination. &lt;a href=&#34;https://botsin.space/@rverbsr/110903654468565096&#34;&gt;@rverbsr&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In Haskell, one of the first exercises after “Hello, World!” people discover is
the Fibonacci sequence, where the &lt;span class=&#34;math inline&#34;&gt;\(n^{\rm th}\)&lt;/span&gt; value is given by the sum of the
two previous values. As a function, this can be written as&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;λ&amp;gt; fib 0 = 0
λ&amp;gt; fib 1 = 1
λ&amp;gt; fib n = fib (n-1) + fib (n-2)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Essentially, &lt;code&gt;fib(0)&lt;/code&gt; returns &lt;code&gt;0&lt;/code&gt;. &lt;code&gt;fib(1)&lt;/code&gt; returns &lt;code&gt;1&lt;/code&gt;, and for any value &lt;code&gt;n&lt;/code&gt; it
returns the (recursively defined) sum of the two previous values. This isn’t infinite
at all…&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[
\begin{align*}
{\rm fib}(4) &amp;amp;= {\rm fib}(3) + {\rm fib}(2)\\
&amp;amp;= ({\rm fib}(2) + {\rm fib}(1)) + ({\rm fib}(1) + {\rm fib}(0))\\
&amp;amp;= {\rm fib}(1) + {\rm fib}(0) + {\rm fib}(1) +  {\rm fib}(1) + {\rm fib}(0)\\
&amp;amp;= 1 + 0 + 1 + 1 + 0\\
&amp;amp;= 3
\end{align*}
\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We could write that in R as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fib &amp;lt;- function(n) {
  if (n == 0) return(0)
  if (n == 1) return(1)
  fib(n - 1) + fib(n - 2)
}

fib(4)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fib(8)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 21&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This may come as a surprise to some - the function is defined &lt;em&gt;in terms of itself&lt;/em&gt; and
some base cases. This is entirely fine in R and Haskell as they’re lazily evaluated -
nothing happens until a value is actually used. In R, this means that if an argument
to a function isn’t used, it’s not evaluated at all&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;loud_func &amp;lt;- function() {
  cat(&amp;quot;HELLLOOOOO!!!\n&amp;quot;)
}

stays_quiet &amp;lt;- function(f, g = loud_func()) {
  f(c(1, 2, 3, 4))
}

stays_quiet(f = mean)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2.5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that although the argument &lt;code&gt;g&lt;/code&gt; is the &lt;em&gt;invocation&lt;/em&gt; of &lt;code&gt;loud_func()&lt;/code&gt;, it’s never
evaluated because we don’t use it. If we did use it…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;noisy &amp;lt;- function(f, g = loud_func()) {
  g
  f(c(1, 2, 3, 4))
}

noisy(sum)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## HELLLOOOOO!!!&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, in these languages, we can define a function recursively. Given the base case(s),
these will eventually return just a number, so the computation will complete.&lt;/p&gt;
&lt;p&gt;Instead of just adding the values together, we can create a sequence of values by
concatenating the iterations together. Starting with data and working down to a base
case is called “recursion”, while starting from a base case and building up a data
structure is “corecursion”.&lt;/p&gt;
&lt;p&gt;If we want a sequence of values that represents the Fibonacci numbers, we can use&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fibs &amp;lt;- function(n) {
  if (n == 0) return(0)
  if (n == 1) return(1)
  prev &amp;lt;- fibs(n - 1)
  c(prev, sum(tail(prev, 2)))
}

fibs(10)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1]  1  1  2  3  5  8 13 21 34 55&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What’s blown my mind recently is the concept of &lt;em&gt;infinite&lt;/em&gt; data structures. If I
defined some function that, instead of working &lt;em&gt;down&lt;/em&gt; to a base case, just kept
expanding, say, by concatenating with a &lt;em&gt;larger&lt;/em&gt; number (corecursion), such as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;inf_series &amp;lt;- function(x) {
  c(x, inf_series(x + 1))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, if I tried to evaluate &lt;code&gt;inf_series(5)&lt;/code&gt; this would produce&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;c(5, inf_series(6))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which would expand to&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;c(5, 6, inf_series(7))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and so on… forever. Of course, R can’t keep going forever&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;inf_series(5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-danger&#34;&gt;&lt;code&gt;Error: C stack usage  7971732 is too close to the limit&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This error comes about because each function in R is a “closure” which “encloses”
its environment. The way R keeps track of that (and where it needs to return after
returning from a function) is by adding “stack frames” each time it dives deeper
into a function calling a function. We’ve asked it to add infinity of these, so
at some point it says “too many”.&lt;/p&gt;
&lt;p&gt;Okay, so, not possible, right?&lt;/p&gt;
&lt;p&gt;In Haskell I can define&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;λ&amp;gt; fibs = 0 : scanl (+) 1 fibs&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is a concatenation (&lt;code&gt;:&lt;/code&gt;) of &lt;code&gt;0&lt;/code&gt; with the result of &lt;code&gt;scanl (+) 1 fibs&lt;/code&gt;. Note carefully,
this &lt;em&gt;isn’t&lt;/em&gt; a function - it’s a vector of values defined recursively 🤯&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/mindblown.gif&#34; alt=&#34;Mind = blown&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Mind = blown&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To explain the definition a little more: &lt;a href=&#34;https://hackage.haskell.org/package/base-4.18.0.0/docs/Prelude.html#v:scanl&#34;&gt;&lt;code&gt;scanl&lt;/code&gt;&lt;/a&gt; is similar to &lt;code&gt;reduce&lt;/code&gt; in that it takes a starting value, a vector, and a
binary operator, but rather than reducing the vector to a value, it creates a new
vector with the successively reduced values. In this example, the values &lt;code&gt;1..5&lt;/code&gt; are
successively added (&lt;code&gt;+&lt;/code&gt;) to &lt;code&gt;0&lt;/code&gt;, so the second entry is &lt;code&gt;0+1=1&lt;/code&gt;, the next is &lt;code&gt;1+2=3&lt;/code&gt;, the
next is &lt;code&gt;3+3=6&lt;/code&gt;, then &lt;code&gt;6+4=10&lt;/code&gt;, then &lt;code&gt;10+5=15&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;λ&amp;gt; scanl (+) 0 [1..5]
[0,1,3,6,10,15]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the Fibonacci case, the operator is still addition, but the starting value is &lt;code&gt;1&lt;/code&gt;
and the vector is … the entire vector we’re defining. Writing out some of the
terms makes this easier to understand&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;λ&amp;gt; scanl (+) 1 [0, 1, 1, 2, 3, 5, 8]
[1,1,2,3,5,8,13,21]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first terms in the sequence, after concatenating with &lt;code&gt;0&lt;/code&gt; will be&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;λ&amp;gt; [0, 1, 1, 2, 3, 5, 8]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so, by defining &lt;code&gt;fibs&lt;/code&gt; in &lt;em&gt;terms of&lt;/em&gt; &lt;code&gt;fibs&lt;/code&gt;, the sequence can go on forever. So,
what if you try to print this? In &lt;code&gt;GHCI&lt;/code&gt;, the output will just stream forever, which
isn’t particularly useful. Instead, we can ask for some number of values, say, ten&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;λ&amp;gt; take 10 fibs
[0,1,1,2,3,5,8,13,21,34]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Due to the laziness of Haskell, nothing is computed until it’s needed, so asking
for any number of values is fast, despite the list being “infinite”&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;λ&amp;gt; take 100 fibs
[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,
 17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,
 3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,
 165580141,267914296,433494437,701408733,1134903170,1836311903,2971215073,
 4807526976,7778742049,12586269025,20365011074,32951280099,53316291173,
 86267571272,139583862445,225851433717,365435296162,591286729879,956722026041,
 1548008755920,2504730781961,4052739537881,6557470319842,10610209857723,
 17167680177565,27777890035288,44945570212853,72723460248141,117669030460994,
 190392490709135,308061521170129,498454011879264,806515533049393,
 1304969544928657,2111485077978050,3416454622906707,5527939700884757,
 8944394323791464,14472334024676221,23416728348467685,37889062373143906,
 61305790721611591,99194853094755497,160500643816367088,259695496911122585,
 420196140727489673,679891637638612258,1100087778366101931,1779979416004714189,
 2880067194370816120,4660046610375530309,7540113804746346429,12200160415121876738,
 19740274219868223167,31940434634990099905,51680708854858323072,
 83621143489848422977,135301852344706746049,218922995834555169026]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The idea of taking some values from an iterator shows up in other languages.&lt;/p&gt;
&lt;p&gt;In Rust, I can create an infinite iterator of the value &lt;code&gt;1&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;use std::iter;
let ones = iter::repeat(1);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and I can take some number of these, say, five, collected into a vector&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;ones.take(5).collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[1, 1, 1, 1, 1]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Python also has a notion of infinite sequences, and they’re likely even more common.&lt;/p&gt;
&lt;p&gt;When you work with a (regular, finite) list of values in a range, you get a &lt;code&gt;range&lt;/code&gt; object&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;numbers = range(1, 9)
numbers&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## range(1, 9)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;type(numbers)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;lt;class &amp;#39;range&amp;#39;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can convert this to a regular list with&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;list(numbers)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1, 2, 3, 4, 5, 6, 7, 8]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;type(list(numbers))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;lt;class &amp;#39;list&amp;#39;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you &lt;code&gt;filter&lt;/code&gt; the numbers (which works on a &lt;code&gt;range&lt;/code&gt; or a &lt;code&gt;list&lt;/code&gt;) you get a &lt;code&gt;filter&lt;/code&gt; object&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;even_numbers = filter(lambda x: x % 2 == 0, numbers)
even_numbers&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;lt;filter object at 0x7f5ac61da470&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;type(even_numbers)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;lt;class &amp;#39;filter&amp;#39;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which you can also convert to a list to see the values&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;list(even_numbers)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [2, 4, 6, 8]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But, you can use this as an &lt;em&gt;iterable&lt;/em&gt;, so you can get the ‘next’ value as
many times as you need (defined here again to restart the iterator)&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;even_numbers = filter(lambda x: x % 2 == 0, numbers)
next(even_numbers)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;next(even_numbers)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;next(even_numbers)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 6&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;next(even_numbers)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;until there’s none left&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;next(even_numbers)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in py_call_impl(callable, dots$args, dots$keywords): StopIteration&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As before, you can convert these to a fixed-length list, if desired&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;list(filter(lambda x: x % 2 == 0, numbers))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [2, 4, 6, 8]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Still with me? Great. We can create an &lt;em&gt;infinite&lt;/em&gt; list, if we want to, because
it isn’t evaluated until we ask for elements&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;def infinitenumbers():
    count = 0
    while True:
        yield count
        count += 1

nums = infinitenumbers()        

nums&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;lt;generator object infinitenumbers at 0x7f5ac615d310&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;type(nums)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;lt;class &amp;#39;generator&amp;#39;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a &lt;em&gt;generator&lt;/em&gt; which means it’s capable of generating values. We can ask
for as many as we want, now&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;next(nums)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 0&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;next(nums)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;next(nums)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;next(nums)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;next(nums)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we want to convert some number of these to a list, we need a new function, roughly
the equivalent of Haskell’s &lt;code&gt;take&lt;/code&gt;, in order to extract these&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;from itertools import islice

nums = infinitenumbers()        

list(islice(nums, 10))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and as before, if we ask for more &lt;em&gt;now&lt;/em&gt;, we get the next batch&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;list(islice(nums, 10))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, can we do this at all in R? We can’t build an infinite data structure &lt;em&gt;per se&lt;/em&gt;,
but what if we use a recursive definition and just… stop when it’s recursed enough
times?&lt;/p&gt;
&lt;p&gt;I initially thought about hacking into functions with &lt;code&gt;body()&lt;/code&gt; to keep track of this,
but we’ve already discussed something we can use - the stack frames! R keeps track of
how deep it’s recursed using these, and we can access that information with &lt;code&gt;sys.calls()&lt;/code&gt;,
the help for which describes&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.GlobalEnv is given number 0 in the list of frames. Each subsequent function evaluation increases the frame stack by 1.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, we can tell from inside a recursive function how deeply nested we currently are.&lt;/p&gt;
&lt;p&gt;I wrote the following helper, named for the Haskell inspiration&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;take &amp;lt;- function(f, n, x = 1) {
  current_depth &amp;lt;- length(sys.calls())  # Subtract 1 to exclude the current call,
                                        # but add 1 to start at 1
  
  # uncomment this line to watch the magic happen!
  # cat(&amp;quot;Current Stack Depth: &amp;quot;, current_depth, &amp;quot;\n&amp;quot;)
 
  if (current_depth &amp;gt;= n) {
    return(f(x))
  } else {
    return(c(f(x), take(f, n, x + 1)))
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;this checks &lt;code&gt;length(sys.calls())&lt;/code&gt; which starts at 1 the first time it’s called, and adds
1 every time we go deeper. So long as we haven’t reached the requested depth, it
combines the passed-in function evaluated at &lt;span class=&#34;math inline&#34;&gt;\(x + i\)&lt;/span&gt; with a new evaluation one level deeper.&lt;/p&gt;
&lt;p&gt;When that reaches the requested depth, it returns the evaluated function, bubbling up the
returned values so that we end up with a vector of &lt;span class=&#34;math inline&#34;&gt;\(n\)&lt;/span&gt; values&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[
[f(x), f(x+1), f(x+2), f(x+3), \dots, f(x+n-1)]
\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Neat idea, but does it work? We can’t pass in an actual infinite data structure,
but we &lt;em&gt;can&lt;/em&gt; pass a function that defines one&lt;/p&gt;
&lt;p&gt;A (trivial) function that produces a number at each value of &lt;code&gt;x&lt;/code&gt; is&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;numbers &amp;lt;- function(x) {
  x
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we pretend that’s a generator for every number, we can “take” some values from it&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;take(numbers, 5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt; [1] 1 2 3 4 5&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;take(numbers, 10)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt; [1]  1  2  3  4  5  6  7  8  9 10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A more complicated recipe for an infinite list of numbers could be&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;g &amp;lt;- function(x) {
  x + 1
}

take(g, 7)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[1] 2 3 4 5 6 7 8&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;take(g, 10)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt; [1]  2  3  4  5  6  7  8  9 10 11&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dealing with non-sequential numbers might be trickier… what if we want all the even
numbers?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;evens &amp;lt;- function(x) {
  if(x %% 2 == 0) x else NULL
}

take(evens, 10)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt; [1]  2  4  6  8 10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No, that only checks the first 10 numbers. Instead,&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;evens &amp;lt;- function(x) {
  x * 2
}

take(evens, 7)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt; [1]  2  4  6  8 10 12 14&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;take(evens, 10)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt; [1]  2  4  6  8 10 12 14 16 18 20&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What about our original example?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fibs &amp;lt;- function(x) {
  if (x == 0) return(0)
  if (x == 1) return(1)
  fibs(x - 1) + fibs(x - 2)
}

# 10 values, starting at 0
take(fibs, 10, x = 0)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt; [1]  0  1  1  2  3  5  8 13 21 34&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# 10 values, starting at 1
take(fibs, 10, x = 1)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt; [1]  1  1  2  3  5  8 13 21 34 55&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, if we want 12 values, starting at the 10th&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;take(fibs, 12, x = 10)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt; [1]    55    89   144   233   377   610   987  1597  2584  4181  6765 10946&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/glasses_recursion.gif&#34; alt=&#34;It… works!&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;It… works!&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I’d say that’s working quite nicely!!!&lt;/p&gt;
&lt;p&gt;Some caveats to keep in mind, though…&lt;/p&gt;
&lt;p&gt;Since we’re relying on a count of stack frames on top of &lt;code&gt;.GlobalEnv&lt;/code&gt;, this &lt;code&gt;take()&lt;/code&gt;
implementation won’t work nicely inside another function. In fact, since
{knitr} is already a few functions deep, it also doesn’t work in an Rmd file (including
this blog which is Rmd via {blogdown}). Not for use in production, but a fun
exercise to figure it out at all.&lt;/p&gt;
&lt;p&gt;Is there a better way to achieve this &lt;code&gt;take()&lt;/code&gt; functionality? Where do you use
infinite iterators/generators in R or another language? Spot an improvement that
I can make? I can be found on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; or
use the comments below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-08-18
##  pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.17    2023-05-16 [1] CRAN (R 4.1.2)
##  bookdown      0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  bslib         0.5.0   2023-06-09 [3] CRAN (R 4.3.1)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [3] CRAN (R 4.2.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest        0.6.33  2023-07-07 [3] CRAN (R 4.3.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.21    2023-05-05 [3] CRAN (R 4.3.0)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  here          1.0.1   2020-12-13 [1] CRAN (R 4.1.2)
##  htmltools     0.5.6   2023-08-10 [3] CRAN (R 4.3.1)
##  htmlwidgets   1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv        1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.7   2023-06-29 [3] CRAN (R 4.3.1)
##  knitr         1.43    2023-05-25 [3] CRAN (R 4.3.0)
##  later         1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lattice       0.21-8  2023-04-05 [4] CRAN (R 4.3.0)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  Matrix        1.6-0   2023-07-08 [4] CRAN (R 4.3.1)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  pkgbuild      1.4.0   2022-11-27 [1] CRAN (R 4.1.2)
##  pkgload       1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  png           0.1-7   2013-12-03 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.8.2   2023-06-30 [3] CRAN (R 4.3.1)
##  profvis       0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises      1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps            1.7.5   2023-04-18 [3] CRAN (R 4.3.0)
##  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  reticulate    1.26    2022-08-31 [1] CRAN (R 4.1.2)
##  rlang         1.1.1   2023-04-28 [1] CRAN (R 4.1.2)
##  rmarkdown     2.23    2023-07-01 [3] CRAN (R 4.3.1)
##  rprojroot     2.0.3   2022-04-02 [1] CRAN (R 4.1.2)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.7   2023-07-15 [3] CRAN (R 4.3.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny         1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi       1.7.12  2023-01-11 [3] CRAN (R 4.2.2)
##  stringr       1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis       2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  vctrs         0.6.3   2023-06-14 [1] CRAN (R 4.1.2)
##  xfun          0.40    2023-08-09 [3] CRAN (R 4.3.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml          2.3.7   2023-01-23 [3] CRAN (R 4.2.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ─ Python configuration ───────────────────────────────────────────────────────
##  python:         /usr/bin/python3
##  libpython:      /usr/lib/python3.10/config-3.10-x86_64-linux-gnu/libpython3.10.so
##  pythonhome:     //usr://usr
##  version:        3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0]
##  numpy:          /home/jono/.local/lib/python3.10/site-packages/numpy
##  numpy_version:  1.24.1
##  
##  NOTE: Python version was forced by RETICULATE_PYTHON_FALLBACK
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Pythagorean Triples with Comprehensions</title>
      <link>https://jcarroll.com.au/2023/08/13/pythagorean-triples-with-comprehensions/</link>
      <pubDate>Sun, 13 Aug 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/08/13/pythagorean-triples-with-comprehensions/</guid>
      <description>&lt;p&gt;I’ve been learning at least one new programming language per month through &lt;a href=&#34;https://exercism.org&#34;&gt;Exercism&lt;/a&gt; and the #12in23 challenge. I’ve keep saying,
every time you learn a new language, you learn something about all the others
you know. Plus, once you know &lt;span class=&#34;math inline&#34;&gt;\(N\)&lt;/span&gt; languages, the &lt;span class=&#34;math inline&#34;&gt;\(N+1^{\rm th}\)&lt;/span&gt; is significantly easier. This
post covers a calculation I came across in Haskell, and how I can now do the same
in a lot of other languages - and perhaps can’t as easily in others.&lt;/p&gt;
&lt;p&gt;All of the languages here, I’m learning via Exercism, or at least I’m completing
a handful or more exercises in each of the languages, which means learning enough
of the syntax to be able to complete those. The #12in23 challenge is to
try 12 languages in 2023… I’m doing just fine so far&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/12in23_12.png&#34; alt=&#34;#12in23 progress as of July 2023 - I already have my 12, but no reason to stop now&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;#12in23 progress as of July 2023 - I already have my 12, but no reason to stop now&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;haskell&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Haskell&lt;/h3&gt;
&lt;p&gt;I’ve been reading the (great!) online version of &lt;a href=&#34;http://learnyouahaskell.com/&#34;&gt;Learn You a Haskell for Great Good!&lt;/a&gt; - Haskell is a (properly) “pure” functional
language, part of which means it has &lt;strong&gt;no&lt;/strong&gt; side-effects, which includes, say,
printing to the console. Haskell, of course, has a way around this (monads!) but
it means there’s a lot to get through before you even get to a printing “Hello, World!”
example. It’s also &lt;em&gt;lazy&lt;/em&gt; which means it doesn’t evaluate something if it doesn’t
need to, which makes for some good performance, sometimes.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/pUN3algpvMs&#34;&gt;This video&lt;/a&gt; does a really nice job explaining the
principles of pure functional programming using JavaScript to introduce Haskell,
building recursive functions that only take a single argument and return a
single value.&lt;/p&gt;
&lt;p&gt;One example that caught my eye in the &lt;a href=&#34;http://learnyouahaskell.com/starting-out#im-a-list-comprehension&#34;&gt;list comprehensions section&lt;/a&gt; was this&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;ghci&amp;gt; let rightTriangles&amp;#39; = [ (a,b,c) | c &amp;lt;- [1..10], b &amp;lt;- [1..c], a &amp;lt;- [1..b], a^2 + b^2 == c^2, a+b+c == 24]  
ghci&amp;gt; rightTriangles&amp;#39;  
[(6,8,10)]  &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This perhaps isn’t too hard to read, even for those unfamiliar with the language. &lt;code&gt;ghci&lt;/code&gt; is
the interactive REPL for the Glasgow Haskell Compiler, so the prompt starts with that.
Haskell uses a &lt;code&gt;let&lt;/code&gt; binding to identify variables, and the apostrophe just indicates that
this is a slightly different version compared to the one defined slightly earlier in the chapter.&lt;/p&gt;
&lt;p&gt;The list comprehension itself is perhaps not so dissimilar to one you’d find in Python; it
defines some tuple &lt;code&gt;(a, b, c)&lt;/code&gt; and &lt;code&gt;|&lt;/code&gt; identifies some constraints, namely that &lt;code&gt;c&lt;/code&gt; is taken
from a range of 1 to 10, &lt;code&gt;b&lt;/code&gt; is taken from a range of 1 to &lt;code&gt;c&lt;/code&gt;, and &lt;code&gt;a&lt;/code&gt; is taken from
a range of 1 to &lt;code&gt;b&lt;/code&gt;, along with the criteria that &lt;span class=&#34;math inline&#34;&gt;\(a^2 + b^2 = c^2\)&lt;/span&gt; (the numbers form a Pythagorean
triple) and their sum is 24. I discussed the &lt;a href=&#34;https://en.wikipedia.org/wiki/Pythagorean_triple&#34;&gt;Pythagorean triples&lt;/a&gt; in my &lt;a href=&#34;https://jcarroll.com.au/2023/08/11/wrapping-c-code-in-an-r-package/&#34;&gt;last post&lt;/a&gt; - no
coincidence (/s). If you evaluate this line, you more-or-less immediately get back the result&lt;/p&gt;
&lt;pre class=&#34;haskell bg-success&#34;&gt;&lt;code&gt;[(6,8,10)]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is a Pythagorean triple&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[6^2 + 8^2 = 36 + 64 = 100 = 10^2\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;for which&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[a + b + c = 6 + 8 + 10 = 24\]&lt;/span&gt;
This isn’t a groundbreaking calculation, but I’ve done a &lt;em&gt;lot&lt;/em&gt; of R, and my mind
was a little blown that such a calculation could really be done in a single line just
by specifying those constraints. Not a solver, not a grid of values with a filter, just
specifying constraints.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;r&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;R&lt;/h3&gt;
&lt;p&gt;Anyone who knows me knows I write a lot of R. I wrote &lt;a href=&#34;https://beyondspreadsheetswithr.com/&#34;&gt;a book&lt;/a&gt; on it. I solved all of the
&lt;a href=&#34;https://adventofcode.com/&#34;&gt;Advent of Code&lt;/a&gt; 2022 puzzles in &lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/tree/main/2022/R&#34;&gt;&lt;em&gt;strictly base&lt;/em&gt; R&lt;/a&gt; (I really need to write that post).&lt;/p&gt;
&lt;p&gt;Now, R (unfortunately) doesn’t have any comprehensions, list or otherwise, so I started to
wonder how I would do this in R. The best I can come up with is&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;expand.grid(a=1:10, b=1:10, c=1:10) |&amp;gt;
  dplyr::filter(a^2 + b^2 == c^2 &amp;amp; 
                  a + b + c == 24 &amp;amp; 
                  a &amp;lt; b &amp;amp; 
                  b &amp;lt; c)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   a b  c
## 1 6 8 10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but that involves explicitly creating &lt;em&gt;all&lt;/em&gt; 1000 combinations of &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, and &lt;code&gt;c&lt;/code&gt;. There
may be a multi-step way to limit the grid to &lt;span class=&#34;math inline&#34;&gt;\(a &amp;lt; b\)&lt;/span&gt; and &lt;span class=&#34;math inline&#34;&gt;\(b &amp;lt; c\)&lt;/span&gt; but that’s more code. Maybe the
Haskell solution also has to generate these behind the scenes, but it isn’t up to the user to
do that, so it feels nicer. I like the &lt;code&gt;filter()&lt;/code&gt; verb here - technically the &lt;code&gt;&amp;amp;&lt;/code&gt; joining is
redundant and I could have passed each condition as its own argument. &lt;code&gt;expand.grid()&lt;/code&gt; is one
of those underutilised functions that comes in very handy sometimes - or its cousin
&lt;code&gt;tidyr::crossing()&lt;/code&gt; which wraps this and additionally performs de-duplication and sorting.&lt;/p&gt;
&lt;p&gt;Now that I know more languages, I felt I could explore this a bit further!&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;python&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Python&lt;/h3&gt;
&lt;p&gt;In Python, which I feel is well-known for list comprehensions, this translates more
or less 1:1 to&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;[(a,b,c) for c in range(1,11) for b in range(1,c) for a in range(1,b) if ((a**2 + b**2) == c**2) if a+b+c==24]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;python bg-success&#34;&gt;&lt;code&gt;[(6, 8, 10)]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, ranges are specified differently, but otherwise this follows the Haskell
solution quite nicely, including the dynamic ranges of &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;a&lt;/code&gt; which avoids needing
to search the entire &lt;code&gt;10*10*10&lt;/code&gt; space.&lt;/p&gt;
&lt;p&gt;I appreciate there’s a silly language war between Python and R but
honestly, a lot of stuff is written in Python and a lot of people write in Python.
I figure it’s better to understand that language for when I need it than to stick my
head in the sand and claim some sort of superiority. There’s bits I don’t like, sure,
but that doesn’t mean I shouldn’t learn it. I’m even registered and attending &lt;a href=&#34;https://2023.pycon.org.au/&#34;&gt;PyConAU&lt;/a&gt; next
weekend.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;rust&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Rust&lt;/h3&gt;
&lt;p&gt;Rust is a fun language with easily the most helpful compiler ever made - you can make a
lot of mistakes, but the error messages and hints are unparalleled. I’m currently
taking &lt;a href=&#34;https://fosstodon.org/@timClicks@mastodon.nz&#34;&gt;Tim McNamara’s&lt;/a&gt; &lt;a href=&#34;https://learning.accelerant.dev/view/courses/how-to-learn-rust/&#34;&gt;‘How To Learn Rust’&lt;/a&gt; course which has a
lot of practical lessons and I’ve built some &lt;a href=&#34;https://github.com/jonocarroll/rps.rs&#34;&gt;fun things&lt;/a&gt; already. I completed the first 13 &lt;a href=&#34;https://adventofcode.com/&#34;&gt;Advent of Code&lt;/a&gt; 2022 &lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/tree/main/2022/Rust&#34;&gt;puzzles in Rust&lt;/a&gt;, after which it all
got a bit too complicated (and I do &lt;em&gt;really&lt;/em&gt; need to write that post).&lt;/p&gt;
&lt;p&gt;Rust doesn’t have list comprehensions (I believe there are cargo crates which &lt;em&gt;do&lt;/em&gt; add
such functionality) so it’s back to nested loops&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;for c in 1..=10 {
  for b in 1..=c {
    for a in 1..=b {
      if a*a + b*b == c*c &amp;amp;&amp;amp; a+b+c == 24 {
        println!(&amp;quot;{}, {}, {}&amp;quot;, a, b, c);
      }
    }
  }
};&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bash bg-success&#34;&gt;&lt;code&gt;6, 8, 10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That doesn’t allocate a result at all, it just prints the values when it
encounters them, and since the loop is nested, it can limit the search to &lt;span class=&#34;math inline&#34;&gt;\(b \leq c\)&lt;/span&gt; and
&lt;span class=&#34;math inline&#34;&gt;\(a \leq b\)&lt;/span&gt;, but it &lt;em&gt;does&lt;/em&gt; explicitly run the loop across all those combinations. It’s
possible there’s a much better way to do this, but I couldn’t think of it.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;common-lisp&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Common Lisp&lt;/h3&gt;
&lt;p&gt;I like the idea of Common Lisp, and I’m making my way through &lt;a href=&#34;https://gigamonkeys.com/book/&#34;&gt;Practical Common Lisp&lt;/a&gt; slowly. I suspect I enjoy some of the descendants
like Clojure a bit more, but it’s absolutely worth learning. Miles McBain has &lt;a href=&#34;https://www.milesmcbain.com/posts/the-roots-of-quotation/&#34;&gt;a great post&lt;/a&gt;
about how learning about lisp quoting helps understand more of the tidyverse. I have used
lisp in &lt;a href=&#34;https://jcarroll.com.au/2022/04/02/codegolf-lisp-edition/&#34;&gt;a code-golf post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lisp doesn’t have comprehensions so it relies on loops, and again, just prints the
result, returning &lt;code&gt;NIL&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;lein&#34;&gt;&lt;code&gt;  (loop for c from 1 to 10
        do (loop for b from 1 to c
                 do (loop for a from 1 to b
                      do (when (and (= (+ a b c) 24) (= (+ (* a a) (* b b)) (* c c)))
                        (format t &amp;quot;~d, ~d, ~d~%&amp;quot; a b c)))))
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;lein bg-success&#34;&gt;&lt;code&gt;6, 8, 10
NIL&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The loop is still constrained to &lt;span class=&#34;math inline&#34;&gt;\(b \leq c\)&lt;/span&gt; and &lt;span class=&#34;math inline&#34;&gt;\(a \leq b\)&lt;/span&gt;, but definitely runs
through all those values.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;julia&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Julia&lt;/h3&gt;
&lt;p&gt;I really want to learn more Julia, but I’m not entirely new to the language. I have completed
the first 25 &lt;a href=&#34;https://projecteuler.net/&#34;&gt;Project Euler&lt;/a&gt; problems in &lt;a href=&#34;https://github.com/jonocarroll/ProjectEuler_Julia&#34;&gt;Julia&lt;/a&gt; (by
no means optimised solutions). I think what’s holding me back is the fact that almost
every presentation using it is so very mathsy - and I’m a physicist by training. I love
that the tidyverse is making its way over in the forms of &lt;a href=&#34;https://www.queryverse.org/&#34;&gt;Queryverse&lt;/a&gt;,
&lt;a href=&#34;https://juliadata.github.io/DataFramesMeta.jl/stable/&#34;&gt;DataFramesMeta&lt;/a&gt;, and more recently (and
most likely with more success) the &lt;a href=&#34;https://github.com/TidierOrg/Tidier.jl&#34;&gt;Tidier&lt;/a&gt; family.&lt;/p&gt;
&lt;p&gt;Julia &lt;em&gt;does&lt;/em&gt; have list comprehensions, and additionally has an “element” operator with
the mathematically-familiar symbol &lt;code&gt;∈&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;[(a,b,c) for c ∈ 1:10, b ∈ 1:10, a ∈ 1:10 if (a^2 + b^2 == c^2) &amp;amp;&amp;amp; (a+b+c == 24) &amp;amp;&amp;amp; b &amp;lt;= c &amp;amp;&amp;amp; a &amp;lt;= b]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia bg-success&#34;&gt;&lt;code&gt;1-element Vector{Tuple{Int64, Int64, Int64}}:
 (6, 8, 10)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, the choices for &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;a&lt;/code&gt; still need to run through all 10 values because
Julia doesn’t allow these to be co-defined like Haskell and Python do. I came to Julia from
mainly only knowing R, so dealing with an output of type &lt;code&gt;Vector{Tuple{Int64, Int64, Int64}}&lt;/code&gt;
initially proved to be a challenge, but I’d say learning more Rust has made me feel a lot more
comfortable around working with types.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;clojure&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Clojure&lt;/h3&gt;
&lt;p&gt;Clojure feels to me like “lisp, but with good libraries”. There’s definitely syntax
differences, but most of them feel like improvements.&lt;/p&gt;
&lt;pre class=&#34;lein&#34;&gt;&lt;code&gt;(for [c (range 11)
      b (range c)
      a (range b)
     :when (and (== (+ (* a a) (* b b)) (* c c)) (== (+ a b c) 24))]
[a b c])&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;lein bg-success&#34;&gt;&lt;code&gt;([6 8 10])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This still feels like a comprehension, but the syntax is certainly a bit more
convoluted. Bonus points for the dynamic ranges of &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;a&lt;/code&gt;. Still, a long way
off of completely unreadable, I’d say.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;scala&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Scala&lt;/h3&gt;
&lt;p&gt;I’m learning a lot of functional programming, and I think I’m happy that some of the
&lt;a href=&#34;https://www.manning.com/books/functional-programming-in-scala-second-edition&#34;&gt;textbooks&lt;/a&gt; use Scala rather than some alternatives. I’m still very new to this language,
but so far I think I like it.&lt;/p&gt;
&lt;p&gt;Again, we’re back to a loop, but most of it is straightforward assignments and we
get the dynamic ranges of &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;a&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;scala&#34;&gt;&lt;code&gt;for {
     c &amp;lt;- 1 until 11
     b &amp;lt;- 1 until c
     a &amp;lt;- 1 until b
     if a * a + b * b == c * c &amp;amp; a + b + c == 24
     } {
        println(s&amp;quot;Side lengths: $a, $b, $c&amp;quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;scala bg-success&#34;&gt;&lt;code&gt;Side lengths: 6, 8, 10&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;c&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;C&lt;/h3&gt;
&lt;p&gt;I mentioned that I performed this calculation in C in &lt;a href=&#34;https://jcarroll.com.au/2023/08/11/wrapping-c-code-in-an-r-package/&#34;&gt;my last post&lt;/a&gt; - that
ends up being just a loop&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;int a, b, c

printf(&amp;quot;%4s\t%4s\t%4s\t%4s\n&amp;quot;, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;);
printf(&amp;quot;   -------------------------\n&amp;quot;);
for (c = 1; c &amp;lt;= 24; c++) 
  for (b = 1; b &amp;lt;= c; b++)
    for (a = 1; a &amp;lt;= b; a++)
      if ( ( pow ( a, 2 ) + pow ( b, 2 ) ) == pow ( c, 2 ) ) {
        printf(&amp;quot;%4i\t%4i\t%4i\t%4i\n&amp;quot;, a, b, c);
      }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I haven’t run the output directly, since it needs an entire program supporting it, but
it’s the right answer.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;So, what does it look like if you run all of these together? I’ve been getting back
into using &lt;a href=&#34;https://github.com/tmux/tmux/wiki&#34;&gt;tmux&lt;/a&gt; and it’s very powerful. One of the
features is splitting a window into panes, so I did that - one for each of these
languages!&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/polyglot_triangles.png&#34; alt=&#34;Calculating the Pythagorean Triple with perimeter 24 in several languages at once - link&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Calculating the Pythagorean Triple with perimeter 24 in several languages at once - &lt;a href=&#34;https://raw.githubusercontent.com/jonocarroll/jcarroll.com.au/master/content/post/2023-08-13-pythagorean-triples-with-comprehensions/images/polyglot_triangles.png&#34;&gt;link&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I still think the Haskell solution shines above all the rest. It has all of the
simplicity and language richness with none of the boilerplate. I like that it’s
&lt;a href=&#34;https://en.wikipedia.org/wiki/Declarative_programming&#34;&gt;declarative&lt;/a&gt; (“get an answer to this”)
rather than &lt;a href=&#34;https://en.wikipedia.org/wiki/Imperative_programming&#34;&gt;imperative&lt;/a&gt; (“do this, then that, then loop here…”). Comparing all of these, it’s clear there’s no guarantees about
being able to define the dynamic iteration ranges so another win for Haskell, there.&lt;/p&gt;
&lt;p&gt;Following my last post, &lt;a href=&#34;https://fosstodon.org/@Kazinator@mstdn.ca&#34;&gt;@Kazinator&lt;/a&gt; mentioned to me
that the “TXR Lisp code, calling calcsum directly via FFI using Lisp nested arrays” could
be written as&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;$ cat calcsum.tl
(typedef arr3d (ptr (array (ptr (array (ptr (array int)))))))

(with-dyn-lib &amp;quot;./calcsum.so&amp;quot;
  (deffi calcsum &amp;quot;calcsum&amp;quot; void (int (ptr arr3d))))

(let* ((dim 16)
       (arr (vector dim)))
  (each ((a 0..dim))
    (set [arr a] (vector dim))
    (each ((b 0..dim))
      (set [[arr a] b] (vector dim 0))))
  (calcsum (pred dim) arr)
  (each-prod ((a 1..dim)
              (b 1..dim)
              (c 1..dim))
    (let ((sum [[[arr a] b] c]))
      (if (plusp sum)
        (put-line (pic &amp;quot;### + ### + ### = ####&amp;quot; a b c sum))))))

$ txr  calcsum.tl&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;lein&#34;&gt;&lt;code&gt;  3 +   4 +   5 =   12
  5 +  12 +  13 =   30
  6 +   8 +  10 =   24
  9 +  12 +  15 =   36&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This calculates &lt;em&gt;all&lt;/em&gt; the combinations up to some value (as my post did) but it’s
already clear there’s some cool features there.&lt;/p&gt;
&lt;p&gt;How does your favourite language calculate the Pythagorean triple with a sum of 24? What can
I do better in the solution I have above for a language you know? I can be found on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; or use the comments below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-08-13
##  pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.17    2023-05-16 [1] CRAN (R 4.1.2)
##  bookdown      0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  bslib         0.5.0   2023-06-09 [3] CRAN (R 4.3.1)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [3] CRAN (R 4.2.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest        0.6.33  2023-07-07 [3] CRAN (R 4.3.1)
##  dplyr         1.1.2   2023-04-20 [3] CRAN (R 4.3.0)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.21    2023-05-05 [3] CRAN (R 4.3.0)
##  fansi         1.0.4   2023-01-22 [3] CRAN (R 4.2.2)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  generics      0.1.3   2022-07-05 [3] CRAN (R 4.2.1)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  htmltools     0.5.5   2023-03-23 [3] CRAN (R 4.2.3)
##  htmlwidgets   1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv        1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.7   2023-06-29 [3] CRAN (R 4.3.1)
##  JuliaCall     0.17.5  2022-09-08 [1] CRAN (R 4.1.2)
##  knitr         1.43    2023-05-25 [3] CRAN (R 4.3.0)
##  later         1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lattice       0.21-8  2023-04-05 [4] CRAN (R 4.3.0)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  Matrix        1.6-0   2023-07-08 [4] CRAN (R 4.3.1)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  pillar        1.9.0   2023-03-22 [3] CRAN (R 4.2.3)
##  pkgbuild      1.4.0   2022-11-27 [1] CRAN (R 4.1.2)
##  pkgconfig     2.0.3   2019-09-22 [3] CRAN (R 4.0.1)
##  pkgload       1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  png           0.1-7   2013-12-03 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.8.2   2023-06-30 [3] CRAN (R 4.3.1)
##  profvis       0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises      1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps            1.7.5   2023-04-18 [3] CRAN (R 4.3.0)
##  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  reticulate    1.26    2022-08-31 [1] CRAN (R 4.1.2)
##  rlang         1.1.1   2023-04-28 [1] CRAN (R 4.1.2)
##  rmarkdown     2.23    2023-07-01 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.7   2023-07-15 [3] CRAN (R 4.3.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny         1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi       1.7.12  2023-01-11 [3] CRAN (R 4.2.2)
##  stringr       1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  tibble        3.2.1   2023-03-20 [3] CRAN (R 4.3.1)
##  tidyselect    1.2.0   2022-10-10 [3] CRAN (R 4.2.1)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis       2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  utf8          1.2.3   2023-01-31 [3] CRAN (R 4.2.2)
##  vctrs         0.6.3   2023-06-14 [1] CRAN (R 4.1.2)
##  xfun          0.39    2023-04-20 [3] CRAN (R 4.3.0)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml          2.3.7   2023-01-23 [3] CRAN (R 4.2.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Wrapping C Code in an R Package</title>
      <link>https://jcarroll.com.au/2023/08/11/wrapping-c-code-in-an-r-package/</link>
      <pubDate>Fri, 11 Aug 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/08/11/wrapping-c-code-in-an-r-package/</guid>
      <description>&lt;p&gt;Your collaborator says to you “I have some code I’d like to distribute to people who
will probably work in R most of the time. I don’t write R, but I write C. Can you package
this up for me?” so you have a few options: re-write the code in R, package up the C code
and make it &lt;em&gt;available&lt;/em&gt; in R, or say no. I decided to try out the second of these, and this
post details how I achieved that.&lt;/p&gt;
&lt;p&gt;Before we even start, &lt;a href=&#34;https://blog.davisvaughan.com/posts/2019-03-02-now-you-c-me/&#34;&gt;this&lt;/a&gt; is an
excellent post summarising many of the finer points involved here - go read that! Then,
read some of &lt;a href=&#34;https://github.com/coolbutuseless&#34;&gt;@coolbutuseless’&lt;/a&gt; &lt;a href=&#34;https://github.com/coolbutuseless/simplecall&#34;&gt;various&lt;/a&gt; repositories &lt;a href=&#34;https://github.com/coolbutuseless/callme&#34;&gt;demonstrating&lt;/a&gt; how to wrap C code into R packages. These,
and many others, go much deeper into how to achieve this, but I’m going to detail what
I did because a) I’ll want to remember, later; b) I had enough trouble piecing together what
I needed between these excellent posts and some older, possibly out of date posts; and c) I
&lt;em&gt;did&lt;/em&gt; build some functionality beyond what was done in those straightforward examples.&lt;/p&gt;
&lt;p&gt;Those of you who know R really well probably know that the language itself is in no small part
&lt;a href=&#34;https://github.com/wch/r-source/tree/trunk/src/main&#34;&gt;written in C&lt;/a&gt;. Many packages do the
same, usually for performance reasons. This becomes most apparent if you install a package
“from source” and see a lot of this mess fly past in your console&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gcc -I&amp;quot;/usr/share/R/include&amp;quot; -DNDEBUG -I./pkg/    -fvisibility=hidden -fpic  -g -O2 -ffile-prefix-map=/build/r-base-4A2Reg/r-base-4.1.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g  -c file1.c -o file1.o
gcc -I&amp;quot;/usr/share/R/include&amp;quot; -DNDEBUG -I./pkg/    -fvisibility=hidden -fpic  -g -O2 -ffile-prefix-map=/build/r-base-4A2Reg/r-base-4.1.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g  -c file2.c -o file2.o
gcc -I&amp;quot;/usr/share/R/include&amp;quot; -DNDEBUG -I./pkg/    -fvisibility=hidden -fpic  -g -O2 -ffile-prefix-map=/build/r-base-4A2Reg/r-base-4.1.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g  -c pkg.c -o pkg.o
gcc -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro -o pkg.so file1.o file2.o pkg.o -L/usr/lib/R/lib -lR&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Other languages are supported, including Fortran (yet to be superseded for numerical libraries),
C++, Rust, and various others. You can usually dig into the source of these if you can
track down where they come from. When debugging a function call, R is happy to step through
individual lines of R code. Try the following&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;debugonce(seq.default)
seq(5)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and step through the lines of &lt;code&gt;seq.default&lt;/code&gt; until it reaches &lt;code&gt;1L:from&lt;/code&gt; (yes, &lt;code&gt;seq(from = x)&lt;/code&gt; produces the values &lt;code&gt;1&lt;/code&gt; to &lt;code&gt;from&lt;/code&gt;… sigh) where it returns that value as&lt;/p&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;exiting from: seq.default(5)
[1] 1 2 3 4 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the function involves C code, though, R can’t step through that because it’s
compiled. One of the most common ways to hit that limitation is when a function
calls either &lt;code&gt;.Internal()&lt;/code&gt; or &lt;code&gt;.Primitive()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I went looking for a function containing one of these (there are plenty) and found &lt;code&gt;.row_names_info&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# number of rownames
.row_names_info(mtcars)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 32&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# the rownames themselves
.row_names_info(mtcars, type = 0)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] &amp;quot;Mazda RX4&amp;quot;           &amp;quot;Mazda RX4 Wag&amp;quot;       &amp;quot;Datsun 710&amp;quot;         
##  [4] &amp;quot;Hornet 4 Drive&amp;quot;      &amp;quot;Hornet Sportabout&amp;quot;   &amp;quot;Valiant&amp;quot;            
##  [7] &amp;quot;Duster 360&amp;quot;          &amp;quot;Merc 240D&amp;quot;           &amp;quot;Merc 230&amp;quot;           
## [10] &amp;quot;Merc 280&amp;quot;            &amp;quot;Merc 280C&amp;quot;           &amp;quot;Merc 450SE&amp;quot;         
## [13] &amp;quot;Merc 450SL&amp;quot;          &amp;quot;Merc 450SLC&amp;quot;         &amp;quot;Cadillac Fleetwood&amp;quot; 
## [16] &amp;quot;Lincoln Continental&amp;quot; &amp;quot;Chrysler Imperial&amp;quot;   &amp;quot;Fiat 128&amp;quot;           
## [19] &amp;quot;Honda Civic&amp;quot;         &amp;quot;Toyota Corolla&amp;quot;      &amp;quot;Toyota Corona&amp;quot;      
## [22] &amp;quot;Dodge Challenger&amp;quot;    &amp;quot;AMC Javelin&amp;quot;         &amp;quot;Camaro Z28&amp;quot;         
## [25] &amp;quot;Pontiac Firebird&amp;quot;    &amp;quot;Fiat X1-9&amp;quot;           &amp;quot;Porsche 914-2&amp;quot;      
## [28] &amp;quot;Lotus Europa&amp;quot;        &amp;quot;Ford Pantera L&amp;quot;      &amp;quot;Ferrari Dino&amp;quot;       
## [31] &amp;quot;Maserati Bora&amp;quot;       &amp;quot;Volvo 142E&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;if we wanted to see what &lt;code&gt;.row_names_info()&lt;/code&gt; does
we would write&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;.row_names_info&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## function (x, type = 1L) 
## .Internal(shortRowNames(x, type))
## &amp;lt;bytecode: 0x563e6bf3c890&amp;gt;
## &amp;lt;environment: namespace:base&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but we can’t see any deeper unless we ask where that C code lives. I recommend using &lt;code&gt;pryr::show_c_source()&lt;/code&gt; (as I did &lt;a href=&#34;https://jcarroll.com.au/2022/04/22/where-for-loop-art-thou/&#34;&gt;in a previous post&lt;/a&gt;) to identify the C code for these, e.g. &lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;pryr::show_c_source(.Internal(shortRowNames(mtcars)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;shortRowNames is implemented by do_shortRowNames with op = 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which opens a &lt;a href=&#34;https://github.com/search?q=SEXP%20attribute_hidden%20do_shortRowNames+repo:wch/r-source&amp;amp;type=Code&#34;&gt;GitHub search of a copy of the R source&lt;/a&gt; in a browser. The file we want is &lt;a href=&#34;https://github.com/wch/r-source/blob/018816d40299e027d5d16832916019a65c1d6af2/src/main/attrib.c#L190&#34;&gt;&lt;code&gt;attrib.c&lt;/code&gt;&lt;/a&gt; and contains the C code&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SEXP do_shortRowNames(SEXP call, SEXP op, SEXP args, SEXP env)
{
    /* return  n if the data frame &amp;#39;vec&amp;#39; has c(NA, n) rownames;
     *	       nrow(.) otherwise;  note that data frames with nrow(.) == 0
     *		have no row.names.
     ==&amp;gt; is also used in dim.data.frame() */

    checkArity(op, args);
    SEXP s = getAttrib0(CAR(args), R_RowNamesSymbol), ans = s;
    int type = asInteger(CADR(args));

    if( type &amp;lt; 0 || type &amp;gt; 2)
	error(_(&amp;quot;invalid &amp;#39;%s&amp;#39; argument&amp;quot;), &amp;quot;type&amp;quot;);

    if(type &amp;gt;= 1) {
	int n = (isInteger(s) &amp;amp;&amp;amp; LENGTH(s) == 2 &amp;amp;&amp;amp; INTEGER(s)[0] == NA_INTEGER)
	    ? INTEGER(s)[1] : (isNull(s) ? 0 : LENGTH(s));
	ans = ScalarInteger((type == 1) ? n : abs(n));
    }
    return ans;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fully interpreting this is beyond the scope of this post, but the links at the start of this
post cover most of what’s not plain C code here.&lt;/p&gt;
&lt;p&gt;I won’t share my collaborator’s exact code, but I can write enough C that I can create
something with all the relevant features.&lt;/p&gt;
&lt;p&gt;Let’s calculate &lt;a href=&#34;https://en.wikipedia.org/wiki/Pythagorean_triple&#34;&gt;Pythagorean Triples&lt;/a&gt;! These
are sets of 3 integers (whole numbers) &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, and &lt;code&gt;c&lt;/code&gt; such that a triangle with sides of those
lengths will be a right-triangle (contains a 90 degree / right-angle). These have
the property that &lt;span class=&#34;math display&#34;&gt;\[a^2 + b^2 = c^2\]&lt;/span&gt;&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/pythagoras.png&#34; alt=&#34;Pythagorean theorem https://en.wikipedia.org/wiki/Pythagorean_theorem&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Pythagorean theorem &lt;a href=&#34;https://en.wikipedia.org/wiki/Pythagorean_theorem&#34; class=&#34;uri&#34;&gt;https://en.wikipedia.org/wiki/Pythagorean_theorem&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The smallest of these is &lt;code&gt;3, 4, 5&lt;/code&gt; because &lt;span class=&#34;math display&#34;&gt;\[3^2 + 4^2 = 9 + 16 = 25 = 5^2\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Generating these just happens to fit the use-case I’m emulating, plus I have a whole other
blog post coming up about these (stay tuned!).&lt;/p&gt;
&lt;p&gt;Some C code to generate these up to some maximum side-length, written similar to
the code I received, is&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;math.h&amp;gt;

int main (int argc, char *argv[]) {

  int a, b, c;
  int maxval;
  int ***triangles;

  if ( argc != 2 ) {
    printf(&amp;quot;Usage: triangle max_side_length\n&amp;quot;);
    exit(EXIT_FAILURE);
  }

  maxval = atoi( argv[1] );

  triangles = (int ***) malloc (maxval * sizeof(int **));
  for (a = 0; a &amp;lt; maxval; ++a) {
    triangles[a] = (int **) malloc (maxval * sizeof(int *));
    for (b = 0; b &amp;lt; maxval; ++b) {
      triangles[a][b] = (int *) malloc (maxval * sizeof(int));
      for (c = 0; c &amp;lt; maxval; ++c) {
        triangles[a][b][c] = 0;
      }
    }
  }

  for (c = 1; c &amp;lt;= maxval; c++) {
    for (b = 1; b &amp;lt;= c; b++)
      for (a = 1; a &amp;lt;= b; a++)
        if ( ( pow ( a, 2 ) + pow ( b, 2 ) ) == pow ( c, 2 ) ) {
          triangles[a][b][c] = a + b + c;
        }
  }

  printf(&amp;quot;%4s\t%4s\t%4s\t%4s\n&amp;quot;, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;, &amp;quot;sum&amp;quot;);
  printf(&amp;quot;   -------------------------\n&amp;quot;);
  for (c = 1; c &amp;lt;= maxval; c++) {
    for (b = 1; b &amp;lt;= c; b++)
      for (a = 1; a &amp;lt;= b; a++)
        if ( ( pow ( a, 2 ) + pow ( b, 2 ) ) == pow ( c, 2 ) ) {
          printf(&amp;quot;%4i\t%4i\t%4i\t%4i\n&amp;quot;, a, b, c, triangles[a][b][c]);
          }
      }

  exit(EXIT_SUCCESS);

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I won’t make this an entire C tutorial, but the main pieces are:&lt;/p&gt;
&lt;p&gt;Load some libraries for printing to screen, doing math, …&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;math.h&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Define an entrypoint function (the thing that will run when the code is run)
which takes some number of character arguments &lt;code&gt;argv&lt;/code&gt;, the first of which is the
compiled name of the program itself&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;int main (int argc, char *argv[]) {&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Define some variables, the most significant being &lt;code&gt;triangles&lt;/code&gt; which is denoted as
a pointer to a pointer to a pointer (!)&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;  int a, b, c;
  int maxval;
  int ***triangles;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s a lot of redirection, but it’s just creating a reference to a 3-dimensional array.&lt;/p&gt;
&lt;p&gt;Side-note: 0-indexed languages actually make a bit more sense when working with pointer math
because a “vector” of memory addresses really only needs to “point” to the starting address,
then every element is some offset away from that, so the first element of some vector &lt;code&gt;vec&lt;/code&gt;
might have some address &lt;code&gt;x&lt;/code&gt;, but you can access that with &lt;code&gt;vec[0]&lt;/code&gt;. You can access the next
element with &lt;code&gt;vec[1]&lt;/code&gt; which means “offset 1 position from &lt;code&gt;x&lt;/code&gt;, the starting address.” You can access
the fifth value by offsetting 4 positions, so &lt;code&gt;vec[4]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;One of my favourite bits of C trivia is that this syntactic sugar of using square brackets
to identify positions actually translates to&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vec[0] is at address x + 0 =&amp;gt; vec + 0
vec[1] is at address x + 1 =&amp;gt; vec + 1
vec[2] is at address x + 2 =&amp;gt; vec + 2
...
vec[5] is at address x + 5 =&amp;gt; vec + 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but addition (&lt;code&gt;+&lt;/code&gt;) is symmetric (commutative) so we can just as easily write&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vec + 0 =&amp;gt; 0 + vec =&amp;gt; 0 + x is at address 0[vec]
vec + 1 =&amp;gt; 1 + vec =&amp;gt; 1 + x is at address 1[vec]
vec + 2 =&amp;gt; 2 + vec =&amp;gt; 2 + x is at address 2[vec]
...
vec + 5 =&amp;gt; 5 + vec =&amp;gt; 5 + x is at address 5[vec]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and it all works out… &lt;code&gt;5[obj]&lt;/code&gt; is valid, and corresponds to the same address as &lt;code&gt;obj[5]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Back to our function. If only one argument is passed in (the name of the program) then the usage information is printed, otherwise the next argument is used to set the upper bound on the length of a
side of the triangle, converting it from a string to an int with &lt;code&gt;atoi&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;  if ( argc != 2 ) {
    printf(&amp;quot;Usage: triangle max_side_length\n&amp;quot;);
    exit(EXIT_FAILURE);
  }

  maxval = atoi( argv[1] );&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, the array is allocated (and assigned a default value of 0)&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;  triangles = (int ***) malloc (maxval * sizeof(int **));
  for (a = 0; a &amp;lt; maxval; ++a) {
    triangles[a] = (int **) malloc (maxval * sizeof(int *));
    for (b = 0; b &amp;lt; maxval; ++b) {
      triangles[a][b] = (int *) malloc (maxval * sizeof(int));
      for (c = 0; c &amp;lt; maxval; ++c) {
        triangles[a][b][c] = 0;
      }
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then, finally, we do the ‘calculation’ which just involves stepping through
every value, and if our criteria of &lt;span class=&#34;math display&#34;&gt;\[a^2 + b^2 == c^2\]&lt;/span&gt; is met, we
assign the sum of these to an element in &lt;code&gt;triangles&lt;/code&gt; indexed by &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, and &lt;code&gt;c&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;  for (c = 1; c &amp;lt;= maxval; c++) {
    for (b = 1; b &amp;lt;= c; b++)
      for (a = 1; a &amp;lt;= b; a++)
        if ( ( pow ( a, 2 ) + pow ( b, 2 ) ) == pow ( c, 2 ) ) {
          triangles[a][b][c] = a + b + c;
        }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This isn’t &lt;em&gt;efficient&lt;/em&gt; at all - there will be lots of &lt;code&gt;0&lt;/code&gt; values, but this is a
simple program.&lt;/p&gt;
&lt;p&gt;The last section of the code just loops back through all of &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, and &lt;code&gt;c&lt;/code&gt; and when
it finds a non-zero element, it prints it, along with the sum &lt;code&gt;a + b + c&lt;/code&gt; (the value in
&lt;code&gt;triangles[a][b][c]&lt;/code&gt;)&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;  printf(&amp;quot;%4s\t%4s\t%4s\t%4s\n&amp;quot;, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;, &amp;quot;sum&amp;quot;);
  printf(&amp;quot;   -------------------------\n&amp;quot;);
  for (c = 1; c &amp;lt;= maxval; c++) {
    for (b = 1; b &amp;lt;= c; b++)
      for (a = 1; a &amp;lt;= b; a++)
        if ( ( pow ( a, 2 ) + pow ( b, 2 ) ) == pow ( c, 2 ) ) {
          printf(&amp;quot;%4i\t%4i\t%4i\t%4i\n&amp;quot;, a, b, c, triangles[a][b][c]);
          }
      }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With all of this saved as &lt;a href=&#34;https://github.com/jonocarroll/triangles/blob/main/inst/src/triangles.c&#34;&gt;&lt;code&gt;triangles.c&lt;/code&gt;&lt;/a&gt; we can compile and run this code in a terminal&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cc -O -o triangle triangles.c

$ ./triangle 
Usage: triangle max_side_length

$ ./triangle 16
   a	   b	   c	 sum
   -------------------------
   3	   4	   5	  12
   6	   8	  10	  24
   5	  12	  13	  30
   9	  12	  15	  36
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Woot! You can even check that it has worked: &lt;span class=&#34;math display&#34;&gt;\[9^2 + 12^2 = 81 + 144 = 225 = 15^2\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Back to the goal of this post - how do we get R to run that? We have some C code, now what?&lt;/p&gt;
&lt;p&gt;First, I created an R package. I like using RStudio for this as it auto-generates a lot of
the structure I want. It does, however, create an example R file &lt;code&gt;R/hello.R&lt;/code&gt; (and corresponding
&lt;code&gt;man/hello.Rd&lt;/code&gt; page) so I delete those. I also delete the &lt;code&gt;NAMESPACE&lt;/code&gt; because I’m going to
use {roxygen} to generate a new one. I check ‘Generate documentation with Roxygen’ in the
Build tools menu, making sure to select ‘Build &amp;amp; Reload’ (which should be a default, no?)&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/generate.png&#34; alt=&#34;Generate documentation with Roxygen&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Generate documentation with Roxygen&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and build my empty package.&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;love&lt;/em&gt; the {usethis} package for building packages, and there’s support there for what
we’re doing, too! &lt;code&gt;usethis::use_c()&lt;/code&gt; sets up some structure and adds the required boilerplate
so that Roxygen knows we’re using C code. This does add a &lt;code&gt;src/code.c&lt;/code&gt; file we can delete and
in its place we can put our own C code.&lt;/p&gt;
&lt;p&gt;If you read the links at the start of this post, you’ll recognise that this C code isn’t quite
ready to be used in an R package, though - we need to be able to send an R object (a &lt;code&gt;SEXP&lt;/code&gt;) to this
C code, not a &lt;code&gt;char&lt;/code&gt;. More importantly, the functionality of the C code is all wrapped
up in the &lt;code&gt;main()&lt;/code&gt; entrypoint function - it would be great if that was refactored out to
another function that could be called from &lt;code&gt;main()&lt;/code&gt; but also from an R-facing function.&lt;/p&gt;
&lt;p&gt;I communicated this to my colleague and they agreed we could refactor that, but they
want to still run the C code from the command line, so we can’t just put &lt;em&gt;everything&lt;/em&gt; in our
R-facing function. The actual processing in the code could go to a new function
that doesn’t return anything, but does update the 3-dimensional array passed by
reference&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;void calculate_sum(int maxval, int ****tri_sum) {

  int a, b, c;

  for (c = 1; c &amp;lt;= maxval; c++) {
    for (b = 1; b &amp;lt;= c; b++)
      for (a = 1; a &amp;lt;= b; a++)
        if ( ( pow ( a, 2 ) + pow ( b, 2 ) ) == pow ( c, 2 ) ) {
          (*tri_sum)[a][b][c] = a + b + c;
        }
  }
}

[... in main()]

 printf(&amp;quot;calling external sum\n&amp;quot;);
 calculate_sum(maxval, &amp;amp;triangles);
 &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes, that’s a pointer to a pointer to a pointer to a pointer (!!!!).&lt;/p&gt;
&lt;p&gt;The gotchas I encountered here were that&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;*tri_sum[a][b][c]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;would be a pointer to the &lt;em&gt;indexed&lt;/em&gt; object, so I needed&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;(*tri_sum)[a][b][c]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and &lt;code&gt;&amp;amp;triangles&lt;/code&gt; sends a reference to the &lt;code&gt;triangles&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;Compiling and running &lt;a href=&#34;https://github.com/jonocarroll/triangles/blob/main/inst/src/triangles1.c&#34;&gt;this&lt;/a&gt; shows that we’ve successfully refactored out the main functionality&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cc -O -o triangle1 triangles1.c

$ ./triangle1 20
calling external sum
   a	   b	   c	 sum
   -------------------------
   3	   4	   5	  12
   6	   8	  10	  24
   5	  12	  13	  30
   9	  12	  15	  36
   8	  15	  17	  40
  12	  16	  20	  48
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this still isn’t &lt;em&gt;quite&lt;/em&gt; what we need for R… we need to pass and return &lt;code&gt;SEXP&lt;/code&gt;s.&lt;/p&gt;
&lt;p&gt;Rather than disrupt the runnable C code, we can add some additional R-specific code. That
requires the R-related libraries&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;#include &amp;lt;R.h&amp;gt;
#include &amp;lt;Rinternals.h&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(keeping in mind that these are &lt;em&gt;required&lt;/em&gt; if the user is compiling all of this code - it’s
possible, but perhaps we’ll comment these out when just using the C code standalone).&lt;/p&gt;
&lt;p&gt;We need a function that takes a &lt;code&gt;SEXP&lt;/code&gt; (our maximum value) and returns a &lt;code&gt;SEXP&lt;/code&gt; - this is
required, but so far we’re just printing to screen. We’ll return &lt;em&gt;something&lt;/em&gt; for now. A
function that meets these criteria and calls the new &lt;code&gt;calculate_sum()&lt;/code&gt; could &lt;a href=&#34;https://github.com/jonocarroll/triangles/blob/main/inst/src/triangles2.c&#34;&gt;be&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;SEXP C_triangles(SEXP maximum) {

  int a, b, c;
  int ***triangles;

  int maxval = * INTEGER(maximum);

  triangles = (int ***) malloc (maxval * sizeof(int **));
  for (a = 0; a &amp;lt; maxval; ++a) {
    triangles[a] = (int **) malloc (maxval * sizeof(int *));
    for (b = 0; b &amp;lt; maxval; ++b) {
      triangles[a][b] = (int *) malloc (maxval * sizeof(int));
      for (c = 0; c &amp;lt; maxval; ++c) {
        triangles[a][b][c] = 0;
      }
    }
  }

  printf(&amp;quot;calling C function to calc sum\n&amp;quot;);
  calculate_sum(maxval, &amp;amp;triangles);

  printf(&amp;quot;%4s\t%4s\t%4s\t%4s\n&amp;quot;, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;, &amp;quot;sum&amp;quot;);
  printf(&amp;quot;   -------------------------\n&amp;quot;);
  for (c = 1; c &amp;lt; maxval; ++c) {
    for (b = 1; b &amp;lt;= c; ++b)
      for (a = 1; a &amp;lt;= b; ++a)
        if ( ( pow ( a, 2 ) + pow ( b, 2 ) ) == pow ( c, 2 ) ) {
          printf(&amp;quot;%4i\t%4i\t%4i\t%4i\n&amp;quot;, a, b, c, triangles[a][b][c]);
        }
  }

  SEXP result = PROTECT(allocVector(LGLSXP, 1));
  LOGICAL(result)[0] = 1;
  UNPROTECT(1);

  return(result);

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is very similar to what’s in &lt;code&gt;main()&lt;/code&gt; - it still performs the allocation then
calls out to the calculating code, then prints the result. The only new part is
creating a logical &lt;code&gt;result&lt;/code&gt; object (&lt;code&gt;1&lt;/code&gt; == &lt;code&gt;TRUE&lt;/code&gt;) so that there’s something to return.&lt;/p&gt;
&lt;p&gt;You can read about &lt;code&gt;PROTECT&lt;/code&gt; which guards against garbage collection in the &lt;a href=&#34;https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Garbage-Collection&#34;&gt;R-exts manual&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The new functions called here such as &lt;code&gt;allocVector&lt;/code&gt; come from the Rinternals library and
are macros for functions starting with &lt;code&gt;Rf_&lt;/code&gt; - i.e. &lt;code&gt;Rf_allocVector&lt;/code&gt;. I had some issues initially
because I followed some guides which used &lt;code&gt;#define R_NO_REMAP&lt;/code&gt;. Keep in mind that if you use
that (so that library functions aren’t remapped) you will need to use the &lt;code&gt;Rf_&lt;/code&gt; versions
of these functions. I ended up removing the &lt;code&gt;#define&lt;/code&gt; myself, but I’m not sure if that will
bite me later.&lt;/p&gt;
&lt;p&gt;This also needs to convert the &lt;code&gt;SEXP&lt;/code&gt; input &lt;code&gt;maximum&lt;/code&gt; to a C &lt;code&gt;int&lt;/code&gt; via &lt;code&gt;* INTEGER(maximum)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We now have something that &lt;em&gt;should&lt;/em&gt; work in our R package! Saving this as &lt;code&gt;src/triangles.c&lt;/code&gt;
we can add the R interface as &lt;code&gt;R/triangles.R&lt;/code&gt; containing just&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;#&amp;#39; triangles
#&amp;#39;
#&amp;#39; @export
triangles &amp;lt;- function(maxval) {
  .Call(&amp;quot;C_triangles&amp;quot;, as.integer(maxval))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where we definitely only send an integer to the C function.&lt;/p&gt;
&lt;p&gt;Build the package, which compiles the code, and load the package&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(triangles)
triangles(20)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;calling C function to calc sum
   a	   b	   c	 sum
   -------------------------
   3	   4	   5	  12
   6	   8	  10	  24
   5	  12	  13	  30
   9	  12	  15	  36
   8	  15	  17	  40
[1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We see the debug print statement, then the printed output, and finally our returned &lt;code&gt;TRUE&lt;/code&gt;. Success!&lt;/p&gt;
&lt;p&gt;The original code was made to work in a command line pipeline where the values were read
back in by a subsequent program, e.g.&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;$ ./triangle 16 | tail +3 | awk &amp;#39;{ sum += $4 } END { print sum }&amp;#39;
102&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so printing to &lt;code&gt;stdout&lt;/code&gt; made sense there, but we want to &lt;em&gt;use&lt;/em&gt; the values in R, so it
would be great to return an actual &lt;code&gt;data.frame&lt;/code&gt;. &lt;a href=&#34;https://github.com/coolbutuseless/simplecall/blob/master/src/create-data-frame.c&#34;&gt;This repo&lt;/a&gt;
contains a great example of doing that but I want to return a &lt;code&gt;data.frame&lt;/code&gt; with a
variable number of rows, and I need to allocate data into that. ChatGPT actually got me close enough to a working version. Here’s what I ended up with&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;
  [...]

  calculate_sum(maxval, &amp;amp;triangles);

  /* count rows */
  int nrows = 0;
  for (c = 1; c &amp;lt; maxval; ++c) {
    for (b = 1; b &amp;lt;= c; ++b)
      for (a = 1; a &amp;lt;= b; ++a)
          if (triangles[a][b][c] != 0) {
          nrows += 1;
        }
  }

  /* output a data.frame */
  int ncols = 4;

  SEXP col1, col2, col3, col4, df;
  PROTECT(df = allocVector(VECSXP, ncols));

  PROTECT(col1 = allocVector(INTSXP, nrows));
  PROTECT(col2 = allocVector(INTSXP, nrows));
  PROTECT(col3 = allocVector(INTSXP, nrows));
  PROTECT(col4 = allocVector(INTSXP, nrows));

  int j = 0;
  for (c = 1; c &amp;lt; maxval; ++c) {
    for (b = 1; b &amp;lt;= c; ++b) {
      for (a = 1; a &amp;lt;= b; ++a) {
        if (triangles[a][b][c] != 0) {
          INTEGER(col1)[j] = a;
          INTEGER(col2)[j] = b;
          INTEGER(col3)[j] = c;
          INTEGER(col4)[j] = triangles[a][b][c];
          j += 1;
        }
      }
    }
  }

  SET_VECTOR_ELT(df, 0, col1);
  SET_VECTOR_ELT(df, 1, col2);
  SET_VECTOR_ELT(df, 2, col3);
  SET_VECTOR_ELT(df, 3, col4);

  SEXP colNames;
  PROTECT(colNames = allocVector(STRSXP, ncols));
  SET_STRING_ELT(colNames, 0, mkChar(&amp;quot;a&amp;quot;));
  SET_STRING_ELT(colNames, 1, mkChar(&amp;quot;b&amp;quot;));
  SET_STRING_ELT(colNames, 2, mkChar(&amp;quot;c&amp;quot;));
  SET_STRING_ELT(colNames, 3, mkChar(&amp;quot;sum&amp;quot;));
  setAttrib(df, R_NamesSymbol, colNames);

  SEXP rowNames;
  PROTECT(rowNames = allocVector(STRSXP, nrows));
  for (int i = 0; i &amp;lt; nrows; ++i) {
    char rowName[11];
    snprintf(rowName, sizeof(rowName), &amp;quot;%10d&amp;quot;, i + 1
    SET_STRING_ELT(rowNames, i, mkChar(rowName));
  }
  setAttrib(df, R_RowNamesSymbol, rowNames);

  SEXP className;
  PROTECT(className = allocVector(STRSXP, 1));
  SET_STRING_ELT(className, 0, mkChar(&amp;quot;data.frame&amp;quot;));
  classgets(df, className);

  UNPROTECT(8);
  return df;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Going through the biggest parts of this: first we identify how many rows we want
to output by counting the nonzero elements of the passed-by-reference &lt;code&gt;triangles&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;  /* count rows */
  int nrows = 0;
  for (c = 1; c &amp;lt; maxval; ++c) {
    for (b = 1; b &amp;lt;= c; ++b)
      for (a = 1; a &amp;lt;= b; ++a)
          if (triangles[a][b][c] != 0) {
          nrows += 1;
        }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then allocating vectors - first a list the length of the number of columns (4) then
one for each of the columns with length &lt;code&gt;nrows&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt; /* output a data.frame */
  int ncols = 4;

  SEXP col1, col2, col3, col4, df;
  PROTECT(df = allocVector(VECSXP, ncols));

  PROTECT(col1 = allocVector(INTSXP, nrows));
  PROTECT(col2 = allocVector(INTSXP, nrows));
  PROTECT(col3 = allocVector(INTSXP, nrows));
  PROTECT(col4 = allocVector(INTSXP, nrows));&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These are then populated in a loop with a new counter for the nonzero elements&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;  int j = 0;
  for (c = 1; c &amp;lt; maxval; ++c) {
    for (b = 1; b &amp;lt;= c; ++b) {
      for (a = 1; a &amp;lt;= b; ++a) {
        if (triangles[a][b][c] != 0) {
          INTEGER(col1)[j] = a;
          INTEGER(col2)[j] = b;
          INTEGER(col3)[j] = c;
          INTEGER(col4)[j] = triangles[a][b][c];
          j += 1;
        }
      }
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and finally the vectors linked into the list&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;  SET_VECTOR_ELT(df, 0, col1);
  SET_VECTOR_ELT(df, 1, col2);
  SET_VECTOR_ELT(df, 2, col3);
  SET_VECTOR_ELT(df, 3, col4);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The rest is mostly boilerplate of setting up the &lt;code&gt;data.frame&lt;/code&gt;: assigning
column names&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;  SEXP colNames;
  PROTECT(colNames = allocVector(STRSXP, ncols));
  SET_STRING_ELT(colNames, 0, mkChar(&amp;quot;a&amp;quot;));
  SET_STRING_ELT(colNames, 1, mkChar(&amp;quot;b&amp;quot;));
  SET_STRING_ELT(colNames, 2, mkChar(&amp;quot;c&amp;quot;));
  SET_STRING_ELT(colNames, 3, mkChar(&amp;quot;sum&amp;quot;));
  setAttrib(df, R_NamesSymbol, colNames);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and row names&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;  SEXP rowNames;
  PROTECT(rowNames = allocVector(STRSXP, nrows));
  for (int i = 0; i &amp;lt; nrows; ++i) {
    char rowName[11];
    snprintf(rowName, sizeof(rowName), &amp;quot;%10d&amp;quot;, i + 1
    SET_STRING_ELT(rowNames, i, mkChar(rowName));
  }
  setAttrib(df, R_RowNamesSymbol, rowNames);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the class itself&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;  SEXP className;
  PROTECT(className = allocVector(STRSXP, 1));
  SET_STRING_ELT(className, 0, mkChar(&amp;quot;data.frame&amp;quot;));
  classgets(df, className);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then finally &lt;code&gt;UNPROTECT&lt;/code&gt;ing the &lt;code&gt;PROTECTED&lt;/code&gt; objects and returning the &lt;code&gt;data.frame&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;  UNPROTECT(8);
  return df;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At one point, I had forgotten that I had modified an example and now had more &lt;code&gt;PROTECT&lt;/code&gt;
wrappers around objects, but hadn’t updated the number in &lt;code&gt;UNPROTECT&lt;/code&gt;. It turns out this
leads to an error in R about a stack imbalance - not particularly meaningful if you don’t realise what that means, so FYI.&lt;/p&gt;
&lt;p&gt;So, with &lt;a href=&#34;https://github.com/jonocarroll/triangles/blob/main/inst/src/triangles3.c&#34;&gt;this new code&lt;/a&gt; in &lt;code&gt;src/triangles.c&lt;/code&gt; we re-build and reload and try it out&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(triangles)

x &amp;lt;- triangles(16)

x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##            a  b  c sum
##          1 3  4  5  12
##          2 6  8 10  24
##          3 5 12 13  30
##          4 9 12 15  36&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;str(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;#39;data.frame&amp;#39;:	4 obs. of  4 variables:
##  $ a  : int  3 6 5 9
##  $ b  : int  4 8 12 12
##  $ c  : int  5 10 13 15
##  $ sum: int  12 24 30 36&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing printed when not expected, and the result is really a &lt;code&gt;data.frame&lt;/code&gt;! We can
even work with the data now&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sum(x$sum)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 102&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We still have the C code, and this can be updated as it evolves without affecting
the R interface to it. With the R parts commented out, it can still be run as if
it was just a regular C file. If we &lt;em&gt;really&lt;/em&gt; want to compile it with the R parts
still there we can include the R libraries (on a linux system, for example) with&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;$ cc -O -o triangle triangles.c -I/usr/share/R/include -L/usr/lib/R/lib -lR&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Update 12-Aug-2023&lt;/strong&gt;: I forgot to mention that in order to pass checks, R wants
to have the following, typically in a file &lt;a href=&#34;https://github.com/jonocarroll/triangles/blob/main/src/init.c&#34;&gt;&lt;code&gt;src/init.c&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;#include &amp;lt;R.h&amp;gt;
#include &amp;lt;Rinternals.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt; // for NULL
#include &amp;lt;R_ext/Rdynload.h&amp;gt;

/* .Call calls */
extern SEXP C_triangles(SEXP maximum);

static const R_CallMethodDef CallEntries[] = {
  {&amp;quot;C_triangles&amp;quot;, (DL_FUNC) &amp;amp;C_triangles, 1},
  {NULL, NULL, 0}
};

void R_init_addr(DllInfo *dll) {
  R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
  R_useDynamicSymbols(dll, FALSE);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I won’t say I understand this bit, but it &lt;em&gt;is&lt;/em&gt; mentioned in &lt;a href=&#34;https://blog.davisvaughan.com/posts/2019-03-02-now-you-c-me/#registration&#34;&gt;this part&lt;/a&gt;
of Davis’ post.&lt;/p&gt;
&lt;p&gt;I also updated the &lt;code&gt;snprintf&lt;/code&gt; call in the rownames assignment since I got a warning about
truncation.&lt;/p&gt;
&lt;p&gt;There are some valid concerns about the fact that I’m not explicitly &lt;code&gt;free()&lt;/code&gt;ing the
allocated memory, so I plan to add some code to do that.&lt;/p&gt;
&lt;p&gt;As always, I’ve learned a lot messing with things outside of my comfort zone here. I
wouldn’t say that I want to write a lot more C code, but at least now I feel
somewhat comfortable bringing into R to work with.&lt;/p&gt;
&lt;p&gt;The package I detailed building here is on GitHub: &lt;a href=&#34;https://github.com/jonocarroll/triangles&#34;&gt;https://github.com/jonocarroll/triangles&lt;/a&gt; in case it’s useful to you.&lt;/p&gt;
&lt;p&gt;There’s always more for me to learn, though, so if you have comments, feedback,
suggestions for improvements, etc… I can be found on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; or use the comments below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-08-12
##  pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.17    2023-05-16 [1] CRAN (R 4.1.2)
##  bookdown      0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  bslib         0.5.0   2023-06-09 [3] CRAN (R 4.3.1)
##  cachem        1.0.8   2023-05-01 [3] CRAN (R 4.3.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.6.1   2023-03-23 [3] CRAN (R 4.2.3)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest        0.6.33  2023-07-07 [3] CRAN (R 4.3.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.21    2023-05-05 [3] CRAN (R 4.3.0)
##  fastmap       1.1.1   2023-02-24 [3] CRAN (R 4.2.2)
##  fs            1.6.3   2023-07-20 [3] CRAN (R 4.3.1)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  htmltools     0.5.5   2023-03-23 [3] CRAN (R 4.2.3)
##  htmlwidgets   1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv        1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.7   2023-06-29 [3] CRAN (R 4.3.1)
##  knitr         1.43    2023-05-25 [3] CRAN (R 4.3.0)
##  later         1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  pkgbuild      1.4.0   2022-11-27 [1] CRAN (R 4.1.2)
##  pkgload       1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.8.2   2023-06-30 [3] CRAN (R 4.3.1)
##  profvis       0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises      1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps            1.7.5   2023-04-18 [3] CRAN (R 4.3.0)
##  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.1.1   2023-04-28 [1] CRAN (R 4.1.2)
##  rmarkdown     2.23    2023-07-01 [3] CRAN (R 4.3.1)
##  rstudioapi    0.15.0  2023-07-07 [3] CRAN (R 4.3.1)
##  sass          0.4.7   2023-07-15 [3] CRAN (R 4.3.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny         1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi       1.7.12  2023-01-11 [3] CRAN (R 4.2.2)
##  stringr       1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  triangles   * 0.1.0   2023-08-11 [1] local
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis       2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  vctrs         0.6.3   2023-06-14 [1] CRAN (R 4.1.2)
##  xfun          0.39    2023-04-20 [3] CRAN (R 4.3.0)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml          2.3.7   2023-01-23 [3] CRAN (R 4.2.2)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Argument Matching Across Languages</title>
      <link>https://jcarroll.com.au/2023/08/06/argument-matching-across-languages/</link>
      <pubDate>Sun, 06 Aug 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/08/06/argument-matching-across-languages/</guid>
      <description>&lt;p&gt;With Functional Programming, we write functions which take arguments and do something with
or based on those arguments. You might not think there’s much to learn about given that
tiny description of “an argument to a function” but the syntax and mechanics of different
languages is actually widely variable and intricate.&lt;/p&gt;
&lt;p&gt;Let’s say I have some function in R that takes three arguments, &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, and &lt;code&gt;z&lt;/code&gt;,
and just prints them out in a string in that order.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;r_fun &amp;lt;- function(x, y, z) {
  sprintf(&amp;quot;arguments are: %s, %s, %s&amp;quot;, x, y, z)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Calling this function with good practices (specifying all the argument names in full)
would look like this&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;r_fun(x = &amp;quot;a&amp;quot;, y = &amp;quot;b&amp;quot;, z = &amp;quot;c&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;arguments are: a, b, c&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I said “in full” because by default, R will happily do &lt;em&gt;partial&lt;/em&gt; matching, so long
as it can uniquely figure out which argument you mean&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;long_args &amp;lt;- function(alphabet = &amp;quot;a to z&amp;quot;, altitude = 100) {
  print(sprintf(&amp;quot;alphabet: %s&amp;quot;, alphabet))
  print(sprintf(&amp;quot;altitude: %d&amp;quot;, altitude))
}
long_args(alphabet = &amp;quot;[A-Z]&amp;quot;, altitude = 50)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;alphabet: [A-Z]&amp;quot;
## [1] &amp;quot;altitude: 50&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, both arguments start with &lt;code&gt;&#34;al&#34;&lt;/code&gt; so it’s ambiguous up to there&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;long_args(al = &amp;quot;letters&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in long_args(al = &amp;quot;letters&amp;quot;): argument 1 matches multiple formal arguments&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but we only &lt;em&gt;need&lt;/em&gt; to specify enough letters to disambiguate&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;long_args(alpha = &amp;quot;LETTERS&amp;quot;, alt = 200)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;alphabet: LETTERS&amp;quot;
## [1] &amp;quot;altitude: 200&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Relying on this behaviour is dangerous, and it’s recommended to turn on warnings
when this happens with&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;options(warnPartialMatchArgs = TRUE)
long_args(alpha = &amp;quot;LETTERS&amp;quot;, alt = 200)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-warning text-warning&#34;&gt;&lt;code&gt;## Warning in long_args(alpha = &amp;quot;LETTERS&amp;quot;, alt = 200): partial argument match of
## &amp;#39;alpha&amp;#39; to &amp;#39;alphabet&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-warning text-warning&#34;&gt;&lt;code&gt;## Warning in long_args(alpha = &amp;quot;LETTERS&amp;quot;, alt = 200): partial argument match of
## &amp;#39;alt&amp;#39; to &amp;#39;altitude&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;alphabet: LETTERS&amp;quot;
## [1] &amp;quot;altitude: 200&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You don’t &lt;em&gt;have to&lt;/em&gt; use argument names when calling the function, though - you can just rely on positional arguments&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;r_fun(&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;arguments are: a, b, c&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and this is &lt;em&gt;very&lt;/em&gt; commonly done, despite it being less clear to what any of those
refer, and runs the risk that the function changes argument ordering in an updated
version. It works, though.&lt;/p&gt;
&lt;p&gt;Extensive sidenote: square-bracket matrix subsetting officially uses the (poorly? traditionally?)
named arguments &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt; as &lt;code&gt;[i, j]&lt;/code&gt; but it actually entirely ignores them and uses
positional arguments. The documentation (&lt;code&gt;?`[`&lt;/code&gt;) does warn about this&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Note that these operations do not match their index arguments in the standard way:
argument names are ignored and positional matching only is used. So m[j = 2, i = 1] is
equivalent to m[2, 1] and not to m[1, 2].”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;but it would be very easy to get bitten by it if one tried to use the names directly&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m &amp;lt;- matrix(1:9, 3, 3, byrow = TRUE)
m&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
## [3,]    7    8    9&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m[i = 1, j = 2]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m[j = 2, i = 1]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;https://fediscience.org/@tslumley/110670564210497040&#34;&gt;Thomas Lumley&lt;/a&gt;
notes that&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“it used to be that no primitive functions did argument matching by name.”/” and “-’
and switch() and some others still don’t. I’m not sure why”[” wasn’t changed in 2.11
when a bunch of primitives got normal argument matching.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Worse still, perhaps - the &lt;code&gt;seq()&lt;/code&gt; function creates a sequence of values. It has the
formal arguments with defaults &lt;code&gt;from = 1&lt;/code&gt; and &lt;code&gt;to = 1&lt;/code&gt; so you can calculate&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;seq(from = 2, to = 5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 3 4 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or you can leverage the default of &lt;code&gt;from = 1&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;seq(to = 5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 2 3 4 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, there are &lt;strong&gt;five&lt;/strong&gt; “forms” in which
you can provide arguments to this function and they behave differently. If you &lt;em&gt;only&lt;/em&gt;
specify the first argument unnamed, it treats this as &lt;code&gt;to&lt;/code&gt; despite the first argument being &lt;code&gt;from&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;seq(5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 2 3 4 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is extra strange, because if you &lt;em&gt;do&lt;/em&gt; specify &lt;code&gt;to&lt;/code&gt; with its ostensibly default value &lt;code&gt;1&lt;/code&gt;, the sequence is backwards&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;seq(5, to = 1)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 5 4 3 2 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Back to our function - a feature that makes R really neat is that you can specify
the named arguments in &lt;em&gt;any order&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;r_fun(z = &amp;quot;c&amp;quot;, x = &amp;quot;a&amp;quot;, y = &amp;quot;b&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;arguments are: a, b, c&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don’t specify them by name, R will default to positions, so specifying just
one (e.g. &lt;code&gt;z&lt;/code&gt;) but leaving the rest unspecified, R will presume you want the others
in positional order&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;r_fun(z = &amp;quot;c&amp;quot;, &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;arguments are: a, b, c&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where it gets really interesting is you can go &lt;em&gt;back&lt;/em&gt; to named arguments further along
and again, R will figure out that you mean the remaining unnamed argument&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;r_fun(z = &amp;quot;c&amp;quot;, &amp;quot;b&amp;quot;, x = &amp;quot;a&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;arguments are: a, b, c&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This only holds if the function &lt;em&gt;doesn’t&lt;/em&gt; use the ellipses &lt;code&gt;...&lt;/code&gt; which
captures “any other arguments” when calling the function, often to be passed
on to another function. If the function signature has &lt;code&gt;...&lt;/code&gt; then all the
unnamed arguments are captured. This example function just
combines any other arguments into a comma-separated string, if there
are any (tested with the under-documented &lt;code&gt;...length()&lt;/code&gt; which returns the number
of arguments captured via &lt;code&gt;...&lt;/code&gt;)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dot_f &amp;lt;- function(a = 1, b = 2, ...) {
  print(sprintf(&amp;quot;named arguments: %s, %s&amp;quot;, a, b))
  if (...length()) {
    print(sprintf(&amp;quot;additional arguments: %s&amp;quot;, toString(list(...))))
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can call this with just the named arguments&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dot_f(a = 3, b = 4)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;named arguments: 3, 4&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or you can add more argument (no name required)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dot_f(a = 3, b = 4, 5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;named arguments: 3, 4&amp;quot;
## [1] &amp;quot;additional arguments: 5&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As before, none of the names are really required, and we can add as
many as we want&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dot_f(3, 4, 5, 6, 7)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;named arguments: 3, 4&amp;quot;
## [1] &amp;quot;additional arguments: 5, 6, 7&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We &lt;em&gt;can&lt;/em&gt; name them if we want&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dot_f(a = 3, b = 4, blah = 5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;named arguments: 3, 4&amp;quot;
## [1] &amp;quot;additional arguments: 5&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but here be danger, because those names can be &lt;em&gt;anything&lt;/em&gt; and aren’t matched
to the actual function, so this works (say, I misspelled an argument name &lt;code&gt;a&lt;/code&gt; as &lt;code&gt;A&lt;/code&gt;)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dot_f(A = 3, B = 4, 5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;named arguments: 5, 2&amp;quot;
## [1] &amp;quot;additional arguments: 3, 4&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that the additional arguments are the ones I named (not those in
the function definition); the &lt;code&gt;5&lt;/code&gt; has been positionally matched to &lt;code&gt;a&lt;/code&gt;; and &lt;code&gt;b&lt;/code&gt;
has taken its default value of &lt;code&gt;2&lt;/code&gt; because no other arguments were provided.&lt;/p&gt;
&lt;p&gt;We can still mix up the ordering of positions, provided everything else matches up&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dot_f(3, b = 4, 5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;named arguments: 3, 4&amp;quot;
## [1] &amp;quot;additional arguments: 5&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dot_f(3, b = 4, 5, a = 2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;named arguments: 2, 4&amp;quot;
## [1] &amp;quot;additional arguments: 3, 5&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The flexibility in all of this is what encouraged Joe Cheng to use R as an
interface to HTML in the form of shiny, what he calls
&lt;a href=&#34;https://youtu.be/HpqLXB_TnpI?t=1723&#34;&gt;“a bizzarely good host language”&lt;/a&gt; (should link
to the right timestamp) and he notes that other languages don’t let you do
this sort of mixing up of named and positional arguments.&lt;/p&gt;
&lt;p&gt;Okay, that’s R - weird and fun, but a lot of flexibility.&lt;/p&gt;
&lt;p&gt;I saw &lt;a href=&#34;https://thoughtbot.com/blog/rust-doesn-t-have-named-arguments-so-what&#34;&gt;this post&lt;/a&gt; mentioned in the &lt;code&gt;#rust&lt;/code&gt; hashtag on Mastodon and had a look - it surprised me
at first because I thought “what do you mean Rust doesn’t have named arguments?”…&lt;/p&gt;
&lt;p&gt;I’ve become so used to the inline help from VSCode when I’m writing Rust that I
didn’t realise I wasn’t using named arguments.&lt;/p&gt;
&lt;p&gt;Here’s a function I wrote for my &lt;a href=&#34;https://github.com/jonocarroll/rps.rs&#34;&gt;toy rock-paper-scissors game in Rust&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;fn play(a: Throw, b: Throw) -&amp;gt; GameResult {
    let result = match a.cmp(&amp;amp;b) {
        Ordering::Equal =&amp;gt; GameResult::Tie,
        Ordering::Greater =&amp;gt; GameResult::YouWin,
        Ordering::Less =&amp;gt; GameResult::YouLose,
    };

    println!(&amp;quot;{} {}&amp;quot;, &amp;quot;Result:&amp;quot;.purple().bold(), result);

    result
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It has arguments &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; because I did a terrible job naming them - I knew
exactly how I planned to use them, so bad luck to anyone else.&lt;/p&gt;
&lt;p&gt;Calling that function further down in the code I have&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;let user = val.user();
let computer = Throw::computer();
play(user, computer);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;BUT what I see in the editor has the argument names, unless I switch off
hints (which I have bound to holding Ctrl+Alt at the moment)&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/typehints_opt.gif&#34; alt=&#34;Toggling inlay hints in VSCode&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Toggling inlay hints in VSCode&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So, I can’t just rearrange arguments in Rust?&lt;/p&gt;
&lt;p&gt;If I define a function with two arguments&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt; fn two_args(a: f64, b: &amp;amp;str) -&amp;gt; String {
        let res = format!(&amp;quot;all arguments: {a}, {b}&amp;quot;);
        res
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then I can call it&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt; two_args(42.0, &amp;quot;forty-two&amp;quot;)
&amp;quot;all arguments: 42, forty-two&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just swapping the arguments obviously fails because &lt;code&gt;42.0&lt;/code&gt; isn’t a &lt;code&gt;&amp;amp;str&lt;/code&gt; and
&lt;code&gt;&#34;forty-two&#34;&lt;/code&gt; isn’t a &lt;code&gt;f64&lt;/code&gt;. But there isn’t a way to say “the value for that
argument is this”; I can’t use any of these&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;two_args(a = 42.0, b = &amp;quot;forty-two&amp;quot;)
two_args(a: 42.0, b: &amp;quot;forty-two&amp;quot;)

two_args(b = &amp;quot;forty-two&amp;quot;, a = 42.0)
two_args(b: &amp;quot;forty-two&amp;quot;, a: 42.0)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I suspect the fact that this was a surprise to me means I’m earlier in my Rust
learning than I had thought - I clearly haven’t built anything that has
functionality I didn’t directly need, because I haven’t had to worry about
calling functions in strange ways yet.&lt;/p&gt;
&lt;p&gt;There is one loophole… time to break out another cool toy: &lt;a href=&#34;https://github.com/extendr/rextendr&#34;&gt;{rextendr}&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(rextendr)

rust_function(
  &amp;#39;fn two_args(a: f64, b: &amp;amp;str) -&amp;gt; String {
          let res = format!(&amp;quot;all arguments: {a}, {b}&amp;quot;);
          res
  }&amp;#39;
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This produces an R function that takes two arguments, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; which I can call
as if it was an R function&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;two_args(a = 42, b = &amp;quot;forty-two&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;all arguments: 42, forty-two&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can call it without argument names&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;two_args(42, &amp;quot;forty-two&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;all arguments: 42, forty-two&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and I &lt;em&gt;can&lt;/em&gt; swap them&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;two_args(b = &amp;quot;forty-two&amp;quot;, a = 42)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;all arguments: 42, forty-two&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is just because the argument matching happens before the values get
sent down to the Rust code - the function here is an R function that calls
other code internally&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;two_args&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## function (a, b) 
## .Call(&amp;quot;wrap__two_args&amp;quot;, a, b, PACKAGE = &amp;quot;librextendr1&amp;quot;)
## &amp;lt;bytecode: 0x55d873cff7b8&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I somewhat started out the idea for this blogpost as I was learning some Typescript and
came across this &lt;a href=&#34;https://github.com/gibbok/typescript-book#typescript-fundamental-comparison-rules&#34;&gt;https://github.com/gibbok/typescript-book#typescript-fundamental-comparison-rules&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“Function parameters are compared by types, not by their names:”&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&#34;typescript&#34;&gt;&lt;code&gt;type X = (a: number) =&amp;gt; void;
type Y = (a: number) =&amp;gt; void;
let x: X = (j: number) =&amp;gt; undefined;
let y: Y = (k: number) =&amp;gt; undefined;
y = x; // Valid
x = y; // Valid&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which initially struck me as strange, and I needed to work through some examples in a live
setting. On reflection, I think I see that this is exactly what I would specify in
e.g. &lt;a href=&#34;http://learnyouahaskell.com/types-and-typeclasses&#34;&gt;Haskell&lt;/a&gt; - “a function that takes a number”, not “a function with an argument named &lt;code&gt;a&lt;/code&gt; which
is a number”&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;x :: Float -&amp;gt; Nothing&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because technically all functions in Haskell &lt;a href=&#34;https://wiki.haskell.org/Currying&#34;&gt;actually only take a single argument&lt;/a&gt; (the notation &lt;code&gt;Int -&amp;gt; Int -&amp;gt; Int&lt;/code&gt; reveals this
fact nicely, but in practice the notation makes it feel like multiple arguments can be used)
there is no way to “pass arguments by name” but there &lt;em&gt;is&lt;/em&gt; a neat way to swap the order
of arguments that a function expects to receive; &lt;a href=&#34;https://hackage.haskell.org/package/base-4.18.0.0/docs/Prelude.html#v:flip&#34;&gt;&lt;code&gt;flip&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;flip :: (a -&amp;gt; b -&amp;gt; c) -&amp;gt; b -&amp;gt; a -&amp;gt; c

&amp;gt;&amp;gt;&amp;gt; flip (++) &amp;quot;hello&amp;quot; &amp;quot;world&amp;quot;
&amp;quot;worldhello&amp;quot;

-- or

&amp;gt;&amp;gt;&amp;gt; &amp;quot;hello&amp;quot; ++ &amp;quot;world&amp;quot;
&amp;quot;helloworld&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those of you familiar with R’s S3 dispatch functionality will perhaps note that
the ‘first’ argument has a special role; it controls exactly which method will
be called. If we had some function which was flexible in the sense that it could
take several different ‘classes’ and do something different with them, we would
write that as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;flexi &amp;lt;- function(a, b) {
  UseMethod(&amp;quot;flexi&amp;quot;)
}

flexi.matrix &amp;lt;- function(a, b) {
  paste0(&amp;quot;a is a matrix, b = &amp;quot;, b)
}

flexi.data.frame &amp;lt;- function(a, b) {
  paste0(&amp;quot;a is a data.frame, b = &amp;quot;, b)
}

flexi.default &amp;lt;- function(a, b) {
  paste0(&amp;quot;a is something else, b = &amp;quot;, b)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, depending on whether &lt;code&gt;a&lt;/code&gt; is a &lt;code&gt;matrix&lt;/code&gt;, a &lt;code&gt;data.frame&lt;/code&gt;, or something else, one
of the ‘methods’ will be called&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;flexi(a = matrix(), b = 7)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;a is a matrix, b = 7&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;flexi(a = data.frame(), b = 8)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;a is a data.frame, b = 8&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;flexi(a = 1, b = 9)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;a is something else, b = 9&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;even if we swap the order of the arguments in the call&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;flexi(b = 3, a = matrix())&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;a is a matrix, b = 3&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;S4 dispatch goes even further and dispatches based on more than just the class of
the first argument. Stuart Lee has &lt;a href=&#34;https://stuartlee.org/2019/07/09/s4-short-guide/&#34;&gt;a great guide on S4&lt;/a&gt;. The point is, you can do something
different depending on what you pass to multiple arguments&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;s4flexi(matrix(), data.frame(), 7)
s4flexi(matrix(), data.frame(), list())
s4flexi(matrix(), data.frame(), NULL)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Julia has some of the most interesting argument parsing. I love the Haskell-like
function declarations - so little boilerplate! We define some function &lt;code&gt;f&lt;/code&gt; that
takes two arguments&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;f(a, b) = a + b&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## f (generic function with 1 method)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;f(4, 5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similar to the Rust situation, though - these aren’t named outside of the function body,
so we can’t refer to them either in that order or reversed&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;f(a = 4, b = 5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia bg-danger text-danger&#34;&gt;&lt;code&gt;MethodError: no method matching f(; a=4, b=5)
Closest candidates are:
  f(!Matched::Any, !Matched::Any) at none:3 got unsupported keyword arguments &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The reason is that Julia uses the python-esque keyword argument syntax, where unnamed
arguments appear first, followed by any keyword arguments following a &lt;code&gt;;&lt;/code&gt;, so we can specify
these correctly as&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;f(; a, b) = a + b&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## f (generic function with 2 methods)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;f(a = 4, b = 6)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Julia is optionally typed, which means we can be flippant with the types here, or we
can be very specific - we can specify that &lt;code&gt;a&lt;/code&gt; should be an integer and &lt;code&gt;b&lt;/code&gt; should be
a string, and that produces a &lt;em&gt;different&lt;/em&gt; method compared to what we already defined. In
this case, I want to return a string with the two values&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;f(; a::Int, b::String) = &amp;quot;$a; $b&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## f (generic function with 2 methods)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;f(a = 42, b = &amp;quot;life, universe, everything&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;quot;42; life, universe, everything&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since these are now named, we can swap them&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;f(b = &amp;quot;L, U, E&amp;quot;, a = 42)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;quot;42; L, U, E&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but what’s even more powerful is we can define a general method, and add type-specific methods
for whatever combination of argument types we want; the first of these returns an integer,
while the other two return strings&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;g(a, b) = a + b&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## g (generic function with 1 method)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;g(a::Int, b::String) = &amp;quot;unnamed int, string: $a; $b&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## g (generic function with 2 methods)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;g(a::String, b::Int) = &amp;quot;unnamed string, int: $a; $b&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## g (generic function with 3 methods)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, depending on what types we provide in each argument, a different method is called&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;g(3, 2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 5&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;g(&amp;quot;abc&amp;quot;, 123)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;quot;unnamed string, int: abc; 123&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;g(123, &amp;quot;abc&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;quot;unnamed int, string: 123; abc&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similar to S4, but so easy to declare and use! Of course, this doesn’t work if we want these
to be named since that would be ambiguous.&lt;/p&gt;
&lt;p&gt;As I’m slowly learning APL, I’ve found it interesting that there’s a well-known approach of
writing &lt;a href=&#34;https://en.wikipedia.org/wiki/Tacit_programming&#34;&gt;“point-free” (“tacit”)&lt;/a&gt; functions which don’t specify arguments at all.&lt;/p&gt;
&lt;p&gt;Last of all, I’ve had the pleasure of dealing with C this week including passing a &lt;em&gt;pointer&lt;/em&gt;
to some object into a function, in which case the value &lt;em&gt;outside of the function&lt;/em&gt; is updated.
That’s a whole other post I’m working on.&lt;/p&gt;
&lt;p&gt;How does your favourite language use arguments? Let me know! I can be found on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; or use the comments below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-08-06
##  pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  assertthat    0.2.1   2019-03-21 [3] CRAN (R 4.0.1)
##  blogdown      1.17    2023-05-16 [1] CRAN (R 4.1.2)
##  bookdown      0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  brio          1.1.3   2021-11-30 [1] CRAN (R 4.1.2)
##  bslib         0.4.1   2022-11-02 [3] CRAN (R 4.2.2)
##  cachem        1.0.6   2021-08-19 [3] CRAN (R 4.2.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.4.1   2022-09-23 [3] CRAN (R 4.2.1)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  DBI           1.1.3   2022-06-18 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest        0.6.30  2022-10-18 [3] CRAN (R 4.2.1)
##  dplyr         1.0.10  2022-09-01 [3] CRAN (R 4.2.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.18    2022-11-07 [3] CRAN (R 4.2.2)
##  fansi         1.0.3   2022-03-24 [3] CRAN (R 4.2.0)
##  fastmap       1.1.0   2021-01-25 [3] CRAN (R 4.2.0)
##  fs            1.5.2   2021-12-08 [3] CRAN (R 4.1.2)
##  generics      0.1.3   2022-07-05 [3] CRAN (R 4.2.1)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  htmltools     0.5.3   2022-07-18 [3] CRAN (R 4.2.1)
##  htmlwidgets   1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv        1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.3   2022-10-21 [3] CRAN (R 4.2.1)
##  JuliaCall     0.17.5  2022-09-08 [1] CRAN (R 4.1.2)
##  knitr         1.40    2022-08-24 [3] CRAN (R 4.2.1)
##  later         1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  pillar        1.8.1   2022-08-19 [3] CRAN (R 4.2.1)
##  pkgbuild      1.4.0   2022-11-27 [1] CRAN (R 4.1.2)
##  pkgconfig     2.0.3   2019-09-22 [3] CRAN (R 4.0.1)
##  pkgload       1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.8.0   2022-10-26 [3] CRAN (R 4.2.1)
##  profvis       0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises      1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps            1.7.2   2022-10-26 [3] CRAN (R 4.2.2)
##  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rextendr    * 0.3.0   2023-05-30 [1] CRAN (R 4.1.2)
##  rlang         1.0.6   2022-09-24 [1] CRAN (R 4.1.2)
##  rmarkdown     2.18    2022-11-09 [3] CRAN (R 4.2.2)
##  rprojroot     2.0.3   2022-04-02 [1] CRAN (R 4.1.2)
##  rstudioapi    0.14    2022-08-22 [3] CRAN (R 4.2.1)
##  sass          0.4.2   2022-07-16 [3] CRAN (R 4.2.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny         1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi       1.7.8   2022-07-11 [3] CRAN (R 4.2.1)
##  stringr       1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  tibble        3.1.8   2022-07-22 [3] CRAN (R 4.2.2)
##  tidyselect    1.2.0   2022-10-10 [3] CRAN (R 4.2.1)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis       2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  utf8          1.2.2   2021-07-24 [3] CRAN (R 4.2.0)
##  vctrs         0.5.2   2023-01-23 [1] CRAN (R 4.1.2)
##  withr         2.5.0   2022-03-03 [3] CRAN (R 4.2.0)
##  xfun          0.34    2022-10-18 [3] CRAN (R 4.2.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml          2.3.6   2022-10-18 [3] CRAN (R 4.2.1)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Array Languages: R vs APL</title>
      <link>https://jcarroll.com.au/2023/07/07/array-languages-r-vs-apl/</link>
      <pubDate>Fri, 07 Jul 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/07/07/array-languages-r-vs-apl/</guid>
      <description>&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: this post was discussed late March 2024 on
&lt;a href=&#34;https://news.ycombinator.com/item?id=39771878&#34;&gt;HackerNews&lt;/a&gt; and &lt;a href=&#34;https://lobste.rs/s/dhwo8a/array_languages_r_vs_apl&#34;&gt;lobste.rs&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I’ve been learning at least one new programming language a month through
&lt;a href=&#34;https://exercism.org/&#34;&gt;Exercism&lt;/a&gt; which has been really fun and interesting. I frequently say that “every language you learn teaches you something about all the
others you know” and with nearly a dozen under my belt so far I’m starting to worry about the combinatorics of that statement.&lt;/p&gt;
&lt;p&gt;APL isn’t on the list of languages but I’ve seen it in &lt;a href=&#34;https://codegolf.stackexchange.com/&#34;&gt;codegolf&lt;/a&gt; solutions often enough that it
seemed worth a look.&lt;/p&gt;
&lt;p&gt;Now, when I say “learning” I mean “good enough to do 5 toy exercises” which is
what you need to do to in order to earn the badge for that month in the &lt;a href=&#34;https://exercism.org/challenges/12in23&#34;&gt;“#12in23
challenge”&lt;/a&gt; (gamification FTW). That’s often
sufficient for me to get a taste for the language and see if it’s something I’d
like to dive deeper into.&lt;/p&gt;
&lt;p&gt;It means I’ve been watching a lot of “&amp;lt;language&amp;gt; beginner tutorial” videos recently,
which may have been what prompted YouTube to suggest to me a video from
&lt;a href=&#34;https://www.youtube.com/@code_report&#34;&gt;code_report&lt;/a&gt;; I think &lt;a href=&#34;https://www.youtube.com/watch?v=UVUjnzpQKUo&#34;&gt;this one&lt;/a&gt;
comparing a &lt;a href=&#34;https://leetcode.com/&#34;&gt;leetcode&lt;/a&gt; solution to the problem&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;find the GCD (greatest common divisor) of the smallest and largest numbers in an array&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;written in 16 (sixteen!!!) languages. Some of those I know a little or a moderate
amount about, but one stood out. The APL solution comprises 5 glyphs (symbols)
representing operations&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      ⌈/∨⌊/&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ve seen APL solutions pop up in codegolf and they’ve just looked like madness,
which is probably fair. The linked video prompted me to look into some of their
other videos and they do a great job explaining the glyphs in APL and how they
compare to other languages. It turns out this madness is not nearly as hard to
read as it looks. The above glyphs represent “maximum” (⌈), “reduce” (/), “GCD”
(∨), and “minimum” (⌊) and those all correspond well to the problem statement.
The function itself is
&lt;a href=&#34;https://en.wikipedia.org/wiki/Tacit_programming&#34;&gt;“point-free”&lt;/a&gt; whereby the
argument(s) aren’t specified at all; like saying &lt;code&gt;mean&lt;/code&gt; rather than &lt;code&gt;mean(x)&lt;/code&gt;.
For the truly adventurous: &lt;a href=&#34;https://blog.devgenius.io/the-hideous-beauty-of-point-free-programming-e8608e3df09d&#34;&gt;‘The Hideous Beauty of Point-Free Programming; An
exercise in combinators using
Haskell’&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I ended up diving deeper and deeper, and it all started to make more and more sense.&lt;/p&gt;
&lt;p&gt;In a recent stream, &lt;a href=&#34;https://www.youtube.com/@ThePrimeagen&#34;&gt;ThePrimeagen&lt;/a&gt; responded
to the comment about some language that “&amp;lt;x&amp;gt; is more readable” with “readability is
just familiarity” and that stuck with me - I’m not entirely sure I 100% agree with it
because I can find several ways to write some code that someone familiar with that
language will either find easy or hard to read, despite familiarity. I think {dplyr} in R
does a fantastic job of abstracting operations with verbs and making data pipelines
easy to comprehend, certainly much more than the base-equivalent code.&lt;/p&gt;
&lt;p&gt;So, would APL be “readable” if I was more familiar with it? Let’s find out!&lt;/p&gt;
&lt;p&gt;There aren’t &lt;em&gt;that&lt;/em&gt; many glyphs in APL - there are far more unique functions in
most big libraries from any mainstream language. Looking at the top of the ‘ride’
editor for Dyalog APL there are 80 glyphs. To make a slightly unfair example, there
are a lot of exported functions (288 of them) in {dplyr}…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;packageVersion(&amp;quot;dplyr&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;#39;1.0.10&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ns &amp;lt;- sort(getNamespaceExports(&amp;quot;dplyr&amp;quot;))
head(ns, 20)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] &amp;quot;.data&amp;quot;        &amp;quot;%&amp;gt;%&amp;quot;          &amp;quot;across&amp;quot;       &amp;quot;add_count&amp;quot;    &amp;quot;add_count_&amp;quot;  
##  [6] &amp;quot;add_row&amp;quot;      &amp;quot;add_rownames&amp;quot; &amp;quot;add_tally&amp;quot;    &amp;quot;add_tally_&amp;quot;   &amp;quot;all_equal&amp;quot;   
## [11] &amp;quot;all_of&amp;quot;       &amp;quot;all_vars&amp;quot;     &amp;quot;anti_join&amp;quot;    &amp;quot;any_of&amp;quot;       &amp;quot;any_vars&amp;quot;    
## [16] &amp;quot;arrange&amp;quot;      &amp;quot;arrange_&amp;quot;     &amp;quot;arrange_all&amp;quot;  &amp;quot;arrange_at&amp;quot;   &amp;quot;arrange_if&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;tail(ns, 20)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] &amp;quot;tbl_vars&amp;quot;            &amp;quot;tibble&amp;quot;              &amp;quot;top_frac&amp;quot;           
##  [4] &amp;quot;top_n&amp;quot;               &amp;quot;transmute&amp;quot;           &amp;quot;transmute_&amp;quot;         
##  [7] &amp;quot;transmute_all&amp;quot;       &amp;quot;transmute_at&amp;quot;        &amp;quot;transmute_if&amp;quot;       
## [10] &amp;quot;tribble&amp;quot;             &amp;quot;type_sum&amp;quot;            &amp;quot;ungroup&amp;quot;            
## [13] &amp;quot;union&amp;quot;               &amp;quot;union_all&amp;quot;           &amp;quot;validate_grouped_df&amp;quot;
## [16] &amp;quot;validate_rowwise_df&amp;quot; &amp;quot;vars&amp;quot;                &amp;quot;with_groups&amp;quot;        
## [19] &amp;quot;with_order&amp;quot;          &amp;quot;wrap_dbplyr_obj&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Taking the functions listed as &lt;code&gt;S3method&lt;/code&gt; or &lt;code&gt;export&lt;/code&gt; in the
&lt;a href=&#34;https://github.com/tidyverse/dplyr/blob/main/NAMESPACE&#34;&gt;&lt;code&gt;NAMESPACE&lt;/code&gt;&lt;/a&gt;
file is 470+. Sure, these aren’t &lt;em&gt;all&lt;/em&gt; user-facing, but still. Lots.&lt;/p&gt;
&lt;p&gt;So, 80 isn’t a “huge” number, if that’s the &lt;strong&gt;entire language&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I watched some more videos about what the glyphs mean and how they work. I
started to become slightly familiar with what they mean. Learning is done with
the hands, not the eyes, though - as &lt;a href=&#34;https://giansegato.com/essays/edutainment-is-not-learning&#34;&gt;this (not new) blog post&lt;/a&gt; goes into great
detail on, so
I felt that I needed to actually write something. I installed Dyalog APL and the
ride editor (given that it uses glyphs, a non-standard editor seems to make sense;
I’ve otherwise been completing the Exercism solutions in emacs). I also found &lt;a href=&#34;https://tryapl.org&#34;&gt;tryapl.org&lt;/a&gt; as an online editor.&lt;/p&gt;
&lt;p&gt;The first step was to just follow along what I’d seen in the videos. I had
most recently watched &lt;a href=&#34;https://www.youtube.com/watch?v=8ynsN4nJxzU&#34;&gt;this one&lt;/a&gt; that
does include a comparison to R (and Julia) so I tried to recreate what I’d seen
built up. I was shocked that I actually could!&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/49288d6d46f5baac.png&#34; alt=&#34;Recreating construction of an X-matrix in APL using tryapl.org&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Recreating construction of an X-matrix in APL using tryapl.org&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;From reshaping into a matrix, to building up the sequence, to inserting the
combinator - it all came together easily enough.&lt;/p&gt;
&lt;p&gt;On “combinators” - if you aren’t familiar with Lambda Calculus and have a spare hour,
&lt;a href=&#34;https://youtu.be/3VQ382QG-y4&#34;&gt;this&lt;/a&gt; is a wonderful talk explaining the basics
and demonstrating them using JavaScript.&lt;/p&gt;
&lt;p&gt;More videos, more learning. I found &lt;a href=&#34;https://youtu.be/MKb4WD6mioE&#34;&gt;this one&lt;/a&gt;
which is another leetcode problem which was roughly&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;find the maximum value of the sum of rows of a matrix&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That sounded like something R would easily handle, but this particular
video didn’t feature R. It &lt;em&gt;did&lt;/em&gt; feature C++, the solution for which
requires two &lt;code&gt;for&lt;/code&gt; loops and looked (to me) horrific - I’m used to just
passing a matrix to an R function and not having to worry about loops.&lt;/p&gt;
&lt;p&gt;I’ve had many discussions on this topic because for whatever reason, &lt;code&gt;for&lt;/code&gt;
loops have a particular reputation in R despite them not (necessarily) being
any worse than any other solution. The short response is that if you’re using one
when you could be using vectorisation, you’re probably stating your problem poorly
and can do better (in terms of readability, performance, or both). &lt;a href=&#34;https://youtu.be/TdbweYvwnss&#34;&gt;This video&lt;/a&gt;
covers the points really nicely.&lt;/p&gt;
&lt;p&gt;Jenny Bryan &lt;a href=&#34;https://speakerdeck.com/jennybc/row-oriented-workflows-in-r-with-the-tidyverse?slide=16&#34;&gt;made the point&lt;/a&gt; that&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Of course someone has to write loops… It doesn’t have to be you&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;alluding to the fact that vectorisation (either with the &lt;code&gt;*apply&lt;/code&gt; family or &lt;code&gt;purrr&lt;/code&gt;)
still has a C loop buried within (I covered some of this myself in &lt;a href=&#34;https://jcarroll.com.au/2022/04/22/where-for-loop-art-thou/&#34;&gt;another post&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://fosstodon.org/@milesmcbain/110658467908744395&#34;&gt;Miles McBain makes a point of never using them&lt;/a&gt; (directly).&lt;/p&gt;
&lt;p&gt;Okay, so, returning to the leetcode problem. The APL solution in the video is
reshaping (&lt;code&gt;⍴&lt;/code&gt;) a vector to a matrix then reducing (&lt;code&gt;/&lt;/code&gt;) addition (&lt;code&gt;+&lt;/code&gt;) across rows (last-axis; c.f. first axis would be &lt;code&gt;+⌿&lt;/code&gt;) and reducing (&lt;code&gt;/&lt;/code&gt;) that with maximum (&lt;code&gt;⌈&lt;/code&gt;)
making the entire solution&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      x ← 3 3⍴1 2 3 5 5 5 3 1 4
      ⌈/+/x
 15&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is an elegant, compact solution. APL agrees to ignore the &lt;code&gt;[1]&lt;/code&gt; at the
start of R’s default output if R agrees to ignore the odd indenting of APL commands.&lt;/p&gt;
&lt;p&gt;As a sidenote: I &lt;strong&gt;love&lt;/strong&gt; that I finally get to use the OG assignment arrow &lt;code&gt;←&lt;/code&gt;
that inspired the usage in R (as &lt;code&gt;&amp;lt;-&lt;/code&gt;). This isn’t some ligature font, it’s the
actual arrow glyph with Unicode code point U+2190. The APL keyboard has this on
a key and that was common around the time that it made it into R (or S).&lt;/p&gt;
&lt;p&gt;The video explains that this solution is
particularly nice because it’s explicit that two “reduce” operations
are occurring. The &lt;code&gt;+&lt;/code&gt; operator in APL can be either unary (takes 1 argument) or
binary (takes 2 arguments) but it can’t loop over an entire vector. To achieve that,
it’s combined with &lt;code&gt;/&lt;/code&gt; which performs “reduce”, essentially applying &lt;code&gt;+&lt;/code&gt; across
the input.&lt;/p&gt;
&lt;p&gt;It’s a fairly straightforward answer with R, too:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- matrix(c(1, 2, 3,
              5, 5, 5,
              3, 1, 4),
            3, 3, byrow = TRUE)
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    5    5    5
## [3,]    3    1    4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;max(rowSums(a))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 15&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and done. Nice. No &lt;code&gt;for&lt;/code&gt; loops. Or are there? Of course there are, somewhere, but
can we write this “like” the APL solution and be more explicit with the “reduce”
steps over binary operators? R has a &lt;code&gt;Reduce()&lt;/code&gt; function for exactly this case.&lt;/p&gt;
&lt;p&gt;A simplified &lt;code&gt;rowSums()&lt;/code&gt; function could just be applying the &lt;code&gt;sum&lt;/code&gt; operation to
the rows of the matrix&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;s &amp;lt;- function(x) apply(x, 1, sum)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but &lt;code&gt;sum(x)&lt;/code&gt; is itself vectorised - it’s an application of the binary &lt;code&gt;+&lt;/code&gt; operation
across a vector, so really we could have&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;s &amp;lt;- function(x) apply(x, 1, \(y) Reduce(`+`, y))
s(a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]  6 15  8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This isn’t so bad compared to APL which “naturally” performs the reduction
over that dimension. Compare (&lt;code&gt;⍝&lt;/code&gt; signifies a comment):&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      x
1 2 3
5 5 5
3 1 4

⍝ &amp;quot;rowSums&amp;quot;

      +/x
6 15 8

⍝ &amp;quot;colSums&amp;quot;

      +⌿x
9 8 12&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s nothing here that says &lt;code&gt;x&lt;/code&gt; &lt;em&gt;needs&lt;/em&gt; to have more than 1 dimension, though -
it’s the same operator(s) on a vector, just that they do the same thing&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      +/(1 2 3)
6
      +⌿(1 2 3)
6&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;max&lt;/code&gt; is also vectorised, so a simple, ostensibly binary version of that could be&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m &amp;lt;- function(x, y) ifelse(x &amp;gt; y, x, y)
m(1, 2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m(4, 2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Together, an R solution using these could be&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Reduce(m, s(a))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 15&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which, if we shortened &lt;code&gt;Reduce&lt;/code&gt; to a single character&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;R &amp;lt;- Reduce&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;would be&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;R(m, s(a))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 15&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s not a lot more characters than APL. I’ve abstracted at least one of the functions, though - APL uses the operators directly, in which case we’d have&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;maxWealth &amp;lt;- \(x) R(m, apply(x, 1, \(y) R(`+`, y)))
maxWealth(a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 15&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s &lt;em&gt;only&lt;/em&gt; using &lt;code&gt;Reduce&lt;/code&gt;, binary &lt;code&gt;+&lt;/code&gt;, a simplified &lt;code&gt;max&lt;/code&gt; (which we could
imagine was a built-in we could shorten to &lt;code&gt;m&lt;/code&gt;), and the &lt;code&gt;apply&lt;/code&gt; over rows.&lt;/p&gt;
&lt;p&gt;Comparing these directly (with some artistic license):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; m R + R
 ⌈ / + /&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The point of this whole exercise wasn’t to rebuild the APL solution in R - it
was to think more deeply about what abstractions R offers and how they compare
to a language that uses (only) the atomic constructs directly.&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;love&lt;/em&gt; that in R I can pass either individual values or a vector to &lt;code&gt;sum&lt;/code&gt;
and it “just deals with it”&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sum(4, 5, 6) # sum some &amp;quot;scalars&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 15&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;vals &amp;lt;- c(4, 5, 6)
sum(vals) # sum a vector&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 15&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ability to hide/abstract the looping over dimensions and to work directly with
objects with more than one dimension is what &lt;a href=&#34;https://en.wikipedia.org/wiki/Array_programming#R&#34;&gt;qualifies R as an “array language”&lt;/a&gt;.
This is also (mimicking, perhaps) &lt;a href=&#34;https://www.jernesto.com/articles/rapl.html&#34;&gt;“rank polymorphism”&lt;/a&gt; which APL does have. Julia
gets around this with “broadcasting”. But, at least in R, this hides/abstracts some of what is happening, and sometimes/often, that’s a &lt;code&gt;for&lt;/code&gt; loop.&lt;/p&gt;
&lt;p&gt;Does every programmer need to know the gory details? Absolutely not. Might it be
useful for gaining a better understanding of the language and how to work with it?
I really think it is. It’s why I’m digging further and further into functional
programming in general.&lt;/p&gt;
&lt;p&gt;I do believe that the APL solution is more explicit in what it’s doing; that it
doesn’t hide (much, if any) of the implementation details. I’m comfortable
with the abstractions in R and will continue to write R for this reason, but if
I had a need to do some array math in any other language, I now feel like APL
really does have a lot to offer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bonus Round&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I was thinking about the leetcode problem and thought that a slightly more
complex version would be to return “which row has the maximum?” rather than
the maximum itself.&lt;/p&gt;
&lt;p&gt;In R, there is another useful function to achieve this&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;which.max(rowSums(a))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so, have I learned enough APL to do this myself?&lt;/p&gt;
&lt;p&gt;There’s a “Grade Down” operator (&lt;code&gt;⍒&lt;/code&gt;) which seems equivalent to R’s
&lt;code&gt;order(decreasing = TRUE)&lt;/code&gt; and a “First” operator (&lt;code&gt;⊃&lt;/code&gt;) like &lt;code&gt;head(n = 1)&lt;/code&gt;
so a solution seems to be to get the indices of the sorted (decreasing)
elements then take the first one&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      ⊃⍒+/x
2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Apparently an alternative would be to find the (first) element of the input (&lt;code&gt;⍵&lt;/code&gt;) that
matches the maximum which would be&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      {⍵⍳⌈/⍵}(+/x)
2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which, at least to me, isn’t as elegant.&lt;/p&gt;
&lt;p&gt;Lastly, &lt;a href=&#34;https://mastodon.social/@kjhealy/110661489858307306&#34;&gt;Kieran Healy&lt;/a&gt;
relayed to me a small algorithm for finding ‘primes smaller
than some number’ in APL which cleaned up as&lt;/p&gt;
&lt;pre class=&#34;apl&#34;&gt;&lt;code&gt;      ((⊢~∘.×⍨)1↓⍳)(50)
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This makes use of some combinators (e.g. the C-combinator &lt;code&gt;⍨&lt;/code&gt; - possibly the
coolest glyph in the entire system),
but roughly involves filtering values not (&lt;code&gt;~&lt;/code&gt;)
members (&lt;code&gt;∈&lt;/code&gt;) of values produced by the outer (&lt;code&gt;º&lt;/code&gt;) product (&lt;code&gt;.&lt;/code&gt;) using
multiplication (&lt;code&gt;×&lt;/code&gt;) (i.e. numbers that can be made by multiplying other
numbers) from the sequence (&lt;code&gt;⍳&lt;/code&gt;) from 2 to some value (dropping (&lt;code&gt;↓&lt;/code&gt;) 1;
&lt;code&gt;3↓⍳8 == 4:8&lt;/code&gt;). With the small amount I’ve learned - mostly from watching
someone else use the language - I was able to decipher at least &lt;em&gt;what&lt;/em&gt; the
operators were in all of that, even if I probably couldn’t come up with the
solution myself.&lt;/p&gt;
&lt;p&gt;I’m happy to call that “readable”.&lt;/p&gt;
&lt;p&gt;I looked around for code to generate the primes below some number in R. I couldn’t (easily) find one that worked without an explicit loop. I found
a version in &lt;a href=&#34;https://github.com/mmaechler/sfsmisc/blob/81015322032edd9f900e5103ac11c70de49619bd/R/prime-numbers-fn.R#L15-L31&#34;&gt;{sfsmisc}&lt;/a&gt; which compacts to&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;primes. &amp;lt;- function(n) {
  ## By Bill Venables &amp;lt;= 2001
  x &amp;lt;- 1:n
  x[1] &amp;lt;- 0
  p &amp;lt;- 1
  while((p &amp;lt;- p + 1) &amp;lt;= floor(sqrt(n)))
    if(x[p] != 0)
      x[seq(p^2, n, p)] &amp;lt;- 0
  x[x &amp;gt; 0]
}
primes.(50)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1]  2  3  5  7 11 13 17 19 23 29 31 37 41 43 47&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Taking inspiration from the APL solution, though - what if we just generate all
products from the set of numbers &lt;code&gt;2:n&lt;/code&gt; and exclude those as “not prime” from all
the numbers up to &lt;code&gt;n&lt;/code&gt;?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;primes &amp;lt;- function(n) {
  s &amp;lt;- 2:n
  setdiff(s, c(outer(s, s, `*`)))
}
primes(50)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1]  2  3  5  7 11 13 17 19 23 29 31 37 41 43 47&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That… works! It’s slower and uses more memory, for sure, but that wasn’t
our criteria, and isn’t relevant for a once-off evaluation. Even better - I can
“read” exactly what it’s doing.&lt;/p&gt;
&lt;p&gt;I’ve learned a lot and I’ll continue to learn more about APL because I really do
think that understanding how these operators come together to build a function
will be enlightening in terms of a functional approach.&lt;/p&gt;
&lt;p&gt;I still haven’t made it to trying out BQN (&lt;em&gt;almost&lt;/em&gt; constructed by incrementing
each letter of APL, &lt;code&gt;IBM -&amp;gt; HAL&lt;/code&gt; style, but perhaps officially
&lt;a href=&#34;https://mlochbaum.github.io/BQN/&#34;&gt;“Big Questions Notation”&lt;/a&gt;, and sometimes
pronounced “bacon”) but it sounds like it has some newer improvements over APL
and will be worth a try.&lt;/p&gt;
&lt;p&gt;As always, comments and discussions are welcome here or on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-07-07
##  pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  assertthat    0.2.1   2019-03-21 [3] CRAN (R 4.0.1)
##  blogdown      1.17    2023-05-16 [1] CRAN (R 4.1.2)
##  bookdown      0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  bslib         0.4.1   2022-11-02 [3] CRAN (R 4.2.2)
##  cachem        1.0.6   2021-08-19 [3] CRAN (R 4.2.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.4.1   2022-09-23 [3] CRAN (R 4.2.1)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  DBI           1.1.3   2022-06-18 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest        0.6.30  2022-10-18 [3] CRAN (R 4.2.1)
##  dplyr         1.0.10  2022-09-01 [3] CRAN (R 4.2.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.18    2022-11-07 [3] CRAN (R 4.2.2)
##  fansi         1.0.3   2022-03-24 [3] CRAN (R 4.2.0)
##  fastmap       1.1.0   2021-01-25 [3] CRAN (R 4.2.0)
##  fs            1.5.2   2021-12-08 [3] CRAN (R 4.1.2)
##  generics      0.1.3   2022-07-05 [3] CRAN (R 4.2.1)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  htmltools     0.5.3   2022-07-18 [3] CRAN (R 4.2.1)
##  htmlwidgets   1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv        1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.3   2022-10-21 [3] CRAN (R 4.2.1)
##  knitr         1.40    2022-08-24 [3] CRAN (R 4.2.1)
##  later         1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  pillar        1.8.1   2022-08-19 [3] CRAN (R 4.2.1)
##  pkgbuild      1.4.0   2022-11-27 [1] CRAN (R 4.1.2)
##  pkgconfig     2.0.3   2019-09-22 [3] CRAN (R 4.0.1)
##  pkgload       1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.8.0   2022-10-26 [3] CRAN (R 4.2.1)
##  profvis       0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises      1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps            1.7.2   2022-10-26 [3] CRAN (R 4.2.2)
##  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.0.6   2022-09-24 [1] CRAN (R 4.1.2)
##  rmarkdown     2.18    2022-11-09 [3] CRAN (R 4.2.2)
##  rstudioapi    0.14    2022-08-22 [3] CRAN (R 4.2.1)
##  sass          0.4.2   2022-07-16 [3] CRAN (R 4.2.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny         1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi       1.7.8   2022-07-11 [3] CRAN (R 4.2.1)
##  stringr       1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  tibble        3.1.8   2022-07-22 [3] CRAN (R 4.2.2)
##  tidyselect    1.2.0   2022-10-10 [3] CRAN (R 4.2.1)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis       2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  utf8          1.2.2   2021-07-24 [3] CRAN (R 4.2.0)
##  vctrs         0.5.2   2023-01-23 [1] CRAN (R 4.1.2)
##  xfun          0.34    2022-10-18 [3] CRAN (R 4.2.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml          2.3.6   2022-10-18 [3] CRAN (R 4.2.1)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Reflecting on Macros</title>
      <link>https://jcarroll.com.au/2023/06/10/reflecting-on-macros/</link>
      <pubDate>Sat, 10 Jun 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/06/10/reflecting-on-macros/</guid>
      <description>&lt;p&gt;I’ve been following the drama of the RustConf Keynote Fiasco (RKNF, per &lt;a href=&#34;https://fasterthanli.me/articles/the-rustconf-keynote-fiasco-explained&#34;&gt;@fasterthanlime&lt;/a&gt;)
from a great distance - I’m not involved in that community beyond starting to learn
the language. But the controversial topic itself &lt;a href=&#34;https://soasis.org/posts/a-mirror-for-rust-a-plan-for-generic-compile-time-introspection-in-rust/&#34;&gt;Compile-Time Reflection&lt;/a&gt; seemed like something interesting I could learn something about.&lt;/p&gt;
&lt;p&gt;A good start is usually a Wikipedia page, and I found one called &lt;a href=&#34;https://en.wikipedia.org/wiki/Reflective_programming&#34;&gt;“Reflective programming”&lt;/a&gt; under the “MetaProgramming”
category, where it defines&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;reflection is the ability of a process to examine, introspect, and modify its own structure and behavior&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That sounds somewhat familiar from what metaprogramming I’ve read about. One of the
great features of R is the ability to inspect and rewrite functions, for example,
the body of the &lt;code&gt;sd()&lt;/code&gt; function (calculating the standard deviation of the input) looks
like&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sd&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## function (x, na.rm = FALSE) 
## sqrt(var(if (is.vector(x) || is.factor(x)) x else as.double(x), 
##     na.rm = na.rm))
## &amp;lt;bytecode: 0x5647347e3980&amp;gt;
## &amp;lt;environment: namespace:stats&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Trying to extract a “component” of that function results in the ever-classic error&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sd[1]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in sd[1]: object of type &amp;#39;closure&amp;#39; is not subsettable&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;However&lt;/em&gt;, using &lt;code&gt;body()&lt;/code&gt; we &lt;em&gt;can&lt;/em&gt; get to the components of the function&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;body(sd)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## sqrt(var(if (is.vector(x) || is.factor(x)) x else as.double(x), 
##     na.rm = na.rm))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;body(sd)[1]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## sqrt()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and we can even mess with it (meaninglessly, in this case)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;vals &amp;lt;- c(1, 3, 5, 7)
sd(vals)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2.581989&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;my_sd &amp;lt;- sd
body(my_sd)[1] &amp;lt;- call(&amp;quot;log&amp;quot;)
my_sd # note that the function now (wrongly) uses log() instead of sqrt()&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## function (x, na.rm = FALSE) 
## log(var(if (is.vector(x) || is.factor(x)) x else as.double(x), 
##     na.rm = na.rm))
## &amp;lt;environment: namespace:stats&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;my_sd(vals)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1.89712&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Wikipedia page lists the following example of reflection in R&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Without reflection, assuming foo() returns an S3-type object that has method &amp;quot;hello&amp;quot;
obj &amp;lt;- foo()
hello(obj)

# With reflection
class_name &amp;lt;- &amp;quot;foo&amp;quot;
generic_having_foo_method &amp;lt;- &amp;quot;hello&amp;quot;
obj &amp;lt;- do.call(class_name, list())
do.call(generic_having_foo_method, alist(obj))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using a more concrete data object and class, e.g. &lt;code&gt;tibble::tibble&lt;/code&gt; and &lt;code&gt;summary&lt;/code&gt; might be
clearer&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(tibble) # do.call doesn&amp;#39;t like pkg::fun as a string

# Without reflection
obj &amp;lt;- tibble(a = 1:2, b = 3:4)
summary(obj)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##        a              b       
##  Min.   :1.00   Min.   :3.00  
##  1st Qu.:1.25   1st Qu.:3.25  
##  Median :1.50   Median :3.50  
##  Mean   :1.50   Mean   :3.50  
##  3rd Qu.:1.75   3rd Qu.:3.75  
##  Max.   :2.00   Max.   :4.00&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# With reflection
class_name &amp;lt;- &amp;quot;tibble&amp;quot;
generic_having_foo_method &amp;lt;- &amp;quot;summary&amp;quot;
obj &amp;lt;- do.call(class_name, list(a = 1:2, b = 3:4))
obj&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 2 × 2
##       a     b
##   &amp;lt;int&amp;gt; &amp;lt;int&amp;gt;
## 1     1     3
## 2     2     4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;do.call(generic_having_foo_method, alist(obj))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##        a              b       
##  Min.   :1.00   Min.   :3.00  
##  1st Qu.:1.25   1st Qu.:3.25  
##  Median :1.50   Median :3.50  
##  Mean   :1.50   Mean   :3.50  
##  3rd Qu.:1.75   3rd Qu.:3.75  
##  Max.   :2.00   Max.   :4.00&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, maybe it’s more to do with being able to use a string containing the “name” of
a function and go and find that function, or just the ability to generate functions
on-demand based on non-function objects (?). Please, let me know if there’s a more
enlightening explanation.&lt;/p&gt;
&lt;p&gt;I still don’t think I understand that at all (more time required) but I did note in
some additional research that “reflection” and “macros” are two very similar concepts. Now
macros &lt;em&gt;are&lt;/em&gt; something I’ve heard of at least, so I was off to do some more research.&lt;/p&gt;
&lt;p&gt;Unfortunately, web searches for the terms “reflection” and “macro” turn up a lot of
macro-lens photography results.&lt;/p&gt;
&lt;p&gt;I’ve heard of macros in Julia where they’re used to “rewrite” an expression. &lt;a href=&#34;https://jkrumbiegel.com/pages/2021-06-07-macros-for-beginners/&#34;&gt;This&lt;/a&gt; is a nice rundown
of the process, as are the &lt;a href=&#34;https://docs.julialang.org/en/v1/manual/metaprogramming/#man-macros&#34;&gt;official docs&lt;/a&gt;. These are
used in many places. One up-and-coming place is the new &lt;a href=&#34;https://github.com/TidierOrg/Tidier.jl&#34;&gt;Tidier.jl&lt;/a&gt; which implements the &lt;a href=&#34;https://www.tidyverse.org/&#34;&gt;tidyverse&lt;/a&gt; (at least the most common &lt;code&gt;dplyr&lt;/code&gt; and &lt;code&gt;purrr&lt;/code&gt; parts)
using macros (denoted with a &lt;code&gt;@&lt;/code&gt; prefix)&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;using Tidier
using RDatasets

movies = dataset(&amp;quot;ggplot2&amp;quot;, &amp;quot;movies&amp;quot;);

@chain movies begin
    @mutate(Budget = Budget / 1_000_000)
    @filter(Budget &amp;gt;= mean(skipmissing(Budget)))
    @select(Title, Budget)
    @slice(1:5)
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rust uses macros for printing (amongst other things); &lt;code&gt;println!()&lt;/code&gt; is a macro,
apparently at least in part because it needs to be able to take an arbitrary
number of args, so one can write&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt; println!(&amp;quot;a = {}, b = {}, c = {}&amp;quot;, 1, 2, 3)
a = 1, b = 2, c = 3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rust has a shorthand macro for creating a &lt;a href=&#34;https://doc.rust-lang.org/std/macro.vec.html&#34;&gt;new vector &lt;code&gt;vec!()&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt; let v = vec![2, 3, 4];&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and also has the &lt;a href=&#34;https://doc.rust-lang.org/std/macro.dbg.html&#34;&gt;“debug macro” &lt;code&gt;dbg!()&lt;/code&gt;&lt;/a&gt;
which is super handy - it prints out the expression you wrap, plus the value, so
you can inspect the current state with e.g.&lt;/p&gt;
&lt;pre class=&#34;rust&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt; dbg!(&amp;amp;v);
[src/lib.rs:109] &amp;amp;v = [
    2,
    3,
    4,
]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This last one would be great to have in R… as a side note, we could construct a
simple version with {rlang}&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dbg &amp;lt;- function(x) {
  ex &amp;lt;- rlang::f_text(rlang::enquos(x)[[1]])
  ret &amp;lt;- rlang::eval_bare(x)
  message(glue::glue(&amp;quot;DEBUG: {ex} = {ret}&amp;quot;))
  ret
}

a &amp;lt;- 1
b &amp;lt;- 3
x &amp;lt;- dbg(a + b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## DEBUG: a + b = 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;y &amp;lt;- dbg(2*x + 3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## DEBUG: 2 * x + 3 = 11&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;z &amp;lt;- 10 + dbg(y*2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## DEBUG: y * 2 = 22&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In all of these examples of macros, the code that is &lt;em&gt;run&lt;/em&gt; is different to the code you &lt;em&gt;write&lt;/em&gt;
because the macro makes some changes before executing.&lt;/p&gt;
&lt;p&gt;In R there isn’t a “proper” way to do this but we &lt;em&gt;do&lt;/em&gt; have ways to manipulate code
and we &lt;em&gt;do&lt;/em&gt; have ways to retrieve “unparsed” input, e.g. &lt;code&gt;substitute()&lt;/code&gt;. A quick look
for “macros in R” turned up a function in a package that is more than 20 years old (I was
only starting University when this came out and knew approximately 0 programming) and
comes with a &lt;a href=&#34;https://www.r-project.org/doc/Rnews/Rnews_2001-3.pdf&#34;&gt;journal article&lt;/a&gt;; &lt;code&gt;gtools::defmacro()&lt;/code&gt; by &lt;a href=&#34;https://fosstodon.org/@tslumley@wandering.shop&#34;&gt;Thomas Lumley&lt;/a&gt;
has a construction for writing something that behaves like a macro.&lt;/p&gt;
&lt;p&gt;That article is from 2001 when R 1.3.1 was being released. The example code made me do a double-take&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(gtools)

####
# macro for replacing a specified missing value indicator with NA
# within a dataframe
###
setNA &amp;lt;- defmacro(df, var, values,
  expr = {
    df$var[df$var %in% values] &amp;lt;- NA
  }
)

# create example data using 999 as a missing value indicator
d &amp;lt;- data.frame(
  Grp = c(&amp;quot;Trt&amp;quot;, &amp;quot;Ctl&amp;quot;, &amp;quot;Ctl&amp;quot;, &amp;quot;Trt&amp;quot;, &amp;quot;Ctl&amp;quot;, &amp;quot;Ctl&amp;quot;, &amp;quot;Trt&amp;quot;, &amp;quot;Ctl&amp;quot;, &amp;quot;Trt&amp;quot;, &amp;quot;Ctl&amp;quot;),
  V1 = c(1, 2, 3, 4, 5, 6, 999, 8, 9, 10),
  V2 = c(1, 1, 1, 1, 1, 2, 999, 2, 999, 999),
  stringsAsFactors = TRUE
)
d&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##    Grp  V1  V2
## 1  Trt   1   1
## 2  Ctl   2   1
## 3  Ctl   3   1
## 4  Trt   4   1
## 5  Ctl   5   1
## 6  Ctl   6   2
## 7  Trt 999 999
## 8  Ctl   8   2
## 9  Trt   9 999
## 10 Ctl  10 999&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Try it out
setNA(d, V1, 999)
setNA(d, V2, 999)
d&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##    Grp V1 V2
## 1  Trt  1  1
## 2  Ctl  2  1
## 3  Ctl  3  1
## 4  Trt  4  1
## 5  Ctl  5  1
## 6  Ctl  6  2
## 7  Trt NA NA
## 8  Ctl  8  2
## 9  Trt  9 NA
## 10 Ctl 10 NA&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wait - I thought… there’s no assignment in those last lines, but the data is
being modified!?! Sure enough, the internals of &lt;code&gt;defmacro&lt;/code&gt; make it clear that this
is the case, but it seemed like magic. Essentially, this identifies what needs to
happen, what it needs to happen to (via &lt;code&gt;substitute()&lt;/code&gt;), and makes it happen in the &lt;code&gt;parent.frame()&lt;/code&gt;. Neat! So, what else can we do with this?&lt;/p&gt;
&lt;p&gt;I thought about it for a while and realised what could be a [te|ho]rrific one…&lt;/p&gt;
&lt;p&gt;Just a couple of weeks ago, Danielle Navarro &lt;a href=&#34;https://fosstodon.org/@djnavarro/110455537858873633&#34;&gt;made a wish&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;not for the first time I find myself wishing that push() and pop() were S3 generics in #rstats&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, if you’re not familiar with those, &lt;code&gt;pop(x)&lt;/code&gt; removes the first element of a structure &lt;code&gt;x&lt;/code&gt; (e.g. a vector) and returns that first value, leaving the original object &lt;code&gt;x&lt;/code&gt; containing only the remaining elements, whereas &lt;code&gt;push(x, y)&lt;/code&gt; inserts the value &lt;code&gt;y&lt;/code&gt; as the first element of &lt;code&gt;x&lt;/code&gt;, moving the remaining elements down the line. These show up more in object-oriented languages, but they
don’t exist in R.&lt;/p&gt;
&lt;p&gt;If we define a vector &lt;code&gt;a&lt;/code&gt; containing some values&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- c(3, 1, 4, 1, 5, 9)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and we wish to extract the first value, we can certainly do so with&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a[1]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but, due to the nature of R, the vector &lt;code&gt;a&lt;/code&gt; is unchanged&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3 1 4 1 5 9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead, we could remove the first value of &lt;code&gt;a&lt;/code&gt; with&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a[-1]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 4 1 5 9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but again, &lt;code&gt;a&lt;/code&gt; remains unchanged - in order to modify &lt;code&gt;a&lt;/code&gt; we must redefine it as e.g.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- a[-1]
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 4 1 5 9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we wanted to build a &lt;code&gt;pop()&lt;/code&gt; function, we &lt;em&gt;could&lt;/em&gt; use &lt;code&gt;substitute()&lt;/code&gt; to figure out
what the passed input object was, perform the extraction of the first element, and so on…&lt;/p&gt;
&lt;p&gt;But as we’ve just seen, there’s a better way to define that - a macro!&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;r_pop &amp;lt;- gtools::defmacro(x, expr = {
  ret &amp;lt;- x[1]
  x &amp;lt;- x[-1]
  ret
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if we use that on a vector&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- c(3, 1, 4, 1, 5, 9)
r_pop(a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 4 1 5 9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works!!!&lt;/p&gt;
&lt;p&gt;Danielle wanted a Generic, though, so we can easily make &lt;code&gt;pop()&lt;/code&gt; a Generic and add methods for
some classes (which can be further extended).&lt;/p&gt;
&lt;p&gt;To that end, I present a brand new package; &lt;a href=&#34;https://github.com/jonocarroll/weasel&#34;&gt;{weasel}&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/hex-weasel.png&#34; width=&#34;300&#34; height=&#34;300&#34; alt=&#34;pop() goes the {weasel}&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;&lt;code&gt;pop()&lt;/code&gt; goes the {weasel}&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This defines &lt;code&gt;pop()&lt;/code&gt; and &lt;code&gt;push()&lt;/code&gt; as Generics with methods defined for &lt;code&gt;vector&lt;/code&gt;s, &lt;code&gt;list&lt;/code&gt;s, and &lt;code&gt;data.frame&lt;/code&gt;s&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- list(x = c(2, 3), y = c(&amp;quot;foo&amp;quot;, &amp;quot;bar&amp;quot;), z = c(3.1, 4.2, 6.9))
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## $x
## [1] 2 3
## 
## $y
## [1] &amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot;
## 
## $z
## [1] 3.1 4.2 6.9&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- pop(a)
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## $y
## [1] &amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot;
## 
## $z
## [1] 3.1 4.2 6.9&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- data.frame(x = c(2, 3, 4), y = c(&amp;quot;foo&amp;quot;, &amp;quot;bar&amp;quot;, &amp;quot;baz&amp;quot;), z = c(3.1, 4.2, 6.9))
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   x   y   z
## 1 2 foo 3.1
## 2 3 bar 4.2
## 3 4 baz 6.9&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- pop(a)
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   x   y   z
## 2 3 bar 4.2
## 3 4 baz 6.9&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   x   y   z
## 1 2 foo 3.1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- c(1, 4, 1, 5, 9)
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1 4 1 5 9&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;push(a, 3)
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3 1 4 1 5 9&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- data.frame(y = c(&amp;quot;foo&amp;quot;, &amp;quot;bar&amp;quot;, &amp;quot;baz&amp;quot;), z = c(3.1, 4.2, 6.9))
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##     y   z
## 1 foo 3.1
## 2 bar 4.2
## 3 baz 6.9&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;push(a, data.frame(y = 99, z = 77))
a&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##     y    z
## 1  99 77.0
## 2 foo  3.1
## 3 bar  4.2
## 4 baz  6.9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I wrote this (simple) package as a bit of an exercise - I really don’t think you
should actually use it for anything. The &lt;em&gt;“looks like it modifies in-place but actually
doesn’t”&lt;/em&gt; is really non-idiomatic for R. Nonetheless, I was really interested to see
that &lt;code&gt;defmacro&lt;/code&gt; can be used as a function definition that the dispatch machinery will respect. The only catch I’ve found so far is that I can’t use ellipses (&lt;code&gt;...&lt;/code&gt;) in the function signature.&lt;/p&gt;
&lt;p&gt;I noticed that &lt;a href=&#34;https://github.com/dirkschumacher&#34;&gt;Dirk Schumacher&lt;/a&gt; built a similar &lt;a href=&#34;https://github.com/dirkschumacher/defmacro&#34;&gt;&lt;code&gt;defmacro&lt;/code&gt; package&lt;/a&gt; more recently, but that appears
to be more aimed at building macros to be expanded on package load (funnily enough, “compile-time macros” - we’ve come full circle). This seems like a great opportunity for “inlining”
some functions. I’ll definitely be digging deeper into that one.&lt;/p&gt;
&lt;p&gt;Let me know if you have a better explanation of any of the concepts I’ve (badly) described here;
I’m absolutely just learning and following &lt;a href=&#34;https://jvns.ca/blog/2023/06/05/some-blogging-myths/&#34;&gt;Julia Evans’ advice about blogging&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-06-17
##  pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.17    2023-05-16 [1] CRAN (R 4.1.2)
##  bookdown      0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  bslib         0.4.1   2022-11-02 [3] CRAN (R 4.2.2)
##  cachem        1.0.6   2021-08-19 [3] CRAN (R 4.2.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.4.1   2022-09-23 [3] CRAN (R 4.2.1)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest        0.6.30  2022-10-18 [3] CRAN (R 4.2.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.18    2022-11-07 [3] CRAN (R 4.2.2)
##  fansi         1.0.3   2022-03-24 [3] CRAN (R 4.2.0)
##  fastmap       1.1.0   2021-01-25 [3] CRAN (R 4.2.0)
##  fs            1.5.2   2021-12-08 [3] CRAN (R 4.1.2)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  gtools      * 3.9.4   2022-11-27 [1] CRAN (R 4.1.2)
##  htmltools     0.5.3   2022-07-18 [3] CRAN (R 4.2.1)
##  htmlwidgets   1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv        1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.3   2022-10-21 [3] CRAN (R 4.2.1)
##  knitr         1.40    2022-08-24 [3] CRAN (R 4.2.1)
##  later         1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  pillar        1.8.1   2022-08-19 [3] CRAN (R 4.2.1)
##  pkgbuild      1.4.0   2022-11-27 [1] CRAN (R 4.1.2)
##  pkgconfig     2.0.3   2019-09-22 [3] CRAN (R 4.0.1)
##  pkgload       1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.8.0   2022-10-26 [3] CRAN (R 4.2.1)
##  profvis       0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises      1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps            1.7.2   2022-10-26 [3] CRAN (R 4.2.2)
##  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.0.6   2022-09-24 [1] CRAN (R 4.1.2)
##  rmarkdown     2.18    2022-11-09 [3] CRAN (R 4.2.2)
##  rstudioapi    0.14    2022-08-22 [3] CRAN (R 4.2.1)
##  sass          0.4.2   2022-07-16 [3] CRAN (R 4.2.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny         1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi       1.7.8   2022-07-11 [3] CRAN (R 4.2.1)
##  stringr       1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  tibble      * 3.1.8   2022-07-22 [3] CRAN (R 4.2.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis       2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  utf8          1.2.2   2021-07-24 [3] CRAN (R 4.2.0)
##  vctrs         0.5.2   2023-01-23 [1] CRAN (R 4.1.2)
##  weasel      * 0.1.0   2023-06-09 [1] local
##  xfun          0.34    2022-10-18 [3] CRAN (R 4.2.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml          2.3.6   2022-10-18 [3] CRAN (R 4.2.1)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Hyperlink Annotations in JavaScript and CSS</title>
      <link>https://jcarroll.com.au/2023/06/02/hyperlink-annotations-in-javascript-and-css/</link>
      <pubDate>Fri, 02 Jun 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/06/02/hyperlink-annotations-in-javascript-and-css/</guid>
      <description>&lt;p&gt;This might not have been difficult for a seasoned web-dev, but it was reasonably tricky
to find a clear solution online (at least it was for me) so here&amp;rsquo;s how I added the
neat domain hints next to all the hyperlinks on my blog.&lt;/p&gt;
&lt;p&gt;This might not have been difficult for a seasoned web-dev, but it was reasonably tricky
to find a clear solution online (at least it was for me) so here&amp;rsquo;s how I added the
neat domain hints next to all the hyperlinks on my blog.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m familiar with these from the &lt;a href=&#34;https://rweekly.org&#34;&gt;RWeekly&lt;/a&gt; site where hyperlinks
are annotated with the target domain -&lt;/p&gt;
&lt;img src=&#34;images/rweekly.png&#34; alt=&#34;Rweekly.org annotated hyperlinks&#34; width=&#34;600px&#34;/&gt;
&lt;div class=&#34;figcaption&#34;&gt;Rweekly.org annotated hyperlinks&lt;/div&gt;
&lt;p&gt;I find this really useful to see where a link will take me.&lt;/p&gt;
&lt;p&gt;I hadn&amp;rsquo;t looked into &lt;em&gt;how&lt;/em&gt; those were being added, but we
certainly weren&amp;rsquo;t doing it manually; we use regular markdown links like&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-md&#34; data-lang=&#34;md&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[&lt;span class=&#34;nt&#34;&gt;link description&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;https://example.com&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I recently saw a blog where these also appeared and it made me want to figure out
how to add those to mine. Trying to search for &amp;ldquo;add domain next to hyperlink&amp;rdquo; doesn&amp;rsquo;t
seem to produce much along the lines of what I was trying to do, and to make matters
worse, I wasn&amp;rsquo;t sure whether this was part of Hugo/blogdown, JavaScript, CSS, or
something else entirely.&lt;/p&gt;
&lt;p&gt;I finally got enough clues to patch together a solution and I&amp;rsquo;m pretty happy with it!&lt;/p&gt;
&lt;p&gt;My approach was to add some JavaScript (JQuery, I believe) to all built pages that inserts
the hostname of the link target in parentheses. The simple version of that looks like&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;each&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hostname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;after&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39; (&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hostname&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Breaking this down:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$(a)&lt;/code&gt; locates all instances of an anchor (&lt;code&gt;&amp;lt;a href=&amp;quot;...&amp;quot;&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.each()&lt;/code&gt; is a &lt;code&gt;map&lt;/code&gt; over each of these, which takes a function&lt;/li&gt;
&lt;li&gt;provided the &lt;code&gt;hostname&lt;/code&gt; attribute is not empty, some text is inserted &lt;code&gt;after()&lt;/code&gt; which
adds &lt;code&gt;this.hostname&lt;/code&gt;; just the base URL of the site being linked to&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Getting this sourced into my blog means placing this inside a&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ready&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;block. I added all of that to a new &lt;code&gt;links.js&lt;/code&gt; file in &lt;code&gt;static/js/&lt;/code&gt; (which I had to
create). I then edited &lt;code&gt;/layouts/partials/footer_custom.html&lt;/code&gt; to include&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;script src=&amp;#34;{{ &amp;#34;js/links.js&amp;#34; | relURL }}&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This inserts a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; line into every page, adding the path of that file
relative to the actual site. Phew.&lt;/p&gt;
&lt;p&gt;On testing that, it &lt;em&gt;does&lt;/em&gt; work, but it works for &lt;em&gt;every&lt;/em&gt; link on the page, including
those in the header, the social media share buttons&amp;hellip; everything. That&amp;rsquo;s exactly
what we asked for, of course, by selecting &lt;code&gt;$(a)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After using the &lt;code&gt;Inspect&lt;/code&gt; developer tools, I found that the main &lt;code&gt;article&lt;/code&gt; of a blog
post on my site has a &lt;code&gt;blog-post&lt;/code&gt; class, so I can filter down the annotations to
just anchors within that with&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ready&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;.blog-post a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;each&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hostname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;after&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39; (&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hostname&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Checking the output, that prevents the header links from being annotated,
but the share buttons are still within that &lt;code&gt;article&lt;/code&gt;. Excluding those
specifically just needs a &lt;code&gt;.not()&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ready&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;.blog-post a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;not&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;.share a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;each&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hostname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;after&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39; (&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hostname&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lastly, there are some annotations to my own page - those aren&amp;rsquo;t necessary
(though I suppose they don&amp;rsquo;t hurt). I can remove those from being processed
by checking if the link destination &lt;code&gt;hostname&lt;/code&gt; is the same as the current page
&lt;code&gt;hostname&lt;/code&gt; (i.e. if it&amp;rsquo;s a link to the current site or an external link)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ready&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;.blog-post a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;not&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;.share a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;each&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hostname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;location&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hostname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hostname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;after&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39; (&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hostname&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that&amp;rsquo;s it! External links are now annotated.&lt;/p&gt;
&lt;p&gt;As a last step, I decided to style these slightly differently. That means adding
a class to the added text, which I did with a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ready&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;.blog-post a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;not&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;.share a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;each&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hostname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;location&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hostname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hostname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;after&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39; &amp;lt;span class=&amp;#34;link-annot&amp;#34;&amp;gt;(&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hostname&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;)&amp;lt;/span&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Adding some CSS for this class means some of the same steps; I added a new
&lt;code&gt;static/css/links.css&lt;/code&gt; file and added&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;link-annot&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;#808080&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;font-size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;px&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;font-family&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;monospace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;to make the annotations grey, slightly smaller than the body text, and in monospace font.&lt;/p&gt;
&lt;p&gt;I made sure this was sourced into the pages by editing &lt;code&gt;/layouts/partials/head_custom.html&lt;/code&gt;
to include&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;link rel=&amp;#34;stylesheet&amp;#34; href=&amp;#34;{{ &amp;#34;css/links.css&amp;#34; | relURL }}&amp;#34; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and finally, I have what I wanted!&lt;/p&gt;
&lt;img src=&#34;images/annotations.png&#34; alt=&#34;Hyperlink annotations; automatically added and styled&#34; width=&#34;600px&#34;/&gt;
&lt;div class=&#34;figcaption&#34;&gt;Hyperlink annotations; automatically added and styled&lt;/div&gt;
&lt;p&gt;If anyone wants to do the same, all of the changes I needed to make are in &lt;a href=&#34;https://github.com/jonocarroll/jcarroll.com.au/pull/26/files&#34;&gt;this&lt;/a&gt; pull request&lt;/p&gt;
&lt;p&gt;Was there an easier way to do this? Let me know on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; or use the comments below.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Which Plot Was That?</title>
      <link>https://jcarroll.com.au/2023/05/26/which-plot-was-that/</link>
      <pubDate>Fri, 26 May 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/05/26/which-plot-was-that/</guid>
      <description>&lt;p&gt;Plotly has a nice way of making click-events available to the calling language, but
it doesn’t quite work simply when using &lt;code&gt;subplot()&lt;/code&gt;. This isn’t a post about a new
feature, but I didn’t quickly find a resource for it so I’ll add my findings to
make it easier for the next person.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://plotly.com/graphing-libraries/&#34;&gt;Plotly&lt;/a&gt; (as a graphics library) is a
JavaScript library that has been ported to R, Python, Julia, and - surprising to me -
MATLAB and F#. It provides an interactive plotting framework that works really
nicely for web-facing apps including R’s &lt;a href=&#34;https://shiny.posit.co/&#34;&gt;{shiny}&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’m currently building an internal tool at work and wanted to add some click-event-based
reactivity. Plotly supports that by registering an ‘event’ with a ‘source’ which
can be listened to with an &lt;code&gt;event_data()&lt;/code&gt; call. A simple shiny app demonstrating that
might be&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(plotly)
library(shiny)

ui &amp;lt;- basicPage(&amp;quot;&amp;quot;,
                mainPanel(
                  plotlyOutput(&amp;quot;p&amp;quot;),
                  verbatimTextOutput(&amp;quot;out&amp;quot;)
                )
)

server &amp;lt;- function(input, output, session) {
  output$p &amp;lt;- renderPlotly({
    plotly::plot_ly(data = mtcars,
                    y = ~ hp,
                    x = ~ mpg,
                    type = &amp;quot;scatter&amp;quot;,
                    mode = &amp;quot;markers&amp;quot;,
                    source = &amp;quot;click_src&amp;quot;) |&amp;gt; # default is &amp;quot;A&amp;quot;
      event_register(&amp;quot;plotly_click&amp;quot;)
  })

  output$out &amp;lt;- renderPrint({
    click_data &amp;lt;- event_data(&amp;quot;plotly_click&amp;quot;, source = &amp;quot;click_src&amp;quot;)
    req(click_data)
    message(&amp;quot;CLICK!&amp;quot;)
    click_data
  })
}

runApp(shinyApp(ui = ui, server = server))&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/p1.png&#34; width=&#34;600&#34; alt=&#34;Listening to click events in plotly&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Listening to click events in plotly&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;There’s a bit to break down here if you’re not familiar with {shiny};&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A user interface stored as &lt;code&gt;ui&lt;/code&gt; which describes how the app should “look”. In this
extremely simple case, it’s some &lt;code&gt;plotly&lt;/code&gt; output followed by some text.&lt;/li&gt;
&lt;li&gt;A server function which performs the ‘backend’ operations, sending outputs to the components
corresponding to the UI elements. In this case producing a &lt;code&gt;plotly&lt;/code&gt; plot of the &lt;code&gt;mtcars&lt;/code&gt;
dataset with a ‘scatter’ plot of the &lt;code&gt;hp&lt;/code&gt; column on the y-axis and the &lt;code&gt;mpg&lt;/code&gt; column on
the x-axis. The &lt;code&gt;source&lt;/code&gt; argument specifies a ‘label’ for the event (defaulting to &lt;code&gt;&#34;A&#34;&lt;/code&gt;
but specified as &lt;code&gt;&#34;click_src&#34;&lt;/code&gt; in this case). Finally, the ‘event’ is registered. This
example also includes a text output of the data associated with clicking on a point
in the plot, and a message the console every time that happens.&lt;/li&gt;
&lt;li&gt;A call to &lt;code&gt;runApp()&lt;/code&gt; which starts an app with the specified &lt;code&gt;ui&lt;/code&gt; and &lt;code&gt;server&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This generates a simple shiny app with one plot. Clicking on any of the points produces
a text output containing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;curveNumber&lt;/code&gt;: identifying the ‘trace’ number for that data. We only have one, so this
will always be &lt;code&gt;0&lt;/code&gt; (JavaScript starts counting at 0)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pointNumber&lt;/code&gt;: ostensibly the index of the clicked point in the original dataset, though
I believe that may not always be the case&lt;/li&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt; the x-coordinate of the clicked point&lt;/li&gt;
&lt;li&gt;&lt;code&gt;y&lt;/code&gt; the y-coordinate of the clicked point&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is nice for interacting with the plot to, say, highlight a row in a table
containing the same data. With two of these plots side-by-side one can give each
a unique &lt;code&gt;source&lt;/code&gt; and “listen” to those independently.&lt;/p&gt;
&lt;p&gt;If, however, we have several plots and want them to share a common x-axis (so that
panning works across all of the plots) we need to “combine” the plots using
&lt;code&gt;plotly::subplot()&lt;/code&gt;. This doesn’t take a &lt;code&gt;source&lt;/code&gt; argument itself, and when we provide a
list of several plots, it produces a warning that&lt;/p&gt;
&lt;pre class=&#34;r bg-warning&#34;&gt;&lt;code&gt;Warning: Can only have one: source&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;How, then, do we identify which subplot was clicked?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If each subplot contained a single “trace”, then &lt;code&gt;curveNumber&lt;/code&gt; would correspond
to that trace (in the order they were supplied to &lt;code&gt;subplot&lt;/code&gt;) and we could identify
which subplot was clicked. A small example of the server code
(the UI would be the same) for such a setup might be&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;server &amp;lt;- function(input, output, session) {
  output$p &amp;lt;- renderPlotly({
    p1 &amp;lt;- plotly::plot_ly(data = mtcars,
                          y = ~ hp,
                          x = ~ mpg,
                          type = &amp;quot;scatter&amp;quot;,
                          mode = &amp;quot;markers&amp;quot;)

    p2 &amp;lt;- plotly::plot_ly(data = mtcars,
                          y = ~ wt,
                          x = ~ mpg,
                          type = &amp;quot;scatter&amp;quot;,
                          mode = &amp;quot;markers&amp;quot;)

    p3 &amp;lt;- plotly::plot_ly(data = mtcars,
                          y = ~ disp,
                          x = ~ mpg,
                          type = &amp;quot;scatter&amp;quot;,
                          mode = &amp;quot;markers&amp;quot;)

    s &amp;lt;- plotly::subplot(
      list(p1, p2, p3),
      shareX = TRUE,
      nrows = 3,
      heights = c(1, 1, 1)/3
    ) |&amp;gt;
      event_register(&amp;quot;plotly_click&amp;quot;)
    s$x$source &amp;lt;- &amp;quot;click_src&amp;quot; # subplot does not take a `source` argument
    s
  })

  output$out &amp;lt;- renderPrint({
    click_data &amp;lt;- event_data(&amp;quot;plotly_click&amp;quot;, source = &amp;quot;click_src&amp;quot;)
    req(click_data)
    message(&amp;quot;CLICK!&amp;quot;)
    click_data
  })
}&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/p2.png&#34; width=&#34;600&#34; alt=&#34;Multiple traces - the second is “trace1” because JavaScript counts from 0&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Multiple traces - the second is “trace1” because JavaScript counts from 0&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Because &lt;code&gt;subplot&lt;/code&gt; doesn’t take a &lt;code&gt;source&lt;/code&gt; argument, the (single) source needs
to be added into the resulting object by force with the &lt;code&gt;s$x$source&lt;/code&gt; line. This works,
and we can get click data back from each subplot. In theory, &lt;code&gt;curveNumber&lt;/code&gt; identifies
which subplot was clicked.&lt;/p&gt;
&lt;p&gt;However, if a subplot contained multiple traces (as my actual example did - a
difficult to count number of traces that was updated as the underlying data
changed… each different ‘color’ point you plot is a unique trace) then this
gets complicated.&lt;/p&gt;
&lt;p&gt;A minor update to the server, adding one additional “markers” trace to the
second plot…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;    p2 &amp;lt;- plotly::plot_ly(data = mtcars,
                          y = ~ wt,
                          x = ~ mpg,
                          type = &amp;quot;scatter&amp;quot;,
                          mode = &amp;quot;markers&amp;quot;) |&amp;gt;
      add_markers(y = ~ drat)                   # &amp;lt;- an additional trace&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/p3.png&#34; width=&#34;600&#34; alt=&#34;With one additional trace, it becomes difficult to determine which plot was clicked based on curveNumber alone&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;With one additional trace, it becomes difficult to determine which plot was clicked based on &lt;code&gt;curveNumber&lt;/code&gt; alone&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So, how can we identify the subplot when we can’t count the traces? The solution
appears to be to add another entry to the click-data using &lt;code&gt;customdata&lt;/code&gt;…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;server &amp;lt;- function(input, output, session) {
  output$p &amp;lt;- renderPlotly({
    p1 &amp;lt;- plotly::plot_ly(data = mtcars,
                          y = ~ hp,
                          x = ~ mpg,
                          type = &amp;quot;scatter&amp;quot;,
                          mode = &amp;quot;markers&amp;quot;,
                          customdata = &amp;quot;first_plot&amp;quot;)       # &amp;lt;--

    p2 &amp;lt;- plotly::plot_ly(data = mtcars,
                          y = ~ wt,
                          x = ~ mpg,
                          type = &amp;quot;scatter&amp;quot;,
                          mode = &amp;quot;markers&amp;quot;,
                          customdata = &amp;quot;second_plot&amp;quot;) |&amp;gt;   # &amp;lt;--
      add_markers(y = ~ drat, customdata = &amp;quot;second_plot&amp;quot;)  # &amp;lt;--

    p3 &amp;lt;- plotly::plot_ly(data = mtcars,
                          y = ~ disp,
                          x = ~ mpg,
                          type = &amp;quot;scatter&amp;quot;,
                          mode = &amp;quot;markers&amp;quot;,
                          customdata = &amp;quot;third_plot&amp;quot;)       # &amp;lt;--

    s &amp;lt;- plotly::subplot(
      list(p1, p2, p3),
      shareX = TRUE,
      nrows = 3,
      heights = c(1, 1, 1)/3
    ) |&amp;gt;
      event_register(&amp;quot;plotly_click&amp;quot;)
    s$x$source &amp;lt;- &amp;quot;click_src&amp;quot;
    s
  })

  output$out &amp;lt;- renderPrint({
    click_data &amp;lt;- event_data(&amp;quot;plotly_click&amp;quot;, source = &amp;quot;click_src&amp;quot;)
    req(click_data)
    message(&amp;quot;CLICK!&amp;quot;)
    click_data 
  })
}&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/p4.png&#34; width=&#34;600&#34; alt=&#34;By adding some customdata it’s easy to determine which plot was clicked&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;By adding some &lt;code&gt;customdata&lt;/code&gt; it’s easy to determine which plot was clicked&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In this example I’ve added a single &lt;code&gt;customdata&lt;/code&gt; value to each plot so it will be
recycled across all of the data points in each plot. I’ve also added the same
&lt;code&gt;&#34;second_plot&#34;&lt;/code&gt; value to both of the traces in the second plot, but you could
further distinguish those if desired. You can also add a vector of &lt;code&gt;customdata&lt;/code&gt;
(one value per point, in order) to individually identify the records, such as a &lt;code&gt;key&lt;/code&gt;
value to deterministically reproduce the &lt;code&gt;pointNumber&lt;/code&gt; functionality.&lt;/p&gt;
&lt;p&gt;As a final check (after doing all the old-school research myself) I asked an AI
how to identify which plot was clicked and it more or less gave the answers I’ve
described here, with some (different) example code and all. It took a bit of
prompting to get it to go further than just using the &lt;code&gt;curveNumber&lt;/code&gt; but I was amazed
that it really did produce a (more or less) working proof-of-concept with minimal
refinement. I definitely need to jump straight to that more often instead of fiddling
around with solutions that &lt;em&gt;don’t&lt;/em&gt; work for too long.&lt;/p&gt;
&lt;p&gt;Is there a better way to achieve this? Let me know! I’m pretty much not on the bird site
any more but I can be found on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; or
use the comments below.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-06-17
##  pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.17    2023-05-16 [1] CRAN (R 4.1.2)
##  bookdown      0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  bslib         0.4.1   2022-11-02 [3] CRAN (R 4.2.2)
##  cachem        1.0.6   2021-08-19 [3] CRAN (R 4.2.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.4.1   2022-09-23 [3] CRAN (R 4.2.1)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest        0.6.30  2022-10-18 [3] CRAN (R 4.2.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.18    2022-11-07 [3] CRAN (R 4.2.2)
##  fastmap       1.1.0   2021-01-25 [3] CRAN (R 4.2.0)
##  fs            1.5.2   2021-12-08 [3] CRAN (R 4.1.2)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  htmltools     0.5.3   2022-07-18 [3] CRAN (R 4.2.1)
##  htmlwidgets   1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv        1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.3   2022-10-21 [3] CRAN (R 4.2.1)
##  knitr         1.40    2022-08-24 [3] CRAN (R 4.2.1)
##  later         1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  pkgbuild      1.4.0   2022-11-27 [1] CRAN (R 4.1.2)
##  pkgload       1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.8.0   2022-10-26 [3] CRAN (R 4.2.1)
##  profvis       0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises      1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps            1.7.2   2022-10-26 [3] CRAN (R 4.2.2)
##  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.0.6   2022-09-24 [1] CRAN (R 4.1.2)
##  rmarkdown     2.18    2022-11-09 [3] CRAN (R 4.2.2)
##  rstudioapi    0.14    2022-08-22 [3] CRAN (R 4.2.1)
##  sass          0.4.2   2022-07-16 [3] CRAN (R 4.2.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny         1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi       1.7.8   2022-07-11 [3] CRAN (R 4.2.1)
##  stringr       1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis       2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  vctrs         0.5.2   2023-01-23 [1] CRAN (R 4.1.2)
##  xfun          0.34    2022-10-18 [3] CRAN (R 4.2.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml          2.3.6   2022-10-18 [3] CRAN (R 4.2.1)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Polyglot Exploration of Function Overloading</title>
      <link>https://jcarroll.com.au/2023/04/03/polyglot-overloading/</link>
      <pubDate>Mon, 03 Apr 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/04/03/polyglot-overloading/</guid>
      <description>&lt;p&gt;I’ve been working my way through &lt;a href=&#34;https://exercism.org/&#34;&gt;Exercism&lt;/a&gt; exercises in a variety of
languages because I strongly believe every language you learn something about teaches
you about all the others you know, and makes for useful comparisons between what
features they offer. I was&lt;a href=&#34;#fn1&#34; class=&#34;footnote-ref&#34; id=&#34;fnref1&#34;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; Learning Me a &lt;a href=&#34;https://exercism.org/tracks/haskell&#34;&gt;Haskell&lt;/a&gt; for Great Good
(there’s &lt;a href=&#34;https://learnyouahaskell.github.io/introduction.html&#34;&gt;a guide/book&lt;/a&gt; by that name) and something about &lt;a href=&#34;https://en.wikibooks.org/wiki/Haskell/Pattern_matching&#34;&gt;Pattern Matching&lt;/a&gt;
just seemed extremely familiar.&lt;/p&gt;
&lt;p&gt;Pattern Matching is sort of like a &lt;code&gt;case&lt;/code&gt; statement, but rather than just comparing literal
values against some &lt;code&gt;enum&lt;/code&gt;, it takes into consideration how the input &lt;em&gt;“looks”&lt;/em&gt;. A simple example
is to match against either an empty list &lt;code&gt;[]&lt;/code&gt; (just that; an empty list) or a non-empty list denoted
&lt;code&gt;(x:xs)&lt;/code&gt;. In Haskell, &lt;code&gt;:&lt;/code&gt; is a concatenation operator (&lt;code&gt;cons&lt;/code&gt; in lisp) so this is the concatenation
of &lt;code&gt;x&lt;/code&gt; and the rest of a list, &lt;code&gt;xs&lt;/code&gt;. The wildcard pattern &lt;code&gt;_&lt;/code&gt; matching “whatever”.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;map&lt;/code&gt; function definition (from &lt;a href=&#34;https://en.wikibooks.org/wiki/Haskell/Pattern_matching&#34;&gt;here&lt;/a&gt;) is then&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;map _ []     = []
map f (x:xs) = f x : map f xs&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is two definitions for &lt;code&gt;map&lt;/code&gt;, depending on which pattern is provided as the two arguments. The first
takes “whatever” (doesn’t matter, is ignored) and an empty list and just returns an empty list. The
second takes some function &lt;code&gt;f&lt;/code&gt; and a non-empty list, and concatenates (&lt;code&gt;:&lt;/code&gt;) &lt;code&gt;(f x)&lt;/code&gt; (the first
element of the list &lt;code&gt;x&lt;/code&gt; provided to the function &lt;code&gt;f&lt;/code&gt;) with &lt;code&gt;map f xs&lt;/code&gt; (the result of providing &lt;code&gt;f&lt;/code&gt; and the
rest of the list &lt;code&gt;xs&lt;/code&gt; to &lt;code&gt;map&lt;/code&gt;, recursively).&lt;/p&gt;
&lt;p&gt;Since Haskell is strongly typed, I don’t think this can be used to define the same named function for
different &lt;em&gt;types&lt;/em&gt;, but it can certainly do something different depending on the pattern of the data.
In this example, if the argument is an empty list, return &lt;code&gt;0&lt;/code&gt;; if the argument is a length-1 list (&lt;code&gt;arg1&lt;/code&gt;
concatenated with an empty list) then return &lt;code&gt;arg1 * 100&lt;/code&gt;, and if the argument is a longer list, return
the product of the first element and the second. This then prints out calling &lt;code&gt;fun 5.0&lt;/code&gt; and &lt;code&gt;fun [5.0, 5.0]&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;haskell&#34;&gt;&lt;code&gt;fun :: [Float] -&amp;gt; Float
fun [] = 0.0
fun (arg1:[]) = arg1 * 100.0
fun (arg1:arg2) = arg1 * (head arg2)

main = do
  print (fun [5.0])
  print (fun [5.0, 5.0])&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;500.0
25.0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Woo! A different function called depending on the input. I believe it might be possible to actually
have optional arguments via the &lt;code&gt;Data.Maybe&lt;/code&gt; package but I couldn’t get it to compile an example the way
I wanted&lt;a href=&#34;#fn2&#34; class=&#34;footnote-ref&#34; id=&#34;fnref2&#34;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Rust has &lt;a href=&#34;https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html&#34;&gt;something similar&lt;/a&gt; but more specific to a &lt;code&gt;case&lt;/code&gt; statement; a &lt;code&gt;match&lt;/code&gt; expression
can take patterns as options and return whichever matches (example from &lt;a href=&#34;https://google.github.io/comprehensive-rust/pattern-matching.html&#34;&gt;here&lt;/a&gt;)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn main() {
    let input = &amp;#39;s&amp;#39;;

    match input {
        &amp;#39;q&amp;#39;                   =&amp;gt; println!(&amp;quot;Quitting&amp;quot;),
        &amp;#39;a&amp;#39; | &amp;#39;s&amp;#39; | &amp;#39;w&amp;#39; | &amp;#39;d&amp;#39; =&amp;gt; println!(&amp;quot;Moving around&amp;quot;),
        &amp;#39;0&amp;#39;..=&amp;#39;9&amp;#39;             =&amp;gt; println!(&amp;quot;Number input&amp;quot;),
        _                     =&amp;gt; println!(&amp;quot;Something else&amp;quot;),
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;Moving around&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another common use of &lt;code&gt;match&lt;/code&gt; is to switch between the &lt;code&gt;enums&lt;/code&gt; &lt;code&gt;Some&lt;/code&gt; and &lt;code&gt;None&lt;/code&gt;
or &lt;code&gt;Ok&lt;/code&gt; and &lt;code&gt;Err&lt;/code&gt; (see &lt;a href=&#34;https://doc.rust-lang.org/std/result/&#34;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The familiarity of the Haskell pattern matching / function definition took me back to one of the
very first programming ‘tricks’ I learned way back in the late 2000’s working on my PhD, using Fortran;
“function overloading”. I wasn’t formally taught programming at all (an oversight, given how important
it became to doing my research), so I just had to pick up bits and pieces from people who knew more.&lt;/p&gt;
&lt;p&gt;I had a bunch of integration routines&lt;a href=&#34;#fn3&#34; class=&#34;footnote-ref&#34; id=&#34;fnref3&#34;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; which were slightly different depending on whether or not
the limits were finite&lt;a href=&#34;#fn4&#34; class=&#34;footnote-ref&#34; id=&#34;fnref4&#34;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;, so I had to call
the right one with various &lt;code&gt;if&lt;/code&gt; statements. The ‘trick’ I was
taught was to use &lt;code&gt;INTERFACE / MODULE PROCEDURE&lt;/code&gt; &lt;a href=&#34;https://www.intel.com/content/www/us/en/docs/fortran-compiler/developer-guide-reference/2023-0/module-procedure.html&#34;&gt;blocks&lt;/a&gt; to “dispatch” depending on the function
signature, or at least the number of arguments. This meant that I could just call &lt;code&gt;integrate&lt;/code&gt; regardless of
whether it was a signature with 4 arguments, or a signature with an additional argument if a bound was &lt;code&gt;Infty&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A “small” (Fortran is hardly economical with page real-estate) example of this,
following the Haskell example, defines two functions &lt;code&gt;Fun1arg&lt;/code&gt; and &lt;code&gt;Fun2arg&lt;/code&gt; which
can be consolidated into &lt;code&gt;fun&lt;/code&gt; with the &lt;code&gt;INTERFACE&lt;/code&gt; block. Calling &lt;code&gt;fun(x)&lt;/code&gt; or &lt;code&gt;fun(x, y)&lt;/code&gt; is
routed to the function with the relevant signature.&lt;/p&gt;
&lt;pre class=&#34;fortran&#34;&gt;&lt;code&gt;MODULE exampleDispatch
  IMPLICIT NONE

  INTERFACE fun
     MODULE PROCEDURE Fun1arg, Fun2arg
  END INTERFACE fun

  CONTAINS

    ! A function that takes one argument
    ! and multiplies it by 100
    REAL FUNCTION Fun1arg(arg1)
      IMPLICIT NONE
      REAL, INTENT( IN ) :: arg1
      Fun1arg = arg1 * 100.0
    END FUNCTION Fun1arg

    ! A function that takes two arguments
    ! and multiplies them
    REAL FUNCTION Fun2arg(arg1, arg2)
      IMPLICIT NONE
      REAL, INTENT( IN ) :: arg1, arg2
      Fun2arg = arg1 * arg2
    END FUNCTION Fun2arg

END MODULE exampleDispatch

PROGRAM dispatch

  USE exampleDispatch

  IMPLICIT NONE
  REAL :: a = 5.0
  REAL :: fun

  PRINT *, fun(a)
  PRINT *, fun(a, a)

END PROGRAM dispatch&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;   500.000000    
   25.0000000&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That takes me back! I’m going to dig out my old research code and get it into GitHub for
posterity. I’m also going to do the &lt;a href=&#34;https://exercism.org/tracks/fortran&#34;&gt;Fortran exercises in Exercism&lt;/a&gt; to
reminisce some more.&lt;/p&gt;
&lt;p&gt;So, not quite the same as the Haskell version, but it got me thinking about dispatch. R has
several approaches. The most common is &lt;a href=&#34;https://adv-r.hadley.nz/s3.html#s3-methods&#34;&gt;S3&lt;/a&gt; in which dispatch occurs based on the &lt;code&gt;class&lt;/code&gt;
of the first argument to a function, so you can have something different happen to a &lt;code&gt;data.frame&lt;/code&gt;
argument and a &lt;code&gt;tibble&lt;/code&gt; argument, but in both cases the signature has the same “shape” - only the
&lt;em&gt;types&lt;/em&gt; vary.&lt;/p&gt;
&lt;p&gt;Wiring that up to work differently with a &lt;code&gt;list&lt;/code&gt; and any other value (the default case, which
would break for anything that doesn’t vectorize, but it’s a toy example) looks like&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fun &amp;lt;- function(x) {
  UseMethod(&amp;quot;fun&amp;quot;)
}

fun.default &amp;lt;- function(x) { 
  x * 100
}

fun.list &amp;lt;- function(x) {
  x[[1]] * x[[2]]
}

fun(5)
fun(list(5, 5))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[1] 500
[1] 25&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another option is to use &lt;a href=&#34;https://adv-r.hadley.nz/s4.html#s4-generics&#34;&gt;S4&lt;/a&gt; which is more complicated but more powerful. Here, dispatch
can occur based on the entire signature, though (and I may be wrong) I believe that, too, still
needs to have a consistent “shape”. A fantastic guide to S4 is &lt;a href=&#34;https://stuartlee.org/2019/07/09/s4-short-guide/&#34;&gt;Stuart Lee’s post here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A S4 version of my example could have two options for the signature; one where both
&lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; are &lt;code&gt;&#34;numeric&#34;&lt;/code&gt;, and another where &lt;code&gt;y&lt;/code&gt; is &lt;code&gt;&#34;missing&#34;&lt;/code&gt;. &lt;code&gt;&#34;ANY&#34;&lt;/code&gt; would also work and
encompass a wider scope.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;setGeneric(&amp;quot;fun&amp;quot;, function(x, y, ...) standardGeneric(&amp;quot;fun&amp;quot;))

setMethod(&amp;quot;fun&amp;quot;, c(&amp;quot;numeric&amp;quot;, &amp;quot;missing&amp;quot;), function(x, y) {
  x * 100
})

setMethod(&amp;quot;fun&amp;quot;, c(&amp;quot;numeric&amp;quot;, &amp;quot;numeric&amp;quot;), function(x, y) {
  x * y
})

fun(5)
fun(5, 5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[1] 500
[1] 25&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, can we ever do what I was originally inspired to do - write a simple definition of a
function that calculates differently depending on the number of arguments? Aha - Julia to
the rescue!! Julia has a &lt;a href=&#34;https://docs.julialang.org/en/v1/manual/methods/&#34;&gt;beautifully simple syntax for defining methods on signatures&lt;/a&gt;:
just write it out!&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;fun(x) = x * 100
fun(x, y) = x * y

println(fun(5))
println(fun(5, 5))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;500
25&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s two different signatures for &lt;code&gt;fun&lt;/code&gt; computing different things, and a &lt;em&gt;lot&lt;/em&gt; less
boilerplate compared to the other languages, especially Fortran. What’s written above
is the &lt;em&gt;entire script&lt;/em&gt;. You can even go further
and be specific about the types, say, mixing &lt;code&gt;Int&lt;/code&gt; and &lt;code&gt;Float64&lt;/code&gt; definitions&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;fun(x::Int) = x * 100
fun(x::Float64) = x * 200

fun(x::Int, y::Int) = x * y
fun(x::Int, y::Float64) = x * y * 2

println(fun(5))
println(fun(5.))
println(fun(5, 5))
println(fun(5, 5.))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;500
1000.0
25
50.0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It doesn’t get simpler or more powerful than that!!&lt;/p&gt;
&lt;p&gt;I’ve added all these examples to &lt;a href=&#34;https://github.com/jonocarroll/overloading&#34;&gt;a repo&lt;/a&gt; split out by language, and some
instructions for running them (assuming you have the language tooling already set up).&lt;/p&gt;
&lt;p&gt;Do you have another example from a language that does this (well? poorly?) or similar?
Leave a comment if you have one, or find me on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-06-17
##  pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.17    2023-05-16 [1] CRAN (R 4.1.2)
##  bookdown      0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  bslib         0.4.1   2022-11-02 [3] CRAN (R 4.2.2)
##  cachem        1.0.6   2021-08-19 [3] CRAN (R 4.2.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.4.1   2022-09-23 [3] CRAN (R 4.2.1)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest        0.6.30  2022-10-18 [3] CRAN (R 4.2.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.18    2022-11-07 [3] CRAN (R 4.2.2)
##  fastmap       1.1.0   2021-01-25 [3] CRAN (R 4.2.0)
##  fs            1.5.2   2021-12-08 [3] CRAN (R 4.1.2)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  htmltools     0.5.3   2022-07-18 [3] CRAN (R 4.2.1)
##  htmlwidgets   1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv        1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.3   2022-10-21 [3] CRAN (R 4.2.1)
##  knitr         1.40    2022-08-24 [3] CRAN (R 4.2.1)
##  later         1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  pkgbuild      1.4.0   2022-11-27 [1] CRAN (R 4.1.2)
##  pkgload       1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.8.0   2022-10-26 [3] CRAN (R 4.2.1)
##  profvis       0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises      1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps            1.7.2   2022-10-26 [3] CRAN (R 4.2.2)
##  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.0.6   2022-09-24 [1] CRAN (R 4.1.2)
##  rmarkdown     2.18    2022-11-09 [3] CRAN (R 4.2.2)
##  rstudioapi    0.14    2022-08-22 [3] CRAN (R 4.2.1)
##  sass          0.4.2   2022-07-16 [3] CRAN (R 4.2.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny         1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi       1.7.8   2022-07-11 [3] CRAN (R 4.2.1)
##  stringr       1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis       2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  vctrs         0.5.2   2023-01-23 [1] CRAN (R 4.1.2)
##  xfun          0.34    2022-10-18 [3] CRAN (R 4.2.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml          2.3.6   2022-10-18 [3] CRAN (R 4.2.1)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&#34;footnotes footnotes-end-of-document&#34;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&#34;fn1&#34;&gt;&lt;p&gt;in part due to a strong representation of
Haskell at my local Functional Programming Meetup&lt;a href=&#34;#fnref1&#34; class=&#34;footnote-back&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;&lt;p&gt;I’m highly likely doing something wrong - I never wrote any Haskell before last week&lt;a href=&#34;#fnref2&#34; class=&#34;footnote-back&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;&lt;p&gt;&lt;a href=&#34;http://www.nrbook.com/a/bookf90pdf.html&#34;&gt;Numerical Recipes in Fortran 90&lt;/a&gt; was about the most
important book we had for writing code, basically nothing else was trusted - getting a &lt;em&gt;digital&lt;/em&gt; copy
of the code was considered a sign of true power&lt;a href=&#34;#fnref3&#34; class=&#34;footnote-back&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&#34;fn4&#34;&gt;&lt;p&gt;what, you don’t have to integrate up to infinity in your code?&lt;a href=&#34;#fnref4&#34; class=&#34;footnote-back&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Version Zero Easter Eggs</title>
      <link>https://jcarroll.com.au/2023/03/31/version-zero-easter-eggs/</link>
      <pubDate>Fri, 31 Mar 2023 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2023/03/31/version-zero-easter-eggs/</guid>
      <description>&lt;p&gt;I’ve just finished reading &lt;a href=&#34;https://micro.blog/books/9780593190371&#34;&gt;‘Version
Zero’&lt;/a&gt; by David Yoon. I really enjoyed
it. There’s some (javascript) code on some separator pages between some of the
chapters that is loosely tied into the plot and general theme of the book. I
love solving puzzles, so what was I supposed to do, just leave it at that?&lt;/p&gt;
&lt;p&gt;Incidentally, I’ve hooked my &lt;a href=&#34;https://jcarroll.xyz/reading/&#34;&gt;reading list into my mini
blog&lt;/a&gt; so my ‘Currently Reading’ list is (ideally)
up to date.&lt;/p&gt;
&lt;p&gt;I can’t help myself when it comes to puzzles or easter eggs like this.
&lt;a href=&#34;https://jcarroll.com.au/2022/09/01/asd_coin/&#34;&gt;Decrypting the new Australian 50c coin puzzle&lt;/a&gt; triggered a conversation
with one of our top spy agencies. I learned a whole lot from solving this
&lt;a href=&#34;https://jcarroll.com.au/2022/10/29/complex-puzzle/&#34;&gt;Gaussian Primes puzzle&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I very much enjoyed the book. I won’t give away too much, but it does a great
job of calmly building up a story, the characters, the plot and then ramping up
the excitement. In the acknowledgements the author thanks his genius nephew Eric Yoon (&lt;a href=&#34;yoonicode.com&#34;&gt;yoonicode.com&lt;/a&gt; - what a great URL!) for the easter egg code.&lt;/p&gt;
&lt;p&gt;I figured I’d try to to run the code and see what it does. I wanted to carefully
read this - especially given the theme of the book - to make sure it wasn’t going to
delete my networking setup or something. The first step was to get the code from the
(paper) pages into a computer. I looked around - web search, GitHub, Eric’s site - and
couldn’t find an online copy anywhere. I tried searching for a few other unique-looking
terms in the code but nothing. &lt;em&gt;Has no one written up a discussion about this easter egg?&lt;/em&gt; The
book is from 2021, so it’s not &lt;em&gt;that&lt;/em&gt; new. I came across it randomly walking the shelves
at my local library (credit to librarians for prominently featuring great suggestions!). Maybe
I’ve just overlooked a write up somewhere, but maybe I’m the first?&lt;/p&gt;
&lt;p&gt;I had a go at OCR via &lt;a href=&#34;https://github.com/tesseract-ocr/tesseract&#34;&gt;tesseract&lt;/a&gt;
but since it’s javascript and not a text language, it didn’t have much luck.
There are supposedly some language packs for tesseract but none of them helped
with the images I have.&lt;/p&gt;
&lt;p&gt;So, with no digital copy of the code to pull in, I guess the only thing to do is
to &lt;del&gt;forget about it and move on&lt;/del&gt;MANUALLY TYPE ALL 80-SOMETHING LINES IN. This
was … interesting, but not too bad, really. The choice of font in the book and
somewhat
low dpi meant that the difference between &lt;code&gt;(&lt;/code&gt; and &lt;code&gt;{&lt;/code&gt; was &lt;em&gt;very&lt;/em&gt; subtle. Having a
little bit of domain knowledge helps in this case. Entering the code was otherwise just a matter
of typing until I got to this (or what looks something like this) line&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;subunit.push(btoa(&amp;quot;ß]xëÏz×|ç¼Û¾v&amp;quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Oh… No.&lt;/p&gt;
&lt;p&gt;My best guess was to use Google Docs’ ‘insert character’ which lets you draw the symbol
you’re looking for and gives some options.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;images/insertchar.png&#34; width=&#34;300&#34; alt=&#34;&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;Google Docs’ insert character dialog&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The next step was to actually confirm that I hadn’t
made any transcription errors, which should show up if I try to run the code. I checked
that I could run a file of javascript code with &lt;code&gt;node&lt;/code&gt; and it worked, sort of. It failed about
halfway through because a function wasn’t defined - &lt;code&gt;btoa&lt;/code&gt; and &lt;code&gt;atob&lt;/code&gt; are &lt;a href=&#34;https://dev.to/2ezpz2plzme/btoa-replacement-in-nodejs-3k6g&#34;&gt;deprecated in Node&lt;/a&gt;. I added some definitions
for &lt;code&gt;atob&lt;/code&gt; and &lt;code&gt;btoa&lt;/code&gt; and that was resolved&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;atob = a =&amp;gt; Buffer.from(a, &amp;#39;base64&amp;#39;).toString(&amp;#39;binary&amp;#39;)
btoa = b =&amp;gt; Buffer.from(b, &amp;#39;binary&amp;#39;).toString(&amp;#39;base64&amp;#39;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code didn’t run, though, because some values didn’t convert to &lt;code&gt;BigInt&lt;/code&gt;,
probably because I’d entered them wrong.&lt;/p&gt;
&lt;p&gt;I carefully went through what I’d entered and did realise that there was only a subtle
difference between &lt;code&gt;1&lt;/code&gt; (one) and &lt;code&gt;l&lt;/code&gt; (lowercase &lt;code&gt;L&lt;/code&gt;) and made some fixes.&lt;/p&gt;
&lt;p&gt;Apart from that, the code ran until it hit the &lt;code&gt;BigInt&lt;/code&gt; conversion of a
particular value and failed. I forced the code to skip over that value and got to
an answer. The result of running the code is similar to the &lt;a href=&#34;https://github.com/jonocarroll/advent-of-code/blob/main/2022/R/R/day10.R%20-%20which%20I&amp;#39;m%20still%20yet%20to%20write%20up&#34;&gt;Advent of Code 2022
Day 10 Part Two
puzzle&lt;/a&gt; which writes out &lt;code&gt;#&lt;/code&gt; and spaces in lines to
spell out ASCII-art words. Clearly my code was broken, because I could see what it
was &lt;em&gt;supposed&lt;/em&gt; to spell out, and there were errors.&lt;/p&gt;
&lt;p&gt;I figured I had to trace back through the result being built up and figure out
which values end up on which lines. Extra fun, because there’s a &lt;code&gt;filter&lt;/code&gt; in the
middle that removes some of the input. Sure enough, one of the offending lines was
the unicode-salad line above - great. The other seemed to be&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const datetime = new Date(1997, 7, 24);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Super great - this is going to involve a timezone issue, isn’t it?&lt;/p&gt;
&lt;p&gt;Back to the unicode, I searched again for this specific line (minus the unicode) and
actually did get a hit - Google Books has a copy of the (Czech?) translation of the
book and returns this line. Not precisely (something hasn’t encoded correctly) and
not selectable in the book, but selectable in the &lt;a href=&#34;https://www.google.com/search?q=%22subunit.push%22+btoa&#34;&gt;Google result for it&lt;/a&gt;. That wasn’t much
help after all.&lt;/p&gt;
&lt;p&gt;Let’s walk through the code and see how it works before we resolve it. A full
copy (with my own annotations and fixes) is
&lt;a href=&#34;https://github.com/jonocarroll/versionzero&#34;&gt;here&lt;/a&gt;, if anyone else wants to not
have to type all of it in.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const VERSION_NUMBER = 0;
const AGENT = &amp;quot;BLACK HALO&amp;quot;;
const year = 0x2018;
const enc = [
    021, 024, 015, 015,
    026, -031, 030, 016,
    034, 027, 021, 034,
    021, 014, 025, -022,
    017, 016, 032, 027
];
let res = [&amp;quot;You are infinite&amp;quot;];
RANDOM_SEED = 20879976793454946324n;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 0
## BLACK HALO
## 8216
## 17,20,13,13,22,-25,24,14,28,23,17,28,17,12,21,-18,15,14,26,23
## You are infinite
## 20879976793454946324&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So far so good. Some constants and the start of a result &lt;code&gt;res&lt;/code&gt; - an array
containing some text.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (VERSION_NUMBER % 2 &amp;lt; 1) res.shift();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With &lt;code&gt;VERSION_NUMBER == 0&lt;/code&gt; this just drops the first (and only) value of &lt;code&gt;res&lt;/code&gt;, so
we’re back to an empty result.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;res.push(enc.map((i, idx) =&amp;gt; {
    return String.fromCharCode(
        AGENT.charCodeAt(
            idx % AGENT.length
        ) - i
    );
}).reduce((i, j) =&amp;gt; {
    return i.toString() + j.toString();
}));
res[0]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;javascript bg-success&#34;&gt;&lt;code&gt;## 18465903081007629328&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This does some math on the characters of &lt;code&gt;AGENT&lt;/code&gt; and produces what will eventually
be the &lt;em&gt;second&lt;/em&gt; line of actual output (currently the first).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;res.unshift(atob(&amp;quot;MzU3NzU1MDM2NTgxMDMzNTg0OTU=&amp;quot;));
res[0]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 35775503658103358495&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This becomes the &lt;em&gt;first&lt;/em&gt; line of output due to the &lt;code&gt;unshift&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;res.push(
    (8939935261623587079n &amp;lt;&amp;lt; 2n).toString() 
);
res.push((RANDOM_SEED &amp;amp; 0x18C445CAC40447832n | 0n).toString());
res.push(&amp;quot;&amp;quot; + (151845383424178857009896n / BigInt(year)));&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 35759741046494348316
## 18465906380616247312
## 18481667894861107231&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;become the third, fourth, and fifth line of the output.&lt;/p&gt;
&lt;p&gt;The next lines set up something to be used later,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let as_json = {
    coordinates: &amp;#39;{&amp;quot;x&amp;quot;: 2, &amp;quot;y&amp;quot;: 5}&amp;#39;,
    tolerance: 0.1,
    subunit: [2 ** 8]
};
const c = JSON.parse(as_json.coordinates);&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## { coordinates: &amp;#39;{&amp;quot;x&amp;quot;: 2, &amp;quot;y&amp;quot;: 5}&amp;#39;, tolerance: 0.1, subunit: [ 256 ] }
## { x: 2, y: 5 }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then adds a separator of &lt;code&gt;0&lt;/code&gt; to the result&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;res.push((z =&amp;gt; `value: ${z}`.slice(7))((x =&amp;gt; x &amp;gt;&amp;gt;&amp;gt; 42)(3 ** 5)));&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next part is a bit of a red herring since it sets up a &lt;code&gt;subunit&lt;/code&gt; object&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let subunit = as_json[&amp;quot;subunit&amp;quot;];
eval(&amp;quot;subunit&amp;quot; + `${String.fromCharCode(46)}pop()`);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but the &lt;code&gt;eval&lt;/code&gt; results in&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## subunit.pop()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so that is back to empty.&lt;/p&gt;
&lt;p&gt;This adds some data to &lt;code&gt;subunit&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;subunit.push(69 + 114 + 105 + 99 + 32 + 89 + 111 + 111 + 110);&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 840&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but again it’s overwritten with&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;subunit[0] = Math.round(euclidianDistance(c.x, c.y, 48, 1967.46095)) + &amp;quot;4568824394612736&amp;quot;; 
[...]
/**
    * @returns the distance between 2d point (x, y) and (x1, y1)
    */
function euclidianDistance(x, y, x1, y1) {
    return Math.sqrt(((x - x1) ** 2) + ((y - y1) ** 2));
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 19634568824394612736&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the first line of the second block of output.&lt;/p&gt;
&lt;p&gt;The next line of output &lt;em&gt;should&lt;/em&gt; come from the code that I have as&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;subunit.push(btoa(&amp;quot;ß]xëÏz×|ç¼Û¾v&amp;quot;));
res = res.concat(subunit);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but that produces&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 3114689613znvNu+dg==&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which doesn’t convert to &lt;code&gt;BigInt&lt;/code&gt; at all. We’ll come back to that.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const str = &amp;quot;MjQyNDI4NzczNDQ0MjgwNjQ3Njg=bMTk2MTc2ODAxMTY0MTIzMTc2OTY=bMTk2MzQ1Njg0OTI2MDgzODkxMjA=bMA==&amp;quot;; 
res = res.concat(str.split(&amp;quot;b&amp;quot;).map(b =&amp;gt; atob(b)));&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;splits up the &lt;code&gt;str&lt;/code&gt; at the letter &lt;code&gt;b&lt;/code&gt; and runs &lt;code&gt;atob&lt;/code&gt; over the pieces&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [
##   &amp;#39;24242877344428064768&amp;#39;,
##   &amp;#39;19617680116412317696&amp;#39;,
##   &amp;#39;19634568492608389120&amp;#39;,
##   &amp;#39;0&amp;#39;
## ]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;providing the rest of the second block of output and the next separator.&lt;/p&gt;
&lt;p&gt;The next lines set up a &lt;code&gt;Date&lt;/code&gt; object and extracts part of the string representation
(local timezone, but it’s just taking the &lt;code&gt;&#34;19&#34;&lt;/code&gt; from &lt;code&gt;&#34;1997&#34;&lt;/code&gt;)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const datetime = new Date(1997, 7, 24);
res.push(
    datetime.toString().slice(11, 13) +
        (
            634601705079659136n +
            BigInt(datetime.getTime())
        )
);&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 19634602577426259136&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which &lt;em&gt;looks&lt;/em&gt; okay, but gives the wrong value on the first line of the last
block - another one to come back to.&lt;/p&gt;
&lt;p&gt;The next lines were fun to enter and validate (not)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;res = res.concat(
    [
        &amp;quot;Mjg4NDIxOTU1MjI5NzAyMDYyMDg=&amp;quot;, /** block 3, line 2 */
        &amp;quot;MTVkIGhlcnJpbmcgZ2V0IHJla3Q=&amp;quot;, 
        &amp;quot;MTEwNTI5MDA1Mjk2MDU5NzY2MTM0&amp;quot;,
        &amp;quot;MjQyMzA1MjI2OTg2ODIzNjM5MDQ=&amp;quot;, /** block 3, line 3 */
        &amp;quot;SG9wZSB5b3UgbGlrZSBSZWdleCE=&amp;quot;, 
        &amp;quot;MTk1MjA0NjkyMDUyODYzMDQ0MDM=&amp;quot;,
        &amp;quot;MjE5MjQ2NjY0OTUzMjkxMjQzNTI=&amp;quot;, /** block 3, line 4 */
        &amp;quot;MjYwMjg2MDQ4NjAyODMwNTUxMDI=&amp;quot;,
        &amp;quot;MTk2MzQ2MDI1OTM2MDc1MTUxMzY=&amp;quot;, /** block 3, line 5 */
        &amp;quot;TG92ZSwgUGlsb3QuIDwzICA8MyA=&amp;quot;, 
        &amp;quot;MzA0NTgyNTg0Mzk1NzM4OTU3OTM5&amp;quot;
    ].filter( 
       i =&amp;gt; i.match(/M[j|T].+[QUINOA][x12][DjTLMNOP]{2}[^aeiou]\*?.{1,5}[a-zA-Z5]+=/g) 
    ).map(atob)
).map((i, j) =&amp;gt; {
    if(j &amp;gt; 5 &amp;amp;&amp;amp; j &amp;lt; 12 &amp;amp;&amp;amp; j != 7) {
        return BigInt(i) &amp;amp; BigInt(31775n &amp;lt;&amp;lt; 50n);
    }
    return i;
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This involves filtering some entries from the big block of encoded text,
running the remaining ones through &lt;code&gt;atob&lt;/code&gt;, then doing some math on these combined
with all the other values from &lt;code&gt;res&lt;/code&gt; (effectively only updating the second block of values).&lt;/p&gt;
&lt;p&gt;While debugging this, I found another easter egg hidden within - one that wouldn’t
be found just by running the code itself. Some of the lines filtered out by the regex
convert to plaintext!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;atob(&amp;quot;MTVkIGhlcnJpbmcgZ2V0IHJla3Q=&amp;quot;)
atob(&amp;quot;SG9wZSB5b3UgbGlrZSBSZWdleCE=&amp;quot;)
atob(&amp;quot;TG92ZSwgUGlsb3QuIDwzICA8MyA=&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 15d herring get rekt
## Hope you like Regex!
## Love, Pilot. &amp;lt;3  &amp;lt;3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Niiiiice!&lt;/p&gt;
&lt;p&gt;The final lines of code take these values, convert to binary, and print a &lt;code&gt;#&lt;/code&gt; for
each &lt;code&gt;1&lt;/code&gt; (and a space otherwise)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for (const i of res) {
    const bin = BigInt(i).toString(2);
    let ln = &amp;quot;&amp;quot;;
    for (const j of bin) ln += j == &amp;quot;0&amp;quot; ? &amp;quot; &amp;quot; : &amp;quot;#&amp;quot;;
    console.log(ln);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you do that, a message (slightly corrupted) appears.&lt;/p&gt;
&lt;p&gt;I decided to work backwards, since I was fairly sure what the ‘right’ solution
should be. Taking those lines (manually corrected), converting them all the way
back through the processing in reverse, I could see what the ‘right’ code should
be.&lt;/p&gt;
&lt;p&gt;The unicode line that produces what I think is the “right” solution is&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;subunit.push(btoa(&amp;quot;ß]xëÏyÓm¼÷\x8DùÓ}ú&amp;quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The characters are mainly close but not perfect, so maybe a &lt;code&gt;LOCALE&lt;/code&gt; issue? Something
to do with Linux (which I’m on) vs Windows?&lt;/p&gt;
&lt;p&gt;The date line seems to be off by exactly 16 hours and 30 minutes which is
disturbingly likely to be a timezone issue. I’m at GMT+10:30 (Adelaide, South
Australia) at the moment. StackOverflow seems to have a lot of &lt;a href=&#34;https://stackoverflow.com/questions/9756120/how-do-i-get-a-utc-timestamp-in-javascript&#34;&gt;angry
comments&lt;/a&gt;
regarding whether or not this is an issue for &lt;code&gt;Date()&lt;/code&gt;. I seem to be able to get
the “right” solution with&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const datetime = new Date(1997, 7, 24, 16, 30);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With all that in place, it’s time to run all of the code! If I do that, I get…&lt;/p&gt;
&lt;/br&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;b&gt; « Click to reveal! » &lt;/b&gt;
&lt;/summary&gt;
&lt;pre&gt;&lt;code&gt;#####     #####     #####     #####     #####     #   #     #####
#         #   #     #   #     #           #       #   #     #    
#####     #   #     #####     #  ##       #       #   #     ###  
#         #   #     # #       #   #       #        # #      #    
#         #####     #  ##     #####     #####       #       #####
 
#   #     #####                                                  
## ##     #                                                      
# # #     ###                                                    
#   #     #                                                      
#   #     #####                                                  
 
#   #     #####     #####     #         #         #####          
##  #     #   #     #         #         #         #              
# # #     #   #     ###       #         #         ###            
#  ##     #   #     #         #         #         #              
#   #     #####     #####     #####     #####     #####          
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;which is fitting, and thoroughly satisfying to finally produce.&lt;/p&gt;
&lt;p&gt;I also ran this code (with my corrections, minus the &lt;code&gt;atob&lt;/code&gt; and &lt;code&gt;btoa&lt;/code&gt;
definitions) over on &lt;a href=&#34;https://jsfiddle.net/&#34;&gt;jsfiddle.net&lt;/a&gt; and it seems to give
the right solution, which makes me think perhaps it really is an error in the
code or how it was printed.&lt;/p&gt;
&lt;p&gt;What an adventure! I learned a lot of javascript (how to run it with &lt;code&gt;node&lt;/code&gt; and
in a browser for debugging), played with
&lt;a href=&#34;https://github.com/tesseract-ocr/tesseract&#34;&gt;tesseract&lt;/a&gt;, and learned about
entering unicode. I’m sending this to Eric Yoon for comment and will update if I
hear anything.&lt;/p&gt;
&lt;p&gt;As a side note for this post, you’ll notice that the code blocks are all nicely
rendered as usual - in this case they’re the actual javascript from the easter
egg code. &lt;a href=&#34;https://yihui.org/knitr/&#34;&gt;{knitr}&lt;/a&gt; &lt;em&gt;does&lt;/em&gt; have a way to evaluate
javascript in code chunks with the &lt;code&gt;node&lt;/code&gt; engine, but that essentially runs
&lt;code&gt;node -e &#39;CODE&#39;&lt;/code&gt; on each chunk independently, so you can’t define a variable in
one chunk then reference it in another. That wasn’t sufficient for this
exploration. I did find an (old)
&lt;a href=&#34;https://github.com/yihui/runr/pull/18&#34;&gt;implementation&lt;/a&gt; that uses
&lt;a href=&#34;https://github.com/jeroen/V8&#34;&gt;{V8}&lt;/a&gt; in Yihui’s (already experimental)
&lt;a href=&#34;https://github.com/yihui/runr&#34;&gt;{runr}&lt;/a&gt;, but it was written for a much older
version of &lt;a href=&#34;https://yihui.org/knitr/&#34;&gt;{knitr}&lt;/a&gt; and was out of date.&lt;/p&gt;
&lt;p&gt;So, of course the thing to do was &lt;del&gt;just hardcode the output&lt;/del&gt;SHAVE A YAK AND UPDATE
THE IMPLEMENTATION. If you’d like to have javascript code chunks in your Rmd, I’ve made
&lt;a href=&#34;https://github.com/stla/runr/pull/1/files&#34;&gt;a pull request&lt;/a&gt; to that original implementation
and have &lt;a href=&#34;https://github.com/jonocarroll/runr&#34;&gt;my own fork&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It seems to work okay, with the exception that it doesn’t pull in &lt;code&gt;Buffer&lt;/code&gt; so my
custom &lt;code&gt;atob&lt;/code&gt; function doesn’t work, and it doesn’t have another. It’s also going
wrong in terms of the persistent context in that the &lt;code&gt;const&lt;/code&gt; and &lt;code&gt;let&lt;/code&gt; directives
are being seen multiple times and it doesn’t like that. Otherwise, variables persist
across chunks just fine - these chunks are fully live:&lt;/p&gt;
&lt;p&gt;Define a variable &lt;code&gt;x&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;v8&#34;&gt;&lt;code&gt;x = 1 + 5;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 6&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then continue the block&lt;/p&gt;
&lt;pre class=&#34;v8&#34;&gt;&lt;code&gt;x + 12&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 18&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, that’s working.&lt;/p&gt;
&lt;p&gt;As always, leave a comment if you have one, or find me on &lt;a href=&#34;https://fosstodon.org/@jonocarroll&#34;&gt;Mastodon&lt;/a&gt; (I’m much
less on Twitter these days). If you have a correction or annotation to add to
the code it’s &lt;a href=&#34;https://github.com/jonocarroll/versionzero&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-03-31
##  pandoc   2.19.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  blogdown      1.13    2022-09-24 [1] CRAN (R 4.1.2)
##  bookdown      0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  bslib         0.4.1   2022-11-02 [3] CRAN (R 4.2.2)
##  cachem        1.0.6   2021-08-19 [3] CRAN (R 4.2.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.4.1   2022-09-23 [3] CRAN (R 4.2.1)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  curl          4.3.3   2022-10-06 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest        0.6.30  2022-10-18 [3] CRAN (R 4.2.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.18    2022-11-07 [3] CRAN (R 4.2.2)
##  fastmap       1.1.0   2021-01-25 [3] CRAN (R 4.2.0)
##  fs            1.5.2   2021-12-08 [3] CRAN (R 4.1.2)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  htmltools     0.5.3   2022-07-18 [3] CRAN (R 4.2.1)
##  htmlwidgets   1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv        1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.3   2022-10-21 [3] CRAN (R 4.2.1)
##  knitr         1.40    2022-08-24 [3] CRAN (R 4.2.1)
##  later         1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  pkgbuild      1.3.1   2021-12-20 [1] CRAN (R 4.1.2)
##  pkgload       1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.8.0   2022-10-26 [3] CRAN (R 4.2.1)
##  profvis       0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises      1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps            1.7.2   2022-10-26 [3] CRAN (R 4.2.2)
##  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.0.6   2022-09-24 [1] CRAN (R 4.1.2)
##  rmarkdown     2.18    2022-11-09 [3] CRAN (R 4.2.2)
##  rstudioapi    0.14    2022-08-22 [3] CRAN (R 4.2.1)
##  runr          0.0.7   2023-03-31 [1] local
##  sass          0.4.2   2022-07-16 [3] CRAN (R 4.2.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny         1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi       1.7.8   2022-07-11 [3] CRAN (R 4.2.1)
##  stringr       1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis       2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  V8          * 4.2.2   2022-11-03 [1] CRAN (R 4.1.2)
##  vctrs         0.5.2   2023-01-23 [1] CRAN (R 4.1.2)
##  xfun          0.34    2022-10-18 [3] CRAN (R 4.2.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml          2.3.6   2022-10-18 [3] CRAN (R 4.2.1)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The Most Complex Puzzle I&#39;ve Ever Solved</title>
      <link>https://jcarroll.com.au/2022/10/29/complex-puzzle/</link>
      <pubDate>Sat, 29 Oct 2022 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2022/10/29/complex-puzzle/</guid>
      <description>&lt;p&gt;Don’t show me puzzles, unless you want to be responsible for me staying up too
late solving them. I’m far too easily &lt;a href=&#34;https://xkcd.com/356/&#34;&gt;nerd-sniped&lt;/a&gt;. This
one was certainly the most complex I’ve ever solved. Quite complicated too,
but definitely the most &lt;em&gt;complex&lt;/em&gt; (you’ll see).&lt;/p&gt;
&lt;p&gt;A few days ago a colleague of mine pointed me to &lt;a href=&#34;https://fivethirtyeight.com/features/can-you-stay-awake-for-50-hours-and-solve-150-puzzles/&#34;&gt;this FiveThirtyEight article&lt;/a&gt;, which isn’t new (2018), but does feature someone else we both work with
as the author of the first puzzle. Brandon is a mathematician-turned-computational-biologist/geneticist and a top-level MIT puzzler.&lt;/p&gt;
&lt;p&gt;The puzzle in the article consists of this image (you may want to save and enlarge, yourself)&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/puzzle.png&#34; width=&#34;250&#34; height=&#34;250&#34; alt=&#34;Studies in two-factor authentication&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Studies in two-factor authentication&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and the clue:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ugh! Dad says the computer will hurt my eyes, but I doubt that’s his prime concern.
Time to see what requires such complex security.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;How could I possibly pass up an opportunity to solve such a cool puzzle?&lt;/p&gt;
&lt;p&gt;I played with a few ideas, but can’t say I made any progress. My colleague also
pointed me to a solution from the MIT puzzles website (I won’t spoil anything just yet)
after which things started to make a lot more sense.&lt;/p&gt;
&lt;p&gt;The critical words in the clue are “prime” and “complex”… we’re going to be dealing
with &lt;a href=&#34;https://en.wikipedia.org/wiki/Gaussian_integer#Gaussian_primes&#34;&gt;Gaussian Primes&lt;/a&gt;; a special case of &lt;a href=&#34;https://en.wikipedia.org/wiki/Gaussian_integer&#34;&gt;Gaussian Integers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I would say “math warning” but if math scares you, you probably could do with some scaring.&lt;/p&gt;
&lt;p&gt;A Gaussian Integer is a complex number (with a &lt;em&gt;real&lt;/em&gt; and an &lt;em&gt;imaginary&lt;/em&gt; part)
&lt;span class=&#34;math inline&#34;&gt;\(z = a + bi\)&lt;/span&gt; where both &lt;span class=&#34;math inline&#34;&gt;\(a\)&lt;/span&gt; and &lt;span class=&#34;math inline&#34;&gt;\(b\)&lt;/span&gt; are integers. A Gaussian Integer is a
Gaussian Prime&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“if and only if either its norm is a prime number, or it is the
product of a unit (&lt;span class=&#34;math inline&#34;&gt;\(\pm 1\)&lt;/span&gt;, &lt;span class=&#34;math inline&#34;&gt;\(\pm i\)&lt;/span&gt;) and a prime number of the form &lt;span class=&#34;math inline&#34;&gt;\(4n + 3\)&lt;/span&gt;”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The first part of this requires that the norm (&lt;span class=&#34;math inline&#34;&gt;\(a^2 + b^2\)&lt;/span&gt;) is itself a prime number.
This will be a positive, real integer. The alternative means that &lt;span class=&#34;math inline&#34;&gt;\(a=0\)&lt;/span&gt; or &lt;span class=&#34;math inline&#34;&gt;\(b=0\)&lt;/span&gt; and we
can write the absolute value of the other (which will be prime) as &lt;span class=&#34;math inline&#34;&gt;\(4n + 3\)&lt;/span&gt; for some non-negative &lt;span class=&#34;math inline&#34;&gt;\(n\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Working with complex numbers in R is actually very well supported. It’s not something
you’d work with a lot in the vast majority of data science (“the average number of
sprockets produced in the first quarter was &lt;span class=&#34;math inline&#34;&gt;\(2 + 3i\)&lt;/span&gt;”?) but R has &lt;code&gt;complex&lt;/code&gt; as an
atomic type and many functions support operations on this.&lt;/p&gt;
&lt;p&gt;Okay, with that in mind, we can generate a bunch of Gaussian Primes. In base R,
of course. First, we’re going to need a way to determine if an integer is
a prime number. We’re not worried about performance, so let’s just try to divide
our target number &lt;span class=&#34;math inline&#34;&gt;\(n\)&lt;/span&gt; by every number smaller than &lt;span class=&#34;math inline&#34;&gt;\(\sqrt n\)&lt;/span&gt; (greater than 1);
if anything divides cleanly (the result is an integer) it’s not a prime number. That can be implemented
(shamelessly stolen from &lt;a href=&#34;https://stackoverflow.com/a/19767707/4168169&#34;&gt;StackOverflow&lt;/a&gt;)
as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.prime &amp;lt;- function(n) n == 2L || all(n %% 2L:max(2,floor(sqrt(n))) != 0)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sanity check:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.prime(7)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.prime(131)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.prime(100)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we’ll need a way to tell if a number is a Gaussian Prime. Implementing the
definition above, and vectorizing it, involves working with the real (&lt;code&gt;Re()&lt;/code&gt;) and
imaginary (&lt;code&gt;Im()&lt;/code&gt;) parts of a complex number&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;isGP &amp;lt;- function(n) {
  (Re(n) != 0 &amp;amp;&amp;amp; Im(n) != 0 &amp;amp;&amp;amp; is.prime(Re(n)^2+Im(n)^2)) ||
    (Re(n) == 0 &amp;amp;&amp;amp; is.prime(Im(n)) &amp;amp;&amp;amp; abs(Im(n)) %% 4 == 3) ||
    (Im(n) == 0 &amp;amp;&amp;amp; is.prime(Re(n)) &amp;amp;&amp;amp; abs(Re(n)) %% 4 == 3)
}
isGPv &amp;lt;- Vectorize(isGP)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sanity check:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;isGP(-5-4i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;isGP(3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;isGP(1 + 3i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;isGP(3 + 20i) # https://planetmath.org/gaussianprime&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can build a grid of integers on the complex plane and mark which are
Gaussian Primes. For the sake of this puzzle, we’ll limit to 250 integers in
each positive direction&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- expand.grid(real = 0:249, im = 0:249)
x$complex &amp;lt;- x$real + (x$im)*1i
x$isGP &amp;lt;- isGPv(x$complex)
head(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   real im complex  isGP
## 1    0  0    0+0i FALSE
## 2    1  0    1+0i FALSE
## 3    2  0    2+0i FALSE
## 4    3  0    3+0i  TRUE
## 5    4  0    4+0i FALSE
## 6    5  0    5+0i FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m &lt;em&gt;solving&lt;/em&gt; this in base R, but we can use a package for visualising things…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)
gg &amp;lt;- ggplot(x, aes(real, im, fill = isGP)) +
  geom_tile() +
  scale_fill_manual(
    values = c(`TRUE` = &amp;quot;black&amp;quot;, `FALSE` = &amp;quot;white&amp;quot;), guide = &amp;quot;none&amp;quot;
  ) +
  theme_void() + 
  theme(aspect.ratio = 1)
gg&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;images/gg-1.png&#34; width=&#34;100%&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Careful inspection shows that this does match the puzzle image, except that the
puzzle version has some additional coloured pixels… Interesting.&lt;/p&gt;
&lt;p&gt;Reading the puzzle image (fetched directly, because Chrome wants to give me a .webp and
maybe I’m getting too old to deal with that) in as pixel data into three channels
(R, G, B) (yes, one external package, fine)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;img &amp;lt;- &amp;quot;puzzle.png&amp;quot;
# download.file(&amp;quot;https://fivethirtyeight.com/wp-content/uploads/2018/01/puzzle1.png&amp;quot;, img)
img &amp;lt;- png::readPNG(img)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;we can rescale these to 8-bit numbers, convert to hex, then combine into hex colours&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;img &amp;lt;- list(
  red = img[,,1]*255, 
  green = img[,,2]*255, 
  blue = img[,,3]*255
)
img &amp;lt;- lapply(img, as.hexmode)
img &amp;lt;- matrix(
  do.call(paste0, img), 
  nrow = 250, ncol = 250, 
  byrow = TRUE
)
# identify the locations of pixels 
#  that are not black or white
idx &amp;lt;- which(! img == &amp;quot;000000&amp;quot; &amp;amp; ! img == &amp;quot;ffffff&amp;quot;, arr.ind = TRUE)
cols &amp;lt;- img[idx]

d &amp;lt;- as.data.frame(idx)
# image reads with (0,0) top left
#  so flip it
d$col &amp;lt;- 250 - d$col 
# start at 0
d$row &amp;lt;- d$row - 1 
d$color &amp;lt;- paste0(&amp;quot;#&amp;quot;, cols)
head(d)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   row col   color
## 1  57 178 #0000ff
## 2  47 140 #cccc00
## 3  46 125 #ff0000
## 4  60 109 #0000ff
## 5  15 104 #0000ff
## 6  58 103 #ff0000&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These colours can be identified just by entering them into a search engine,
or by using one of the &lt;a href=&#34;https://github.com/rstudio/rstudio/issues/5424&#34;&gt;very recent RStudio builds&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;known_colors &amp;lt;- c(red = &amp;quot;#ff0000&amp;quot;, 
                  orange = &amp;quot;#ff9919&amp;quot;, 
                  yellow = &amp;quot;#cccc00&amp;quot;,
                  green = &amp;quot;#00ff00&amp;quot;, 
                  blue = &amp;quot;#0000ff&amp;quot;, 
                  purple = &amp;quot;#7f00cc&amp;quot;
)

d$colorname &amp;lt;- names(known_colors)[match(d$color, known_colors)]
head(d)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   row col   color colorname
## 1  57 178 #0000ff      blue
## 2  47 140 #cccc00    yellow
## 3  46 125 #ff0000       red
## 4  60 109 #0000ff      blue
## 5  15 104 #0000ff      blue
## 6  58 103 #ff0000       red&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looks fantastic in the recent RStudio versions, FYI&lt;/p&gt;
&lt;div class=&#34;float&#34;&gt;
&lt;img src=&#34;images/rstudiocolours.png&#34; alt=&#34;Appropriate colour highlighting in RStudio&#34; /&gt;
&lt;div class=&#34;figcaption&#34;&gt;Appropriate colour highlighting in RStudio&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now comes the hard part (and I’ll gladly admit I’d never have figured this out
without seeing a solution first) - if we assume the coloured pixels represent
&lt;strong&gt;complex&lt;/strong&gt; numbers, and we can factor those into the product of two Gaussian
&lt;strong&gt;Prime&lt;/strong&gt;s (remember the clue?) then we can do &lt;em&gt;something&lt;/em&gt; with those. So, how
do we find the factors? Multiplying two numbers, even complex numbers is pretty
straightforward. Figuring out which two prime factors a number has (even a regular
integer) is the &lt;a href=&#34;https://en.wikipedia.org/wiki/Integer_factorization#Prime_decomposition&#34;&gt;foundation of cryptographic keys&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;More searching turns up &lt;a href=&#34;https://www.alpertron.com.ar/GAUSSIAN.HTM&#34;&gt;this resource&lt;/a&gt;
which details an approach:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are three cases:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;&lt;p&gt;The prime factor p of the norm is 2: This means that the factor of the
Gaussian integer is 1+i or 1-i.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The prime factor p of the norm is multiple of 4 plus 3: this value cannot
be expressed as a sum of two squares, so p is not a norm, but p2
is. Since p2 = p2 + 02, and there is no prime norm that divides p2, the number
p + 0i is a Gaussian prime, and the repeated factor p must be discarded.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The prime factor p of the norm is multiple of 4 plus 1: this number can be
expressed as a sum of two squares, by using the methods explained in the sum
of squares page. If p = m2 + n2, then you can check whether m + ni or m − ni
are divisors of the original Gaussian number.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;This translates to: Given the norm &lt;span class=&#34;math inline&#34;&gt;\(N\)&lt;/span&gt; of a Gaussian Prime, the factors of
&lt;span class=&#34;math inline&#34;&gt;\(N\)&lt;/span&gt; (denoted &lt;span class=&#34;math inline&#34;&gt;\(p\)&lt;/span&gt;) will either be &lt;span class=&#34;math inline&#34;&gt;\(1 \pm i\)&lt;/span&gt;, or if &lt;span class=&#34;math inline&#34;&gt;\(p\)&lt;/span&gt; is of the form &lt;span class=&#34;math inline&#34;&gt;\(p = m^2 + n^2\)&lt;/span&gt;
then candidates are &lt;span class=&#34;math inline&#34;&gt;\(m \pm ni\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;So, we’ll need a function to operate on the norm of our Gaussian Prime. The norm
itself is defined as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;complexnorm &amp;lt;- function(z) {
  Re(z)^2 + Im(z)^2
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sanity check:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;complexnorm(3 + 4i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 25&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can implement the approach above as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;norm_factors &amp;lt;- function(N) {

  ## N %% 2 == 0
  if (N %% 2 == 0) {
    if (divides(N, (1+1i))) return(1+1i)
    if (divides(N, (1-1i))) return(1-1i)

    ## N %% 4 == 3
  } else if (N %% 4 == 3) {
    return(NULL)

    ## N %% 4 == 1
  } else if (N %% 4 == 1) {
    return(sos(N))

    ## something&amp;#39;s wrong
  } else {
    stop(&amp;quot;this shouldn&amp;#39;t happen&amp;quot;)
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are a couple of undefined functions here (R is fine with this; it’s lazy).&lt;/p&gt;
&lt;p&gt;We need a way to tell if two complex numbers are “neatly” divisible, in the sense
that they produce a Gaussian Integer. I’ve called that &lt;code&gt;divides()&lt;/code&gt; and an
implementation could be&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;divides &amp;lt;- function(x, y) {
  z &amp;lt;- x / y
  (intish(Re(z)) &amp;amp;&amp;amp; intish(Im(z)))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This relies on being able to say that a real, floating-point value looks like an
integer. This is an annoying part of working with numbers - sometimes, especially
if you’re doing maths, numbers aren’t precisely representable in the computer as
you hope. The classic example is&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;0.1 + 0.2 == 0.3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Why doesn’t that work? Looks simple enough. Let’s print more digits&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;print(0.1 + 0.2, digits = 20)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 0.30000000000000004441&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is so common, there’s even a website: &lt;a href=&#34;https://0.30000000000000004.com/&#34; class=&#34;uri&#34;&gt;https://0.30000000000000004.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So, can’t we just use R’s &lt;code&gt;is.integer()&lt;/code&gt;? Would I be going through this if we could?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.integer(3) # entered as a numeric value&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.integer(3L) # entered as an integer&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so, if we have a not-entered-as-an-integer, it’s not an integer. What about trying
to round-trip through &lt;code&gt;as.integer()&lt;/code&gt; and comparing to the original? If &lt;code&gt;x&lt;/code&gt; and
&lt;code&gt;as.integer(x)&lt;/code&gt; are the same, it’s an integer, right?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as.integer(3)        # makes sense&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as.integer(3.000001) # so far so good&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as.integer(3.999999) # oh, no&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so, if our value is ever so slightly under the integer, it will be rounded all
the way down to the next integer. Okay, so, how can we do this? &lt;code&gt;round()&lt;/code&gt; rounds
towards integers, so let’s check if the absolute difference between &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;round(x)&lt;/code&gt;
is very small&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;intish &amp;lt;- function(x) {
  abs(round(x) - x) &amp;lt; 1e-7
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sanity check:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# 43 + 80i = (8 + 3i)(8 + 7i)
divides(43 + 80i, 8 + 3i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;divides(43 + 80i, 8 + 7i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;divides(43 + 80i, 5 + 5i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The other missing function is for the last condition of &lt;code&gt;norm_factors()&lt;/code&gt;,
when the factor can be represented as the sum of two squares, so &lt;code&gt;sos()&lt;/code&gt; could
be implemented as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sos &amp;lt;- function(p) {
  s &amp;lt;- sqrt(p)
  i &amp;lt;- seq_len(ceiling(s))
  g &amp;lt;- expand.grid(i, i)
  g$sos &amp;lt;- g[, 1]^2 + g[, 2]^2
  opts &amp;lt;- unlist(g[g$sos == p, c(1, 2)][1, ])
  c(round(opts[1]) + round(opts[2])*1i,
    round(opts[1]) - round(opts[2])*1i,
    round(opts[2]) + round(opts[1])*1i,
    round(opts[2]) - round(opts[1])*1i)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This enumerates all the combinations of integers &lt;span class=&#34;math inline&#34;&gt;\(i\)&lt;/span&gt; up to &lt;span class=&#34;math inline&#34;&gt;\(\sqrt p\)&lt;/span&gt; and checks
if the sum of any two squares is equal to the input &lt;span class=&#34;math inline&#34;&gt;\(p\)&lt;/span&gt;. If so, those are returned
as candidates of the form &lt;span class=&#34;math inline&#34;&gt;\(m \pm ni\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;In order to use the above approach of &lt;code&gt;norm_factors&lt;/code&gt; we need to find the prime
factors of the norm of a Gaussian Prime. We will then test each of those with
this approach.&lt;/p&gt;
&lt;p&gt;Finding the prime factors of a regular integer is a little more straightforward
(for very small integers, less than thousands; for integers with thousands of &lt;em&gt;digits&lt;/em&gt;
we get into public-key cryptography spaces). In this case, we just enumerate the
integers, check if the input is divisible, and take those that are prime (according
to our earlier definition)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;all_prime_factors &amp;lt;- function(x) {
  div &amp;lt;- seq_len(x)
  f &amp;lt;- div[x %% div == 0]
  f[sapply(f, is.prime)]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, it’s &lt;a href=&#34;https://stackoverflow.com/q/6424856/4168169&#34;&gt;StackOverflow&lt;/a&gt; to the
rescue here. In case JD Long is reading this, you may be pleased to see that
yes, your musings are still being read (and leveraged) over a decade later.&lt;/p&gt;
&lt;p&gt;Sanity check:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;all_prime_factors(325)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]  1  5 13&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can put that all together into a function that finds the factors of
a Gaussian Prime&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;GP_factors &amp;lt;- function(n) {
  # get all prime factors of the norm of n
  allf &amp;lt;- all_prime_factors(complexnorm(n))
  # get all candidate factors of those
  tests &amp;lt;- lapply(allf, norm_factors)
  # flatten into a vector of candidates
  tests &amp;lt;- unlist(tests)
  # remove anything that didn&amp;#39;t work
  tests &amp;lt;- tests[!is.na(tests)]
  # check if n can be divided by any candidates and keep those
  tests &amp;lt;- tests[sapply(tests, function(x) divides(n, x))]
  # check if we have a Gaussian Prime and keep those
  tests &amp;lt;- tests[isGPv(tests)]
  # only find positive real and imaginary elements
  res &amp;lt;- tests[sapply(tests, function(x) Re(x) &amp;gt; 0 &amp;amp;&amp;amp; Im(x) &amp;gt; 0)]

  # the factors should be the candidate and n / candidate
  # rounded to integers just to be sure
  unique(unname(c(round(res), round(n / res))))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but does it work? How about the example from earlier…&lt;/p&gt;
&lt;p&gt;Sanity check:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# 43 + 80i = (8 + 3i)(8 + 7i)
GP_factors(43 + 80i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 8+3i 8+7i&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That. Is. So. Satisfying!&lt;/p&gt;
&lt;p&gt;Applying this to our coloured points (converted back to complex)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;d$complex &amp;lt;- d$row + d$col*1i
d$factor_pairs &amp;lt;- sapply(seq_len(nrow(d)),
                         function(x) {
                           list(unique(GP_factors(d$complex[x])))
                         })
head(d)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   row col   color colorname complex factor_pairs
## 1  57 178 #0000ff      blue 57+178i 10+9i, 12+7i
## 2  47 140 #cccc00    yellow 47+140i  8+7i, 12+7i
## 3  46 125 #ff0000       red 46+125i  8+7i, 11+6i
## 4  60 109 #0000ff      blue 60+109i  8+7i, 11+4i
## 5  15 104 #0000ff      blue 15+104i  6+5i, 10+9i
## 6  58 103 #ff0000       red 58+103i  8+5i, 11+6i&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we just extract the real and imaginary parts of those pairs&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;d$factor1 &amp;lt;- sapply(d$factor_pairs, `[[`, 1)
d$factor2 &amp;lt;- sapply(d$factor_pairs, `[[`, 2)
d$x1 &amp;lt;- sapply(d$factor1, Re)
d$y1 &amp;lt;- sapply(d$factor1, Im)
d$x2 &amp;lt;- sapply(d$factor2, Re)
d$y2 &amp;lt;- sapply(d$factor2, Im)
head(d)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   row col   color colorname complex factor_pairs factor1 factor2 x1 y1 x2 y2
## 1  57 178 #0000ff      blue 57+178i 10+9i, 12+7i   10+9i   12+7i 10  9 12  7
## 2  47 140 #cccc00    yellow 47+140i  8+7i, 12+7i    8+7i   12+7i  8  7 12  7
## 3  46 125 #ff0000       red 46+125i  8+7i, 11+6i    8+7i   11+6i  8  7 11  6
## 4  60 109 #0000ff      blue 60+109i  8+7i, 11+4i    8+7i   11+4i  8  7 11  4
## 5  15 104 #0000ff      blue 15+104i  6+5i, 10+9i    6+5i   10+9i  6  5 10  9
## 6  58 103 #ff0000       red 58+103i  8+5i, 11+6i    8+5i   11+6i  8  5 11  6&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looping over the different colors as groups, we can draw segments on our image
joining the two Gaussian Prime factors. The segments are all in one corner of
the plot, so I’ve zoomed in to the first dozen pixels square. I’ve also faded the
Gaussian Primes to make the solution a bit clearer&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;gglist &amp;lt;- list()
suppressMessages({ # replacing fill scale
  for (col in names(known_colors)) {
    dcol &amp;lt;- d[d$colorname == col, ]
    gglist[[col]] &amp;lt;- gg +
      geom_segment(data = dcol,
                   aes(x = x1, y = y1,
                       xend = x2, yend = y2,
                       col = colorname),
                   linewidth = 1.5,
                   inherit.aes = FALSE) +
      coord_cartesian(xlim = c(0, 12), ylim = c(0, 12)) +
      scale_color_manual(values =
                           setNames(d$colorname, d$colorname),
                         guide = &amp;quot;none&amp;quot;) +
      scale_fill_manual(
        values = c(`TRUE` = &amp;quot;grey90&amp;quot;, `FALSE` = &amp;quot;white&amp;quot;), 
        guide = &amp;quot;none&amp;quot;
      ) +
      theme_void() +
      theme(aspect.ratio = 1)
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And, finally, printing the result as a nice reveal, we can plot all of those at once&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cowplot::plot_grid(plotlist = gglist, nrow = 2)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;images/answer-1.png&#34; width=&#34;100%&#34; /&gt;
This spells out &lt;strong&gt;“BOTNET”&lt;/strong&gt; which is the answer to the puzzle! And what a puzzle!&lt;/p&gt;
&lt;p&gt;I had a lot of fun solving this - I’m not sure if there was an easier way, and I
definitely couldn’t have made it this far without a significant hint, but I’m
very pleased that I could solve the entire thing in (mostly) base R.&lt;/p&gt;
&lt;p&gt;As always, comments, critiques, and suggestions are welcome both here and on
&lt;a href=&#34;https://twitter.com/carroll_jono/&#34;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-06-17
##  pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date (UTC) lib source
##  assertthat    0.2.1   2019-03-21 [3] CRAN (R 4.0.1)
##  blogdown      1.17    2023-05-16 [1] CRAN (R 4.1.2)
##  bookdown      0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  bslib         0.4.1   2022-11-02 [3] CRAN (R 4.2.2)
##  cachem        1.0.6   2021-08-19 [3] CRAN (R 4.2.0)
##  callr         3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli           3.4.1   2022-09-23 [3] CRAN (R 4.2.1)
##  colorspace    2.0-3   2022-02-21 [3] CRAN (R 4.2.0)
##  cowplot       1.1.1   2020-12-30 [1] CRAN (R 4.1.2)
##  crayon        1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  DBI           1.1.3   2022-06-18 [3] CRAN (R 4.2.1)
##  devtools      2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest        0.6.30  2022-10-18 [3] CRAN (R 4.2.1)
##  dplyr         1.0.10  2022-09-01 [3] CRAN (R 4.2.1)
##  ellipsis      0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate      0.18    2022-11-07 [3] CRAN (R 4.2.2)
##  fansi         1.0.3   2022-03-24 [3] CRAN (R 4.2.0)
##  farver        2.1.1   2022-07-06 [3] CRAN (R 4.2.1)
##  fastmap       1.1.0   2021-01-25 [3] CRAN (R 4.2.0)
##  fs            1.5.2   2021-12-08 [3] CRAN (R 4.1.2)
##  generics      0.1.3   2022-07-05 [3] CRAN (R 4.2.1)
##  ggplot2     * 3.4.1   2023-02-10 [1] CRAN (R 4.1.2)
##  glue          1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  gtable        0.3.1   2022-09-01 [3] CRAN (R 4.2.1)
##  highr         0.9     2021-04-16 [3] CRAN (R 4.1.1)
##  htmltools     0.5.3   2022-07-18 [3] CRAN (R 4.2.1)
##  htmlwidgets   1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv        1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite      1.8.3   2022-10-21 [3] CRAN (R 4.2.1)
##  knitr         1.40    2022-08-24 [3] CRAN (R 4.2.1)
##  labeling      0.4.2   2020-10-20 [3] CRAN (R 4.2.0)
##  later         1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr      2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  memoise       2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime          0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI        0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  munsell       0.5.0   2018-06-12 [3] CRAN (R 4.0.1)
##  pillar        1.8.1   2022-08-19 [3] CRAN (R 4.2.1)
##  pkgbuild      1.4.0   2022-11-27 [1] CRAN (R 4.1.2)
##  pkgconfig     2.0.3   2019-09-22 [3] CRAN (R 4.0.1)
##  pkgload       1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  png           0.1-7   2013-12-03 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.8.0   2022-10-26 [3] CRAN (R 4.2.1)
##  profvis       0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises      1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps            1.7.2   2022-10-26 [3] CRAN (R 4.2.2)
##  purrr         1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6            2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  Rcpp          1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.0.6   2022-09-24 [1] CRAN (R 4.1.2)
##  rmarkdown     2.18    2022-11-09 [3] CRAN (R 4.2.2)
##  rstudioapi    0.14    2022-08-22 [3] CRAN (R 4.2.1)
##  sass          0.4.2   2022-07-16 [3] CRAN (R 4.2.1)
##  scales        1.2.1   2022-08-20 [3] CRAN (R 4.2.1)
##  sessioninfo   1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny         1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi       1.7.8   2022-07-11 [3] CRAN (R 4.2.1)
##  stringr       1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  tibble        3.1.8   2022-07-22 [3] CRAN (R 4.2.2)
##  tidyselect    1.2.0   2022-10-10 [3] CRAN (R 4.2.1)
##  urlchecker    1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis       2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  utf8          1.2.2   2021-07-24 [3] CRAN (R 4.2.0)
##  vctrs         0.5.2   2023-01-23 [1] CRAN (R 4.1.2)
##  withr         2.5.0   2022-03-03 [3] CRAN (R 4.2.0)
##  xfun          0.34    2022-10-18 [3] CRAN (R 4.2.1)
##  xtable        1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml          2.3.6   2022-10-18 [3] CRAN (R 4.2.1)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Polyglot Sorting</title>
      <link>https://jcarroll.com.au/2022/10/08/polyglot-sorting/</link>
      <pubDate>Sat, 08 Oct 2022 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2022/10/08/polyglot-sorting/</guid>
      <description>&lt;p&gt;I’ve had the impression lately that &lt;em&gt;everyone&lt;/em&gt; is learning &lt;a href=&#34;https://www.rust-lang.org/learn&#34;&gt;Rust&lt;/a&gt; and there’s plenty of &lt;a href=&#34;https://github.com/joaocarvalhoopen/How_to_learn_modern_Rust&#34;&gt;great material&lt;/a&gt; out there to make that easier. &lt;a href=&#34;https://github.com/r-rust/gifski&#34;&gt;{gifski}&lt;/a&gt; is perhaps the most well-known example of an R package wrapping a Rust Cargo crate. I don’t really know any system language particularly well, so I figured I’d wade into it and see what it’s like.&lt;/p&gt;
&lt;p&gt;The big advantages I’ve heard are that it’s more modern than C++, is “safe” (in the sense that you can’t compile something that tries to read out of bounds memory), and it’s super fast (it’s a compiled, strictly-typed language, so one would hope so).&lt;/p&gt;
&lt;p&gt;I had a browse through some beginner material, and watched some videos on Youtube. Just enough to have some understanding of the syntax and keywords so I could actually search for things once I inevitably hit problems.&lt;/p&gt;
&lt;p&gt;Getting everything up and running went surprisingly smoothly. Installing &lt;a href=&#34;https://www.rust-lang.org/tools/install&#34;&gt;the toolchain&lt;/a&gt; went okay on my Linux (Pop!_OS) machine, and the &lt;a href=&#34;https://www.rust-lang.org/learn/get-started&#34;&gt;getting started guide&lt;/a&gt; was straightforward enough to follow along with. I soon enough had Ferris welcoming me to the world of Rust&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;----------------------------
&amp;lt; Hello fellow Rustaceans! &amp;gt;
----------------------------
              \
               \
                 _~^~^~_
             \) /  o o  \ (/
               &amp;#39;_   -   _&amp;#39;
               / &amp;#39;-----&amp;#39; \&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Visual Studio Code works nicely as a multi-language editor, and while it’s great to have errors visible to you immediately, I can imagine that gets annoying pretty quick (especially if you write as much bad Rust code as I do).&lt;/p&gt;
&lt;p&gt;Next I needed to actually code something up myself. I love small, silly problems for learning - you don’t know exactly what problems you’ll solve along the way. This one ended up being really helpful.&lt;/p&gt;
&lt;p&gt;I had &lt;a href=&#34;https://twitter.com/somacdivad/status/1570779684702679046?s=20&amp;amp;t=tYK7rDueMPTXSBmbjtolow&#34;&gt;this tweet&lt;/a&gt;&lt;/p&gt;
&lt;blockquote class=&#34;twitter-tweet&#34;&gt;
&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;
This week I’ve been posting &lt;a href=&#34;https://twitter.com/hashtag/Python?src=hash&amp;amp;ref_src=twsrc%5Etfw&#34;&gt;#Python&lt;/a&gt; 🐍 quizzes about sorting.&lt;br&gt;&lt;br&gt;Let’s see if you can put everything together and solve a challenge! 💪&lt;a href=&#34;https://twitter.com/hashtag/CuriousAboutCode?src=hash&amp;amp;ref_src=twsrc%5Etfw&#34;&gt;#CuriousAboutCode&lt;/a&gt; &lt;a href=&#34;https://t.co/ht51eA3Ttj&#34;&gt;pic.twitter.com/ht51eA3Ttj&lt;/a&gt;
&lt;/p&gt;
— David Amos (&lt;span class=&#34;citation&#34;&gt;@somacdivad&lt;/span&gt;) &lt;a href=&#34;https://twitter.com/somacdivad/status/1570779684702679046?ref_src=twsrc%5Etfw&#34;&gt;September 16, 2022&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
&lt;p&gt;in my bookmarks because I wanted to try to solve this with R (naturally) but I decided it was a reasonable candidate for trying to solve a problem and learn some language at the same time, so I decided to give it a go with Rust. This is slightly more complicated than an academic “sort some strings” because it’s “natural sorting” (2 before 10) and has a complicating character in the middle.&lt;/p&gt;
&lt;p&gt;The first step was to get Rust to read in and just print back the ‘data’ (strings). I managed to copy some “print a vector of strings” code and got that working. I’ll figure out later what’s going with the format string here&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;println!(&amp;quot;{:?}&amp;quot;, x);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, I battled errors in converting between &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;&amp;amp;str&lt;/code&gt;, and &lt;code&gt;i32&lt;/code&gt; types; returning a &lt;code&gt;Result&lt;/code&gt; (error) rather than a value; dealing with obscure errors (“cannot move out of borrowed content”, “expected named lifetime parameter” - ???); and a lack of method support for a &lt;code&gt;struct&lt;/code&gt; I just created (which didn’t have any inherited ‘type’). All in all, nothing too surprising given I know approximately 0 Rust, but I got there in the end!&lt;/p&gt;
&lt;p&gt;Now, this won’t be anything “good”, but it does compile and appears to give the right answer, so I’m led to believe that means it’s “right”.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// enable printing of the struct
#[derive(Debug)]
// create a struct with a String and an integer
// not using &amp;amp;str due to lifetime issues
struct Pair {
    x: String,
    y: i32
}

fn main() {
    // input data vector
    let v = vec![&amp;quot;aa-2&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ba-25&amp;quot;, &amp;quot;ab-3&amp;quot;];
    // create an accumulating vector of `Pair`s
    let mut res: Vec&amp;lt;Pair&amp;gt; = vec![];
    // for each string, split at &amp;#39;-&amp;#39;, 
    //  convert the first part to String and the second to integer.
    //  then push onto the accumulator
    for s in v {
        let a: Vec&amp;lt;&amp;amp;str&amp;gt; = s.split(&amp;quot;-&amp;quot;).collect();
        let tmp_pair = Pair {x: a[0].to_string(), y: a[1].parse::&amp;lt;i32&amp;gt;().unwrap() };
        res.push(tmp_pair);
    }
    // sort by Pair.x then Pair.y
    res.sort_by_key(|k| (k.x.clone(), k.y.clone()));
    // start building a new vector for the final result
    let mut res2: Vec&amp;lt;String&amp;gt; = vec![];
    // paste together Pair.x, &amp;#39;-&amp;#39;, and Pair.y (as String)
    for s2 in res {
        res2.push(s2.x + &amp;quot;-&amp;quot; + &amp;amp;s2.y.to_string());
    }

    // [&amp;quot;aa-2&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ab-3&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;ba-25&amp;quot;]
    println!(&amp;quot;{:?}&amp;quot;, res2);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cargo run --release&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;produces the expected output&lt;/p&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;[&amp;quot;aa-2&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ab-3&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;ba-25&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Feel free to suggest anything that could be improved, I’m sure there’s plenty.&lt;/p&gt;
&lt;p&gt;That &lt;em&gt;might&lt;/em&gt; have been an okay place to stop, but I did still want to see if I could solve the problem with R, and how that might compare (in approach, readability, and speed), so I coded that up as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# input vector
s &amp;lt;- c(&amp;quot;aa-2&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ba-25&amp;quot;, &amp;quot;ab-3&amp;quot;)
# split into pairs of strings
x &amp;lt;- strsplit(s, &amp;quot;-&amp;quot;)
# take elements of s sorted by the first elements of x then
#  the second (as integers)
s[order(sapply(x, `[[`, 1), as.integer(sapply(x, `[[`, 2)))]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;aa-2&amp;quot;   &amp;quot;aa-10&amp;quot;  &amp;quot;ab-3&amp;quot;   &amp;quot;ab-100&amp;quot; &amp;quot;ba-25&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I don’t love that I had to use &lt;code&gt;sapply()&lt;/code&gt; twice, but the only other alternative I could think of was to strip out the first and second element lists and use those in a &lt;code&gt;do.call()&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;s[do.call(order, list(unlist(x)[c(T, F)], as.integer(unlist(x)[c(F,T)])))]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;aa-2&amp;quot;   &amp;quot;aa-10&amp;quot;  &amp;quot;ab-3&amp;quot;   &amp;quot;ab-100&amp;quot; &amp;quot;ba-25&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which… isn’t better.&lt;/p&gt;
&lt;p&gt;I also had an idea to shoehorn &lt;code&gt;dplyr::arrange()&lt;/code&gt; into this, but that requires a &lt;code&gt;data.frame&lt;/code&gt;. One idea I had was to read in the data, using &lt;code&gt;&#34;-&#34;&lt;/code&gt; as a delimiter, explicitly stating that I wanted to read it as character and integer data. That seemed to work, which means I can try what I hoped&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;suppressMessages(library(dplyr, quietly = TRUE))
# input vector
s &amp;lt;- c(&amp;quot;aa-2&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ba-25&amp;quot;, &amp;quot;ab-3&amp;quot;)

# read strings as fields delimited by &amp;#39;-&amp;#39;, 
#  expecting character and integer
s %&amp;gt;% read.delim(
    text = .,
    sep = &amp;quot;-&amp;quot;,
    header = FALSE,
    colClasses = c(&amp;quot;character&amp;quot;, &amp;quot;integer&amp;quot;)
) %&amp;gt;%
    # sort by first then second column
    arrange(V1, V2) %&amp;gt;%
    # collapse to single string per row
    mutate(res = paste(V1, V2, sep = &amp;quot;-&amp;quot;)) %&amp;gt;%
    pull()&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;aa-2&amp;quot;   &amp;quot;aa-10&amp;quot;  &amp;quot;ab-3&amp;quot;   &amp;quot;ab-100&amp;quot; &amp;quot;ba-25&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Why stop there? I know other languages! Okay, the Python and Julia examples I found in other Tweets.&lt;/p&gt;
&lt;p&gt;In Julia, two options were offered. &lt;a href=&#34;https://twitter.com/ArturoErdely/status/1570795178050584581?s=20&amp;amp;t=tYK7rDueMPTXSBmbjtolow&#34;&gt;This one&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;strings = String[&amp;quot;aa-2&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ba-25&amp;quot;, &amp;quot;ab-3&amp;quot;];
print(join.(sort(split.(strings, &amp;quot;-&amp;quot;), by = x -&amp;gt; (x[1], parse(Int, x[2]))), &amp;quot;-&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [&amp;quot;aa-2&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ab-3&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;ba-25&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(I added a type to the input and an explicit print), and &lt;a href=&#34;https://twitter.com/rm_slp/status/1570931796069715969?s=20&amp;amp;t=tYK7rDueMPTXSBmbjtolow&#34;&gt;this one&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;strings = String[&amp;quot;aa-2&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ba-25&amp;quot;, &amp;quot;ab-3&amp;quot;];
print(sort(strings, by = x-&amp;gt;split(x, &amp;quot;-&amp;quot;) |&amp;gt; v-&amp;gt;(v[1], parse(Int, v[2]))))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [&amp;quot;aa-2&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ab-3&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;ba-25&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&#34;https://twitter.com/somacdivad/status/1571505932252708869?s=20&amp;amp;t=tYK7rDueMPTXSBmbjtolow&#34;&gt;Python example&lt;/a&gt; offered by the original author of the challenge was&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;def parts(s):
    letters, nums = s.split(&amp;quot;-&amp;quot;)
    return letters, int(nums)

strings = [&amp;quot;aa-2&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ba-25&amp;quot;, &amp;quot;ab-3&amp;quot;]

print(sorted(strings, key=parts))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [&amp;#39;aa-2&amp;#39;, &amp;#39;aa-10&amp;#39;, &amp;#39;ab-3&amp;#39;, &amp;#39;ab-100&amp;#39;, &amp;#39;ba-25&amp;#39;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I actually really like this one - it’s the approach I wanted to use for R; provide &lt;code&gt;sort&lt;/code&gt; with a function returning the keys to use. Alas.&lt;/p&gt;
&lt;p&gt;Lastly, I remembered that there’s a &lt;code&gt;sort&lt;/code&gt; function in bash that can do natural sorting with the &lt;code&gt;-V&lt;/code&gt; flag. I’m reminded of &lt;a href=&#34;https://leancrew.com/all-this/2011/12/more-shell-less-egg/&#34;&gt;this anecdote (“More shell, less egg”)&lt;/a&gt; about using a very simple bash script when it’s possible. That came together okay&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;#!/bin/bash 

v=(&amp;quot;aa-2&amp;quot; &amp;quot;ab-100&amp;quot; &amp;quot;aa-10&amp;quot; &amp;quot;ba-25&amp;quot; &amp;quot;ab-3&amp;quot;)
readarray -t a_out &amp;lt; &amp;lt;(printf &amp;#39;%s\n&amp;#39; &amp;quot;${v[@]}&amp;quot; | sort -V)
printf &amp;#39;%s &amp;#39; &amp;quot;${a_out[@]}&amp;quot;
echo 

exit 0&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## aa-2 aa-10 ab-3 ab-100 ba-25&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By the way, aside from the Rust example, all of these were run directly in the Rmd source of this post with knitr’s powerful engines… multi-language support FTW!&lt;/p&gt;
&lt;p&gt;So, how do all these compare? I haven’t tuned any of these for performance; they’re how I would have written them as a developer trying to achieve something. Sure, if performance was an issue, I’d do some optimization, but I was curious just how the performance compares ‘out of the box’.&lt;/p&gt;
&lt;p&gt;Mainly for my own posterity, I’ll add how I tracked this. I wrote the relevant code for each language in a file with suffix/filetype appropriate to each language. &lt;a href=&#34;https://github.com/jonocarroll/polyglot_sort&#34;&gt;They’re all here&lt;/a&gt;, in case anyone is interested. Then I wanted to run each of them a few times, keeping track of the timing in a file. The solution I went with was to echo into a file (appending each time) both the input and output, with e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo &amp;quot;Rust (optimised/release)&amp;quot; &amp;gt;&amp;gt; timing
{time cargo run --release} &amp;gt;&amp;gt; timing 2&amp;gt;&amp;amp;1
{time cargo run --release} &amp;gt;&amp;gt; timing 2&amp;gt;&amp;amp;1
{time cargo run --release} &amp;gt;&amp;gt; timing 2&amp;gt;&amp;amp;1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(yes, trivial to loop 3 times, but whatever).&lt;/p&gt;
&lt;p&gt;Doing this for all the languages (with both versions for R and Julia) I get&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Rust (optimized/release)
    Finished release [optimized] target(s) in 0.00s
     Running `target/release/sort`
[&amp;quot;aa-2&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ab-3&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;ba-25&amp;quot;]
cargo run --release  0.04s user 0.02s system 99% cpu 0.066 total
    Finished release [optimized] target(s) in 0.00s
     Running `target/release/sort`
[&amp;quot;aa-2&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ab-3&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;ba-25&amp;quot;]
cargo run --release  0.07s user 0.01s system 99% cpu 0.087 total
    Finished release [optimized] target(s) in 0.00s
     Running `target/release/sort`
[&amp;quot;aa-2&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ab-3&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;ba-25&amp;quot;]
cargo run --release  0.06s user 0.02s system 98% cpu 0.084 total

R1
[1] &amp;quot;aa-2&amp;quot;   &amp;quot;aa-10&amp;quot;  &amp;quot;ab-3&amp;quot;   &amp;quot;ab-100&amp;quot; &amp;quot;ba-25&amp;quot; 
Rscript sort1.R  0.15s user 0.05s system 102% cpu 0.197 total
[1] &amp;quot;aa-2&amp;quot;   &amp;quot;aa-10&amp;quot;  &amp;quot;ab-3&amp;quot;   &amp;quot;ab-100&amp;quot; &amp;quot;ba-25&amp;quot; 
Rscript sort1.R  0.17s user 0.05s system 102% cpu 0.206 total
[1] &amp;quot;aa-2&amp;quot;   &amp;quot;aa-10&amp;quot;  &amp;quot;ab-3&amp;quot;   &amp;quot;ab-100&amp;quot; &amp;quot;ba-25&amp;quot; 
Rscript sort1.R  0.16s user 0.05s system 103% cpu 0.202 total

R2
[1] &amp;quot;aa-2&amp;quot;   &amp;quot;aa-10&amp;quot;  &amp;quot;ab-3&amp;quot;   &amp;quot;ab-100&amp;quot; &amp;quot;ba-25&amp;quot; 
Rscript sort2.R  0.72s user 0.05s system 100% cpu 0.774 total
[1] &amp;quot;aa-2&amp;quot;   &amp;quot;aa-10&amp;quot;  &amp;quot;ab-3&amp;quot;   &amp;quot;ab-100&amp;quot; &amp;quot;ba-25&amp;quot; 
Rscript sort2.R  0.67s user 0.06s system 100% cpu 0.720 total
[1] &amp;quot;aa-2&amp;quot;   &amp;quot;aa-10&amp;quot;  &amp;quot;ab-3&amp;quot;   &amp;quot;ab-100&amp;quot; &amp;quot;ba-25&amp;quot; 
Rscript sort2.R  0.69s user 0.04s system 99% cpu 0.737 total

Python
[&amp;#39;aa-2&amp;#39;, &amp;#39;aa-10&amp;#39;, &amp;#39;ab-3&amp;#39;, &amp;#39;ab-100&amp;#39;, &amp;#39;ba-25&amp;#39;]
python3 sort.py  0.03s user 0.00s system 98% cpu 0.032 total
[&amp;#39;aa-2&amp;#39;, &amp;#39;aa-10&amp;#39;, &amp;#39;ab-3&amp;#39;, &amp;#39;ab-100&amp;#39;, &amp;#39;ba-25&amp;#39;]
python3 sort.py  0.02s user 0.01s system 98% cpu 0.034 total
[&amp;#39;aa-2&amp;#39;, &amp;#39;aa-10&amp;#39;, &amp;#39;ab-3&amp;#39;, &amp;#39;ab-100&amp;#39;, &amp;#39;ba-25&amp;#39;]
python3 sort.py  0.03s user 0.02s system 98% cpu 0.059 total

Julia1
[&amp;quot;aa-2&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ab-3&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;ba-25&amp;quot;]
julia sort1.jl  1.10s user 0.68s system 236% cpu 0.750 total
[&amp;quot;aa-2&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ab-3&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;ba-25&amp;quot;]
julia sort1.jl  1.14s user 0.64s system 233% cpu 0.765 total
[&amp;quot;aa-2&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ab-3&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;ba-25&amp;quot;]
julia sort1.jl  1.13s user 0.62s system 241% cpu 0.725 total

Julia2
[&amp;quot;aa-2&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ab-3&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;ba-25&amp;quot;]
julia sort2.jl  0.97s user 0.64s system 270% cpu 0.596 total
[&amp;quot;aa-2&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ab-3&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;ba-25&amp;quot;]
julia sort2.jl  1.00s user 0.58s system 259% cpu 0.607 total
[&amp;quot;aa-2&amp;quot;, &amp;quot;aa-10&amp;quot;, &amp;quot;ab-3&amp;quot;, &amp;quot;ab-100&amp;quot;, &amp;quot;ba-25&amp;quot;]
julia sort2.jl  0.96s user 0.63s system 276% cpu 0.578 total

Bash
aa-2 aa-10 ab-3 ab-100 ba-25 
./sort.sh  0.01s user 0.00s system 109% cpu 0.013 total
aa-2 aa-10 ab-3 ab-100 ba-25 
./sort.sh  0.00s user 0.01s system 108% cpu 0.015 total
aa-2 aa-10 ab-3 ab-100 ba-25 
./sort.sh  0.01s user 0.00s system 99% cpu 0.009 total&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This wouldn’t be much of a coding/benchmark post without a plot, so I also did a visual comparison&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)
d &amp;lt;- tibble::tribble(
  ~language, ~version, ~run, ~time,
  &amp;quot;Rust&amp;quot;, &amp;quot;&amp;quot;, 1, 0.066,
  &amp;quot;Rust&amp;quot;, &amp;quot;&amp;quot;, 2, 0.087,
  &amp;quot;Rust&amp;quot;, &amp;quot;&amp;quot;, 3, 0.084,
  &amp;quot;R&amp;quot;, &amp;quot;1&amp;quot;, 1, 0.197,
  &amp;quot;R&amp;quot;, &amp;quot;1&amp;quot;, 2, 0.206,
  &amp;quot;R&amp;quot;, &amp;quot;1&amp;quot;, 3, 0.202,
  &amp;quot;R&amp;quot;, &amp;quot;2&amp;quot;, 1, 0.774,
  &amp;quot;R&amp;quot;, &amp;quot;2&amp;quot;, 2, 0.720,
  &amp;quot;R&amp;quot;, &amp;quot;2&amp;quot;, 3, 0.737,
  &amp;quot;Julia&amp;quot;, &amp;quot;1&amp;quot;, 1, 0.750,
  &amp;quot;Julia&amp;quot;, &amp;quot;1&amp;quot;, 2, 0.756,
  &amp;quot;Julia&amp;quot;, &amp;quot;1&amp;quot;, 3, 0.725,
  &amp;quot;Julia&amp;quot;, &amp;quot;2&amp;quot;, 1, 0.596,
  &amp;quot;Julia&amp;quot;, &amp;quot;2&amp;quot;, 2, 0.607,
  &amp;quot;Julia&amp;quot;, &amp;quot;2&amp;quot;, 3, 0.578,
  &amp;quot;Python&amp;quot;, &amp;quot;&amp;quot;, 1, 0.032,
  &amp;quot;Python&amp;quot;, &amp;quot;&amp;quot;, 2, 0.034,
  &amp;quot;Python&amp;quot;, &amp;quot;&amp;quot;, 3, 0.059,
  &amp;quot;Bash&amp;quot;, &amp;quot;&amp;quot;, 1, 0.013,
  &amp;quot;Bash&amp;quot;, &amp;quot;&amp;quot;, 2, 0.015,
  &amp;quot;Bash&amp;quot;, &amp;quot;&amp;quot;, 3, 0.009
)

d$language &amp;lt;- factor(
  d$language, 
  levels = c(&amp;quot;Rust&amp;quot;, &amp;quot;R&amp;quot;, &amp;quot;Julia&amp;quot;, &amp;quot;Python&amp;quot;, &amp;quot;Bash&amp;quot;)
)

ggplot(d, aes(language, time, fill = language, group = run)) + 
  geom_col(position = position_dodge(0.9)) + 
  facet_grid(
    ~language + version, 
    scales = &amp;quot;free_x&amp;quot;, 
    labeller = label_wrap_gen(multi_line = FALSE), 
    switch = &amp;quot;x&amp;quot;
  ) + 
  theme_minimal() +
  theme(axis.text.x = element_blank()) + 
  labs(
    title = &amp;quot;Performance of sort functions by language&amp;quot;, 
    y = &amp;quot;Time [s]&amp;quot;, 
    x = &amp;quot;Language, Version&amp;quot;
  ) + 
  scale_fill_brewer(palette = &amp;quot;Set1&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;staticunnamed-chunk-9-1.png&#34; width=&#34;100%&#34; /&gt;&lt;/p&gt;
&lt;p&gt;It’s true - Rust does pretty well, even with my terrible coding. My R implementation (the sensible one) isn’t too bad - perhaps over &lt;em&gt;many&lt;/em&gt; strings it would be a bit slow. Surprisingly, the Julia implementations are actually quite slow. I don’t have a good explanation for that. I’m using Julia 1.5.0 which is slightly out of date, so perhaps that needs an update. The Python implementation does particularly well - I really should learn more python. The syntax there isn’t the worst, either. Oh, no - do I like that?&lt;/p&gt;
&lt;p&gt;The big winner, though, is the simplest of all - Bash crushes the rest of the languages with a 2 liner, and calling it doesn’t involve compiling anything.&lt;/p&gt;
&lt;p&gt;As I said, I’m not particularly interested in optimizing any of these - this is how they compare as written.&lt;/p&gt;
&lt;p&gt;In summary, I learned some Rust - enough to actually manipulate some data. I’ll keep trying and hopefully some day I’ll be semi literate in it.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2023-06-17
##  pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package      * version date (UTC) lib source
##  assertthat     0.2.1   2019-03-21 [3] CRAN (R 4.0.1)
##  blogdown       1.17    2023-05-16 [1] CRAN (R 4.1.2)
##  bookdown       0.29    2022-09-12 [1] CRAN (R 4.1.2)
##  bslib          0.4.1   2022-11-02 [3] CRAN (R 4.2.2)
##  cachem         1.0.6   2021-08-19 [3] CRAN (R 4.2.0)
##  callr          3.7.3   2022-11-02 [3] CRAN (R 4.2.2)
##  cli            3.4.1   2022-09-23 [3] CRAN (R 4.2.1)
##  colorspace     2.0-3   2022-02-21 [3] CRAN (R 4.2.0)
##  crayon         1.5.2   2022-09-29 [3] CRAN (R 4.2.1)
##  DBI            1.1.3   2022-06-18 [3] CRAN (R 4.2.1)
##  devtools       2.4.5   2022-10-11 [1] CRAN (R 4.1.2)
##  digest         0.6.30  2022-10-18 [3] CRAN (R 4.2.1)
##  dplyr        * 1.0.10  2022-09-01 [3] CRAN (R 4.2.1)
##  ellipsis       0.3.2   2021-04-29 [3] CRAN (R 4.1.1)
##  evaluate       0.18    2022-11-07 [3] CRAN (R 4.2.2)
##  fansi          1.0.3   2022-03-24 [3] CRAN (R 4.2.0)
##  farver         2.1.1   2022-07-06 [3] CRAN (R 4.2.1)
##  fastmap        1.1.0   2021-01-25 [3] CRAN (R 4.2.0)
##  fs             1.5.2   2021-12-08 [3] CRAN (R 4.1.2)
##  generics       0.1.3   2022-07-05 [3] CRAN (R 4.2.1)
##  ggplot2      * 3.4.1   2023-02-10 [1] CRAN (R 4.1.2)
##  glue           1.6.2   2022-02-24 [3] CRAN (R 4.2.0)
##  gtable         0.3.1   2022-09-01 [3] CRAN (R 4.2.1)
##  here           1.0.1   2020-12-13 [1] CRAN (R 4.1.2)
##  highr          0.9     2021-04-16 [3] CRAN (R 4.1.1)
##  htmltools      0.5.3   2022-07-18 [3] CRAN (R 4.2.1)
##  htmlwidgets    1.5.4   2021-09-08 [1] CRAN (R 4.1.2)
##  httpuv         1.6.6   2022-09-08 [1] CRAN (R 4.1.2)
##  jquerylib      0.1.4   2021-04-26 [3] CRAN (R 4.1.2)
##  jsonlite       1.8.3   2022-10-21 [3] CRAN (R 4.2.1)
##  JuliaCall      0.17.5  2022-09-08 [1] CRAN (R 4.1.2)
##  knitr          1.40    2022-08-24 [3] CRAN (R 4.2.1)
##  labeling       0.4.2   2020-10-20 [3] CRAN (R 4.2.0)
##  later          1.3.0   2021-08-18 [1] CRAN (R 4.1.2)
##  lattice        0.20-45 2021-09-22 [4] CRAN (R 4.2.0)
##  lifecycle      1.0.3   2022-10-07 [3] CRAN (R 4.2.1)
##  magrittr       2.0.3   2022-03-30 [3] CRAN (R 4.2.0)
##  Matrix         1.5-3   2022-11-11 [4] CRAN (R 4.2.2)
##  memoise        2.0.1   2021-11-26 [3] CRAN (R 4.2.0)
##  mime           0.12    2021-09-28 [3] CRAN (R 4.2.0)
##  miniUI         0.1.1.1 2018-05-18 [1] CRAN (R 4.1.2)
##  munsell        0.5.0   2018-06-12 [3] CRAN (R 4.0.1)
##  pillar         1.8.1   2022-08-19 [3] CRAN (R 4.2.1)
##  pkgbuild       1.4.0   2022-11-27 [1] CRAN (R 4.1.2)
##  pkgconfig      2.0.3   2019-09-22 [3] CRAN (R 4.0.1)
##  pkgload        1.3.0   2022-06-27 [1] CRAN (R 4.1.2)
##  png            0.1-7   2013-12-03 [1] CRAN (R 4.1.2)
##  prettyunits    1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx       3.8.0   2022-10-26 [3] CRAN (R 4.2.1)
##  profvis        0.3.7   2020-11-02 [1] CRAN (R 4.1.2)
##  promises       1.2.0.1 2021-02-11 [1] CRAN (R 4.1.2)
##  ps             1.7.2   2022-10-26 [3] CRAN (R 4.2.2)
##  purrr          1.0.1   2023-01-10 [1] CRAN (R 4.1.2)
##  R6             2.5.1   2021-08-19 [3] CRAN (R 4.2.0)
##  RColorBrewer   1.1-3   2022-04-03 [3] CRAN (R 4.2.0)
##  Rcpp           1.0.9   2022-07-08 [1] CRAN (R 4.1.2)
##  remotes        2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  reticulate     1.26    2022-08-31 [1] CRAN (R 4.1.2)
##  rlang          1.0.6   2022-09-24 [1] CRAN (R 4.1.2)
##  rmarkdown      2.18    2022-11-09 [3] CRAN (R 4.2.2)
##  rprojroot      2.0.3   2022-04-02 [1] CRAN (R 4.1.2)
##  rstudioapi     0.14    2022-08-22 [3] CRAN (R 4.2.1)
##  sass           0.4.2   2022-07-16 [3] CRAN (R 4.2.1)
##  scales         1.2.1   2022-08-20 [3] CRAN (R 4.2.1)
##  sessioninfo    1.2.2   2021-12-06 [1] CRAN (R 4.1.2)
##  shiny          1.7.2   2022-07-19 [1] CRAN (R 4.1.2)
##  stringi        1.7.8   2022-07-11 [3] CRAN (R 4.2.1)
##  stringr        1.5.0   2022-12-02 [1] CRAN (R 4.1.2)
##  tibble         3.1.8   2022-07-22 [3] CRAN (R 4.2.2)
##  tidyselect     1.2.0   2022-10-10 [3] CRAN (R 4.2.1)
##  urlchecker     1.0.1   2021-11-30 [1] CRAN (R 4.1.2)
##  usethis        2.1.6   2022-05-25 [1] CRAN (R 4.1.2)
##  utf8           1.2.2   2021-07-24 [3] CRAN (R 4.2.0)
##  vctrs          0.5.2   2023-01-23 [1] CRAN (R 4.1.2)
##  withr          2.5.0   2022-03-03 [3] CRAN (R 4.2.0)
##  xfun           0.34    2022-10-18 [3] CRAN (R 4.2.1)
##  xtable         1.8-4   2019-04-21 [1] CRAN (R 4.1.2)
##  yaml           2.3.6   2022-10-18 [3] CRAN (R 4.2.1)
## 
##  [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
##  [2] /usr/local/lib/R/site-library
##  [3] /usr/lib/R/site-library
##  [4] /usr/lib/R/library
## 
## ─ Python configuration ───────────────────────────────────────────────────────
##  python:         /usr/bin/python3
##  libpython:      /usr/lib/python3.10/config-3.10-x86_64-linux-gnu/libpython3.10.so
##  pythonhome:     //usr://usr
##  version:        3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0]
##  numpy:          /home/jono/.local/lib/python3.10/site-packages/numpy
##  numpy_version:  1.24.1
##  
##  NOTE: Python version was forced by RETICULATE_PYTHON_FALLBACK
## 
## ──────────────────────────────────────────────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Australian Signals Directorate 50c Coin Decryption</title>
      <link>https://jcarroll.com.au/2022/09/01/asd_coin/</link>
      <pubDate>Thu, 01 Sep 2022 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2022/09/01/asd_coin/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Updated: 2022-09-04&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I took a &lt;em&gt;very&lt;/em&gt; long time &lt;a href=&#34;https://jcarroll.com.au/2021/12/23/adventures-in-x86-asm/&#34;&gt;to post about the last Australian Signals Directorate (then DSD) decryption&lt;/a&gt;, so this time I’ll be a lot more punctual. &lt;a href=&#34;https://www.abc.net.au/news/2022-09-01/act-spy-agency-releases-coin-with-secret-code/101391964&#34;&gt;This article&lt;/a&gt; was published today announcing that ASD have collaborated to release a new 50c coin containing a decryption challenge.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;images/asd_coin_front.png&#34; alt=&#34;&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;The new ASD 50c coin&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;That looks like fun! Typing in the letters and numbers from the image certainly wasn’t, but after that. Of course, I’ll be solving the entire thing with R.&lt;/p&gt;
&lt;p&gt;Apparently there’s &lt;s&gt;4&lt;/s&gt; 6 challenges here.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Added 2022-09-04:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The obverse (head) side of the coin&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/asd_coin_head.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;has some boxes under particular letters (bolded here) in “ELIZA&lt;strong&gt;B&lt;/strong&gt;E&lt;strong&gt;TH&lt;/strong&gt; &lt;strong&gt;A&lt;/strong&gt;U&lt;strong&gt;S&lt;/strong&gt;TRALI&lt;strong&gt;A&lt;/strong&gt;”. These are Braille numbers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/braille.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;I’m committed to doing all this solving in base R, so no external packages, but &lt;a href=&#34;https://coolbutuseless.github.io/2018/07/31/encoding-and-rendering-grade-1-braille/&#34;&gt;&lt;span class=&#34;citation&#34;&gt;@coolbutuseless&lt;/span&gt; has a great post about Braille in R&lt;/a&gt; where he notes that the system can be bit-encoded quite nicely. Essentially, the positions of the filled boxes can be represented uniquely by a pattern of bits. This means we can store the Braille numbers as bits and identify which one is which. If we store the lookup table as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;nums &amp;lt;- c(1, 5, 3, 11, 9, 7, 15, 13, 6) # 1:9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then we can see one of these (e.g. 8) in the Braille form with&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;print(matrix(intToBits(nums[8])[1:6], ncol=2, byrow = T))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2]
## [1,]   01   00
## [2,]   01   01
## [3,]   00   00&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Taking the patterns under each of the letters&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;code = list(
  B = c(1,1,0,0),
  T = c(1,0,1,0),
  H = c(1,1,1,0),
  A = c(1,0,0,0),
  S = c(1,0,0,1),
  a = c(1,1,0,1)
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then calculating their bit values&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sums &amp;lt;- sapply(code, function(x) sum(x*2^(0:3)))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;we can compare against the lookup table and sort the result to see&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sort(setNames(match(sums, nums), names(code)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## A T B a S H 
## 1 2 3 4 5 6&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which leads us to the cipher we should use for the next challenge!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;The text around the rim looks to be split into sections. The shortest one is&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;txt1 &amp;lt;- &amp;quot;URMWXOZIRGBRM7DRWGSC5WVKGS&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I tried a few different substitution ciphers and hit gold with an &lt;a href=&#34;https://en.wikipedia.org/wiki/Atbash&#34;&gt;Atbash cipher&lt;/a&gt; where the alphabet is simply reversed. That’s easy enough to code up…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;solve_atbash &amp;lt;- function(txt) {
  txt &amp;lt;- strsplit(txt, &amp;quot;&amp;quot;)[[1]]
  atbash &amp;lt;- rev(LETTERS)
  res &amp;lt;- LETTERS[match(txt, atbash)]
  # if an element doesn&amp;#39;t match, it&amp;#39;s probably a number 
  # and can go straight in
  res[is.na(res)] &amp;lt;- txt[is.na(res)]
  paste(res, collapse = &amp;quot;&amp;quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;R having the alphabet available as &lt;code&gt;LETTERS&lt;/code&gt; is certainly nice in this case. Applying that to the string above we get&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;solve_atbash(txt1)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;FINDCLARITYIN7WIDTHX5DEPTH&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which we can space out a bit to read “FIND CLARITY IN 7 WIDTH X 5 DEPTH”. Sounds like we’re going to need a matrix - good news for R!&lt;/p&gt;
&lt;p&gt;Trying the next rim letters&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;txt2 &amp;lt;- &amp;quot;DVZIVZFWZXRLFHRMXLMXVKGZMWNVGRXFOLFHRMVCVXFGRLM&amp;quot;
solve_atbash(txt2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;WEAREAUDACIOUSINCONCEPTANDMETICULOUSINEXECUTION&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which once again needs some spaces, but we can read “WE ARE AUDACIOUS IN CONCEPT AND METICULOUS IN EXECUTION”. No additional hints there, I guess - just some filler.&lt;/p&gt;
&lt;p&gt;The inner ring of text doesn’t reveal anything with the cipher&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;inner &amp;lt;- &amp;quot;BGOAMVOEIATSIRLNGTTNEOGRERGXNTEAIFCECAIEOALEKFNR5LWEFCHDEEAEEE7NMDRXX5&amp;quot;
solve_atbash(inner)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;YTLZNELVRZGHRIOMTGGMVLTIVITCMGVZRUXVXZRVLZOVPUMI5ODVUXSWVVZVVV7MNWICC5&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but we had the earlier clue of a 7 x 5 matrix… that’s only 35 characters, so maybe we need 2&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mat1 &amp;lt;- matrix(strsplit(inner, &amp;quot;&amp;quot;)[[1]][1:35], 5, 7, byrow = TRUE)
mat1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,] &amp;quot;B&amp;quot;  &amp;quot;G&amp;quot;  &amp;quot;O&amp;quot;  &amp;quot;A&amp;quot;  &amp;quot;M&amp;quot;  &amp;quot;V&amp;quot;  &amp;quot;O&amp;quot; 
## [2,] &amp;quot;E&amp;quot;  &amp;quot;I&amp;quot;  &amp;quot;A&amp;quot;  &amp;quot;T&amp;quot;  &amp;quot;S&amp;quot;  &amp;quot;I&amp;quot;  &amp;quot;R&amp;quot; 
## [3,] &amp;quot;L&amp;quot;  &amp;quot;N&amp;quot;  &amp;quot;G&amp;quot;  &amp;quot;T&amp;quot;  &amp;quot;T&amp;quot;  &amp;quot;N&amp;quot;  &amp;quot;E&amp;quot; 
## [4,] &amp;quot;O&amp;quot;  &amp;quot;G&amp;quot;  &amp;quot;R&amp;quot;  &amp;quot;E&amp;quot;  &amp;quot;R&amp;quot;  &amp;quot;G&amp;quot;  &amp;quot;X&amp;quot; 
## [5,] &amp;quot;N&amp;quot;  &amp;quot;T&amp;quot;  &amp;quot;E&amp;quot;  &amp;quot;A&amp;quot;  &amp;quot;I&amp;quot;  &amp;quot;F&amp;quot;  &amp;quot;C&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looking down the columns the text reads consistently, so let’s paste those together&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;res1 &amp;lt;- paste(apply(mat1, 2, paste, collapse = &amp;quot;&amp;quot;), collapse = &amp;quot;&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Doing the same for the remaining letters then joining the results&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mat2 &amp;lt;- matrix(strsplit(inner, &amp;quot;&amp;quot;)[[1]][36:70], 5, 7, byrow = TRUE)
res2 &amp;lt;- paste(apply(mat2, 2, paste, collapse = &amp;quot;&amp;quot;), collapse = &amp;quot;&amp;quot;)
paste(res1, res2, collapse = &amp;quot;&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;BELONGINGTOAGREATTEAMSTRIVINGFOREXC ELLENCEWEMAKEADIFFERENCEXORHEXA5D75&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which, with spaces, reads “BELONGING TO A GREAT TEAM STRIVING FOR EXCELLENCE WE MAKE A DIFFERENCE XOR HEX A5D75”.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;XOR&lt;/code&gt; is familiar from &lt;a href=&#34;https://jcarroll.com.au/2021/12/23/adventures-in-x86-asm/&#34;&gt;the last time I solved the challenge&lt;/a&gt;! The key ‘A5D75’ (l33tspeek for ASD’s 75th Anniversary, I take it) doesn’t have an even number of characters so the bytes won’t work out, so I’ll duplicate it enough times to properly &lt;code&gt;xor&lt;/code&gt; with the input. I can only assume the big chunk of hex text is the remaining input. Typing that in was … interesting.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;hex &amp;lt;- &amp;quot;
E3B8287D4290F7233814D7A47A291DC0F71B2806
D1A53B311CC4B97A0E1CC2B93B31068593332F10
C6A3352F14D1B27A3514D6F7382F1AD0B0322955
D1B83D3801CDB2287D05C0B82A311085A033291D
85A3323855D6BC333119D6FB7A3C11C4A72E3C17
CCBB33290C85B6343955CCBA3B3A1CCBB62E341A
CBF72E3255CAA73F2F14D1B27A341B85A3323855
D6BB333055C4A53F3C55C7B22E2A10C0B97A291D
C0F73E3413C3BE392819D1F73B331185A3323855
CCBA2A3206D6BE3831108B&amp;quot;
hex &amp;lt;- gsub(&amp;quot;\\n&amp;quot;, &amp;quot;&amp;quot;, hex) # remove linebreaks
# split into pairs of bytes
pairs &amp;lt;- sapply(seq(1, nchar(hex), by = 2), function(x) substr(hex, x, x+1))
# xor key from earlier solution, duplicated so that pairs can be extracted
xor &amp;lt;- &amp;quot;A5D75A5D75&amp;quot;
# duplicate to length of input
xor &amp;lt;- rep(sapply(seq(1, nchar(xor), by = 2), function(x) substr(xor, x, x+1)), 40)[1:length(pairs)]
# xor input and key as integers
res &amp;lt;- bitwXor(strtoi(pairs, 16L), strtoi(xor, 16L))
# convert result to ASCII
cat(rawToChar(as.raw(res)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## For 75 years the Australian Signals Directorate has brought together people with the skills, adaptability and imagination to operate in the slim area between the difficult and the impossible.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What a nice challenge! I don’t expect to be getting a phone call from ASD any time soon, but this was certainly fun to solve with R.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Added 2022-09-04&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The inner ring text has a dark/light pattern to it. Treating this as binary&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;txt &amp;lt;- &amp;quot;BGOAMVOEIATSIRLNGTTNEOGRERGXNTEAIFCECAIEOALEKFNR5LWEFCHDEEAEEE7NMDRXX5&amp;quot;
bin &amp;lt;- &amp;quot;1000001101001110001001000011110001011100100110010011000001100100110010&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then spliting into groups (of 7, since &lt;span class=&#34;math inline&#34;&gt;\(2^7 = 128\)&lt;/span&gt; is sufficient for the &lt;a href=&#34;https://www.asciitable.com/&#34;&gt;ASCII text table&lt;/a&gt;)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;bin &amp;lt;- sapply(seq(1, nchar(bin), by = 7), function(x) substr(bin, x, x+6))
bin&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] &amp;quot;1000001&amp;quot; &amp;quot;1010011&amp;quot; &amp;quot;1000100&amp;quot; &amp;quot;1000011&amp;quot; &amp;quot;1100010&amp;quot; &amp;quot;1110010&amp;quot; &amp;quot;0110010&amp;quot;
##  [8] &amp;quot;0110000&amp;quot; &amp;quot;0110010&amp;quot; &amp;quot;0110010&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then converting to ASCII, this time with a base of 2 for the binary data&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;rawToChar(as.raw(strtoi(bin, 2L)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;ASDCbr2022&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which looks to be short for “ASD &lt;a href=&#34;https://en.wikipedia.org/wiki/Canberra&#34;&gt;CANBERRA&lt;/a&gt; 2022”.&lt;/p&gt;
&lt;p&gt;The outer ring additionally has a shaded pattern. Instead of binary, we can treat this as Morse code with a light letter representing a dot, a dark letter representing a dash, and a shaded letter representing a space. If we start at the double space near the top of the coin, the pattern is&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;txt &amp;lt;- &amp;quot;WNVGRXFOLFHRMVCVXFGRLM.URMWXOZIRGBRM7DRWGSC5WVKGSDVZIVZFWZXRLFHRMXLMXVKGZM&amp;quot;
pat &amp;lt;- &amp;quot;-.. ... -... .- .-.. -... . .-. - .--. .- .-. -.- .---- ----. ....- --... &amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Splitting this at the spaces&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;pat &amp;lt;- strsplit(pat, &amp;quot; &amp;quot;)[[1]]
pat&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] &amp;quot;-..&amp;quot;   &amp;quot;...&amp;quot;   &amp;quot;-...&amp;quot;  &amp;quot;.-&amp;quot;    &amp;quot;.-..&amp;quot;  &amp;quot;-...&amp;quot;  &amp;quot;.&amp;quot;     &amp;quot;.-.&amp;quot;   &amp;quot;-&amp;quot;    
## [10] &amp;quot;.--.&amp;quot;  &amp;quot;.-&amp;quot;    &amp;quot;.-.&amp;quot;   &amp;quot;-.-&amp;quot;   &amp;quot;.----&amp;quot; &amp;quot;----.&amp;quot; &amp;quot;....-&amp;quot; &amp;quot;--...&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m still trying to do this in base R, so again, no packages. Instead I’ll load a lookup table&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;morse &amp;lt;-
  data.frame(char = c(
    &amp;quot;A&amp;quot;, &amp;quot;B&amp;quot;, &amp;quot;C&amp;quot;, &amp;quot;D&amp;quot;,
    &amp;quot;E&amp;quot;, &amp;quot;F&amp;quot;, &amp;quot;G&amp;quot;, &amp;quot;H&amp;quot;,
    &amp;quot;I&amp;quot;, &amp;quot;J&amp;quot;, &amp;quot;K&amp;quot;, &amp;quot;L&amp;quot;,
    &amp;quot;M&amp;quot;, &amp;quot;N&amp;quot;, &amp;quot;O&amp;quot;, &amp;quot;P&amp;quot;,
    &amp;quot;Q&amp;quot;, &amp;quot;R&amp;quot;, &amp;quot;S&amp;quot;, &amp;quot;T&amp;quot;,
    &amp;quot;U&amp;quot;, &amp;quot;V&amp;quot;, &amp;quot;W&amp;quot;, &amp;quot;X&amp;quot;,
    &amp;quot;Y&amp;quot;, &amp;quot;Z&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;1&amp;quot;,
    &amp;quot;2&amp;quot;, &amp;quot;3&amp;quot;, &amp;quot;4&amp;quot;, &amp;quot;5&amp;quot;,
    &amp;quot;6&amp;quot;, &amp;quot;7&amp;quot;, &amp;quot;8&amp;quot;, &amp;quot;9&amp;quot;,
    &amp;quot;,&amp;quot;, &amp;quot;?&amp;quot;, &amp;quot;:&amp;quot;, &amp;quot;-&amp;quot;,
    &amp;quot;\&amp;quot;&amp;quot;, &amp;quot;(&amp;quot;, &amp;quot;=&amp;quot;, &amp;quot;*&amp;quot;,
    &amp;quot;.&amp;quot;, &amp;quot;;&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;&amp;#39;&amp;quot;,
    &amp;quot;_&amp;quot;, &amp;quot;)&amp;quot;, &amp;quot;+&amp;quot;, &amp;quot;@&amp;quot;,
    &amp;quot; &amp;quot;),
    row.names = c(
      &amp;quot;.-&amp;quot;, &amp;quot;-...&amp;quot;, &amp;quot;-.-.&amp;quot;, &amp;quot;-..&amp;quot;,
      &amp;quot;.&amp;quot;, &amp;quot;..-.&amp;quot;, &amp;quot;--.&amp;quot;, &amp;quot;....&amp;quot;,
      &amp;quot;..&amp;quot;, &amp;quot;.---&amp;quot;, &amp;quot;-.-&amp;quot;, &amp;quot;.-..&amp;quot;,
      &amp;quot;--&amp;quot;, &amp;quot;-.&amp;quot;, &amp;quot;---&amp;quot;, &amp;quot;.--.&amp;quot;,
      &amp;quot;--.-&amp;quot;, &amp;quot;.-.&amp;quot;, &amp;quot;...&amp;quot;, &amp;quot;-&amp;quot;,
      &amp;quot;..-&amp;quot;, &amp;quot;...-&amp;quot;, &amp;quot;.--&amp;quot;, &amp;quot;-..-&amp;quot;,
      &amp;quot;-.--&amp;quot;, &amp;quot;--..&amp;quot;, &amp;quot;-----&amp;quot;, &amp;quot;.----&amp;quot;,
      &amp;quot;..---&amp;quot;, &amp;quot;...--&amp;quot;, &amp;quot;....-&amp;quot;, &amp;quot;.....&amp;quot;,
      &amp;quot;-....&amp;quot;, &amp;quot;--...&amp;quot;, &amp;quot;---..&amp;quot;, &amp;quot;----.&amp;quot;,
      &amp;quot;__..__&amp;quot;, &amp;quot;..__..&amp;quot;, &amp;quot;___...&amp;quot;, &amp;quot;_...._&amp;quot;,
      &amp;quot;._.._.&amp;quot;, &amp;quot;_.__.&amp;quot;, &amp;quot;_..._&amp;quot;, &amp;quot;_.._&amp;quot;,
      &amp;quot;._._._&amp;quot;, &amp;quot;_._._.&amp;quot;, &amp;quot;_.._.&amp;quot;,
      &amp;quot;.____.&amp;quot;, &amp;quot;..__._&amp;quot;, &amp;quot;_.__._&amp;quot;, &amp;quot;._._.&amp;quot;,
      &amp;quot;.__._.&amp;quot;, &amp;quot;   &amp;quot;)
  )&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I like using rownames as an easy way to lookup values, despite the aversion to them in the tidyverse. Now it’s just a matter of extracting the values based on the lookup&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;paste(morse[pat, ], collapse = &amp;quot;&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;DSBALBERTPARK1947&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which stands for “DSB ALBERT PARK 1947”. Back when the division was started in &lt;a href=&#34;https://www.asd.gov.au/75th-anniversary/timeline/178-1947-defence-signals-bureau-dsb-established&#34;&gt;1947 at Albert Park&lt;/a&gt; it was the &lt;a href=&#34;https://www.asd.gov.au/75th-anniversary/timeline/181-1964-dsb-renamed-defence-signals-division-dsd&#34;&gt;Defence Signals Bureau&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The very last part is the squares and circles - that appears to be the &lt;a href=&#34;https://www.cre8ive.com.au/work/asd/&#34;&gt;ADS’s typeface&lt;/a&gt; and I think just spells out “ASD”&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/asd.jpg&#34; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Thanks for the comments and helpful tips, everyone!&lt;/p&gt;
&lt;p&gt;&lt;s&gt;Now I just need to get one of the coins as a souvenir.&lt;/s&gt; I managed to get one of the coins from the Mint, and they’re now sold out.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 21.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2022-09-04                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date       lib source        
##  blogdown      1.8     2022-02-16 [1] CRAN (R 4.1.2)
##  bookdown      0.24    2021-09-02 [1] CRAN (R 4.1.2)
##  brio          1.1.1   2021-01-20 [3] CRAN (R 4.0.3)
##  bslib         0.3.1   2021-10-06 [1] CRAN (R 4.1.2)
##  cachem        1.0.3   2021-02-04 [3] CRAN (R 4.0.3)
##  callr         3.7.0   2021-04-20 [1] CRAN (R 4.1.2)
##  cli           3.2.0   2022-02-14 [1] CRAN (R 4.1.2)
##  crayon        1.5.0   2022-02-14 [1] CRAN (R 4.1.2)
##  desc          1.4.1   2022-03-06 [1] CRAN (R 4.1.2)
##  devtools      2.4.3   2021-11-30 [1] CRAN (R 4.1.2)
##  digest        0.6.27  2020-10-24 [3] CRAN (R 4.0.3)
##  ellipsis      0.3.2   2021-04-29 [1] CRAN (R 4.1.2)
##  evaluate      0.14    2019-05-28 [3] CRAN (R 4.0.1)
##  fastmap       1.1.0   2021-01-25 [3] CRAN (R 4.0.3)
##  fs            1.5.0   2020-07-31 [3] CRAN (R 4.0.2)
##  glue          1.6.1   2022-01-22 [1] CRAN (R 4.1.2)
##  htmltools     0.5.2   2021-08-25 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [1] CRAN (R 4.1.2)
##  jsonlite      1.7.2   2020-12-09 [3] CRAN (R 4.0.3)
##  knitr         1.37    2021-12-16 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.1   2021-09-24 [1] CRAN (R 4.1.2)
##  magrittr      2.0.1   2020-11-17 [3] CRAN (R 4.0.3)
##  memoise       2.0.0   2021-01-26 [3] CRAN (R 4.0.3)
##  pkgbuild      1.2.0   2020-12-15 [3] CRAN (R 4.0.3)
##  pkgload       1.2.4   2021-11-30 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.5.2   2021-04-30 [1] CRAN (R 4.1.2)
##  ps            1.5.0   2020-12-05 [3] CRAN (R 4.0.3)
##  purrr         0.3.4   2020-04-17 [3] CRAN (R 4.0.1)
##  R6            2.5.0   2020-10-28 [3] CRAN (R 4.0.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.0.1   2022-02-03 [1] CRAN (R 4.1.2)
##  rmarkdown     2.13    2022-03-10 [1] CRAN (R 4.1.2)
##  rprojroot     2.0.2   2020-11-15 [3] CRAN (R 4.0.3)
##  rstudioapi    0.13    2020-11-12 [3] CRAN (R 4.0.3)
##  sass          0.4.0   2021-05-12 [1] CRAN (R 4.1.2)
##  sessioninfo   1.1.1   2018-11-05 [3] CRAN (R 4.0.1)
##  stringi       1.5.3   2020-09-09 [3] CRAN (R 4.0.2)
##  stringr       1.4.0   2019-02-10 [3] CRAN (R 4.0.1)
##  testthat      3.1.2   2022-01-20 [1] CRAN (R 4.1.2)
##  usethis       2.1.5   2021-12-09 [1] CRAN (R 4.1.2)
##  withr         2.5.0   2022-03-03 [1] CRAN (R 4.1.2)
##  xfun          0.30    2022-03-02 [1] CRAN (R 4.1.2)
##  yaml          2.2.1   2020-02-01 [3] CRAN (R 4.0.1)
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Lissajous Curve Matrix in Julia</title>
      <link>https://jcarroll.com.au/2022/05/12/lissajous-curve-matrix-in-julia/</link>
      <pubDate>Thu, 12 May 2022 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2022/05/12/lissajous-curve-matrix-in-julia/</guid>
      <description>&lt;p&gt;Another ‘small learning project’ for me as I continue to learn Julia. I’ve said many
times that small projects with a defined goal are one of the best ways to learn, at
least for me. This one was inspired by &lt;a href=&#34;https://www.reddit.com/r/oddlysatisfying/comments/uc054a/lissajous_polygons/&#34;&gt;yet another Reddit post&lt;/a&gt;&lt;/p&gt;
&lt;iframe id=&#34;reddit-embed&#34; src=&#34;https://www.redditmedia.com/r/oddlysatisfying/comments/uc054a/lissajous_polygons/?ref_source=embed&amp;amp;ref=share&amp;amp;embed=true&#34; sandbox=&#34;allow-scripts allow-same-origin allow-popups&#34; style=&#34;border: none;&#34; height=&#34;620&#34; width=&#34;640&#34; scrolling=&#34;no&#34;&gt;
&lt;/iframe&gt;
&lt;p&gt;These are at least reminiscent of &lt;a href=&#34;https://en.wikipedia.org/wiki/Lissajous_curve&#34;&gt;Lissajous curves&lt;/a&gt; but they
primarily just looked pretty cool - that animation is very nicely put together.&lt;/p&gt;
&lt;p&gt;That graphic was &lt;a href=&#34;https://codepen.io/ScarpMetal/pen/abEPdwK&#34;&gt;made using Typescript&lt;/a&gt; which
is itself neat to begin with, but it looked like something that Julia might be well-suited to,
at least the parts I’ve learned so far. It seems to involve interpolating between points and animation,
both of which I &lt;a href=&#34;https://jcarroll.xyz/2022/04/07/interpolation-animation-in.html&#34;&gt;recently covered on my mini blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Better yet, it appeared that matrix operations might be a useful component, for which Julia seems particularly well-suited.&lt;/p&gt;
&lt;p&gt;The first thing I needed to do was to get a polygon plotted in Julia. This already challenged my existing
knowledge, but that’s where the learning happens. I dabbled with the &lt;code&gt;Shape&lt;/code&gt; class and didn’t get very far. I found
some other implementations that plotted shapes, but none (at least that I understood) that produced a set of
points I could interpolate between.&lt;/p&gt;
&lt;p&gt;I ended up defining my own function that calculates the vertices of an n-sided polygon with a bit of math. There’s
very likely already something that does it, but it failed the discoverability aspect. The function I came up with is&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;&amp;quot;&amp;quot;&amp;quot;
    vertices(center, R, n[, closed])

# Arguments
- `center::Point`: center of polygon
- `R::Real`: circumradius
- `n::Int`: number of sides
- `closed::Bool`: should the first point be repeated?

Polygon has a flat bottom and points progress counterclockwise 
starting at the right end of the base

The final point is the starting point when closed = true
&amp;quot;&amp;quot;&amp;quot;
function vertices(center::Point, R::Real, n::Int, closed::Bool=true) 
    X = center[1] .+ R * cos.(π/n .* (1 .+ 2 .* (0:n-1)) .- π/2)
    Y = center[2] .+ R * sin.(π/n .* (1 .+ 2 .* (0:n-1)) .- π/2)

    res = permutedims([X Y])
    ## append the start point if closed
    if closed
        res = hcat(res, res[:,1])
    end
    return res
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is where playing around with code and data where you know &lt;em&gt;what&lt;/em&gt; you want but
not how to produce it is the most useful. Coming from R, I was at risk of trying to
create a &lt;code&gt;data.frame&lt;/code&gt; of &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; points, but &lt;code&gt;Array&lt;/code&gt;s make more sense here. Getting
the points in the right structure was the biggest learning experience for me - combining
&lt;code&gt;Array&lt;/code&gt;s of &lt;code&gt;Point&lt;/code&gt;s doesn’t quite work in the way I expect coming from R, but I think this works.&lt;/p&gt;
&lt;p&gt;I did play with the idea of making my own &lt;code&gt;struct&lt;/code&gt; for this group of &lt;code&gt;Point&lt;/code&gt;s, but even though
(I think) it inherited from &lt;code&gt;AbstractArray&lt;/code&gt;, none of the &lt;code&gt;Array&lt;/code&gt; methods seemed to work for it - more
to learn for next time!&lt;/p&gt;
&lt;p&gt;I wanted to make sure that the points I generated here seem to make sense, so I can plot them. Getting
the plots to work requires &lt;code&gt;using Plots&lt;/code&gt;, and &lt;code&gt;Point&lt;/code&gt; comes from &lt;code&gt;GeometryBasics&lt;/code&gt;, so&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;using Plots
import GeometryBasics: Point&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then plotting the vertices of a polygon is as easy as&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;a = vertices(Point(0,0), 1, 5, true);
plot(a[1,:], a[2,:], xlim = (-1.2, 1.2), ylim = (-1.2, 1.2), ratio = 1)
scatter!(a[1,:], a[2,:])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;images/vertices.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;And just by changing the number of vertices&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;a = vertices(Point(0,0), 1, 6, true);
plot(a[1,:], a[2,:], xlim = (-1.2, 1.2), ylim = (-1.2, 1.2), ratio = 1)
scatter!(a[1,:], a[2,:])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;images/vertices6.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;I find it somewhat odd that &lt;code&gt;plot&lt;/code&gt; doesn’t have an &lt;code&gt;Array&lt;/code&gt; method and I need to explicitly slice out the
&lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; arguments, but perhaps I’m &lt;a href=&#34;https://uxdesign.cc/youre-holding-it-wrong-how-to-blame-the-user-6ebfd36f5664?gi=99891968d5b4&#34;&gt;“holding it wrong”&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;Next I wanted to interpolate points between these vertices. I played with interpolation
in Julia in my &lt;a href=&#34;https://jcarroll.xyz/2022/04/07/interpolation-animation-in.html&#34;&gt;last mini blog post&lt;/a&gt; so
I knew that function was&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;interpolate(a, b) = t -&amp;gt; ((1.0 - t) * a + t * b)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Interpolating between vertices meant interpolating between any two vertices, then repeating that over pairs. Taking
the case of two vertices first&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;&amp;quot;&amp;quot;&amp;quot;
    _interPoints(pts, steps, slice)

# Arguments
- `pts::Array`: Array of `Point`s representing a polygon
- `steps::Int`: number of points to interpolate
- `slice::Int`: which polygon vertex to begin with; points will  be interpolated to the next vertex

This is an internal function to interpolate points between 
    two vertices of a polygon. It is intended to be used 
    in a `map` across slices of a polygon.
&amp;quot;&amp;quot;&amp;quot;
function _interPoints(pts::Array, steps::Int, slice::Int) 
    int = interpolate(pts[:,slice], pts[:,slice+1])
    explode = [int(t) for t in range(0,1,length=steps)]
    return hcat(explode...)
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which I can test with&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;a = vertices(Point(0,0), 1, 5, true);
b = _interPoints(a, 10, 1);
plot(a[1,:], a[2,:], ratio = 1)
scatter!(b[1,:], b[2,:])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;images/_interPoints.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Then, mapping across pairs of points is just&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;&amp;quot;&amp;quot;&amp;quot;
    interPoints(pts, steps)

# Arguments
- `pts::Array`: Array of `Point`s representing a polygon
- `steps::Int`: number of points to interpolate between each pair of vertices

This takes an `Array` of `Point`s representing polygon vertices and interpolates between the vertices
&amp;quot;&amp;quot;&amp;quot;
function interPoints(pts::Array, steps::Int) 
    res = map(s -&amp;gt; _interPoints(pts, steps, s), 1:(size(pts,2)-1))
    return hcat(res...)
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Plotting all these points&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;a = vertices(Point(0,0), 1, 5, true);
b = interPoints(a, 10);
plot(b[1,:], b[2,:], xlim = (-1.2, 1.2), ylim = (-1.2, 1.2), ratio = 1)
scatter!(b[1,:], b[2,:])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;images/interPoints.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Animating these points is as simple as&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;anim = @animate for t in 1:size(b,2)
    plot(b[1,:], b[2,:], xlim = (-1.2, 1.2), ylim = (-1.2, 1.2), ratio=1)
    scatter!([b[1,t]], [b[2,t]], markersize=8)
end

gif(anim, fps = 12)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;images/n5_points.gif&#34; /&gt;&lt;/p&gt;
&lt;p&gt;and I think that’s pretty great progress towards what I want to make. Now I just need to run more of these
at different speeds, and find the intersections of them.&lt;/p&gt;
&lt;p&gt;Taking the intersection problem first, I just want to create two polygons and extract the &lt;code&gt;x&lt;/code&gt; values from one and
the &lt;code&gt;y&lt;/code&gt; values from the other. Simple enough&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;&amp;quot;&amp;quot;&amp;quot;
Find the intersection of two Arrays (representing polygons)

# Arguments
- `a::Array`: first polygon (for x values)
- `b::Array`: second polygon (for y values)

Take the x values from a and the y values from b
&amp;quot;&amp;quot;&amp;quot;
function intersection(a::Array, b::Array) 
    permutedims(hcat([(a[1, :])...], [(b[2, :])...]))
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;permutedims&lt;/code&gt; was the big win for me here - I naively expected to be able to transpose
an &lt;code&gt;Array&lt;/code&gt; but that ends up with some &lt;code&gt;LinearAlgebra.Adjoint&lt;/code&gt; mess and I got confused&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;[1 2; 3 4]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 2×2 Array{Int64,2}:
##  1  2
##  3  4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;
[1 2; 3 4]&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 2×2 Adjoint{Int64,Array{Int64,2}}:
##  1  3
##  2  4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Anyway, this appears to be able to take the intersection of two &lt;code&gt;Array&lt;/code&gt;s. Let’s plot it!&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;t1 = interPoints(vertices(Point(2,8), 0.5, 5), 10);
t2 = interPoints(vertices(Point(1,7), 0.5, 5), 10);
tx = intersection(t1, t2);

plot(t1[1,:], t1[2,:], xlim = (0,3.5), ylim = (6,9), ratio = 1)
plot!(t2[1,:], t2[2,:])
plot!(tx[1,:], tx[2,:])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;images/intersection.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Perfect! Now I just need to do it a bunch more times (at different ‘speeds’) and animate it.&lt;/p&gt;
&lt;p&gt;I originally worked out the array math by hand and found a suitable number of points to plot
for any given polygon and which multiplicative factors I could use, then I worked backwards to
formalise it into a function&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;&amp;quot;&amp;quot;&amp;quot;

    speed_factor(poly, speed)

# Arguments
- `poly::Array`: Array of `Point`s representing a polygon
- `speed::Real`: mulitiplicative factor representing how the number of times a polygon should be traversed
&amp;quot;&amp;quot;&amp;quot;
function speed_factor(poly::Array, speed::Real)
    if (speed % 1 == 0)
        res = repeat(poly, outer = (1,Int(speed)))
    else 
        n = Int(floor(speed / 1))
        res = repeat(poly, outer=(1,n))
        n_rem = Int(speed*size(poly,2)-size(res,2))
        res = hcat(res, poly[:,1:n_rem])
    end
    res
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I create a polygon of 72 interpolated points, I can create another with the same number of
points but with larger gaps between them. This means the ‘faster’ polygon will loop around some &lt;code&gt;n&amp;gt;1&lt;/code&gt; number
of times.&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;r = 0.4; # circumradius for the polygon
d = 3;   # number of vertices

# Both produce a 2x72 Array{Float64,2}
tx1 = interPoints(vertices(Point(2,6), r, d), 24)
tx2 = speed_factor(interPoints(vertices(Point(3,6), r, d), 16) , 1.5) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can create a series of these, say, at speeds of 1, 1.5, 2, 2.4, and 3. These are just nice
numbers which are all integer divisors of the largest number of points (72)&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;## n = 3
r = 0.4;
d = 3;

tx1 = interPoints(vertices(Point(2,6), r, d), 24)
tx2 = speed_factor(interPoints(vertices(Point(3,6), r, d), 16), 1.5) 
tx3 = speed_factor(interPoints(vertices(Point(4,6), r, d), 12), 2)
tx4 = speed_factor(interPoints(vertices(Point(5,6), r, d), 10), 2.4)
tx5 = speed_factor(interPoints(vertices(Point(6,6), r, d), 8), 3)

ty1 = interPoints(vertices(Point(1,5), r, d), 24)
ty2 = speed_factor(interPoints(vertices(Point(1,4), r, d), 16), 1.5)
ty3 = speed_factor(interPoints(vertices(Point(1,3), r, d), 12), 2)
ty4 = speed_factor(interPoints(vertices(Point(1,2), r, d), 10), 2.4)
ty5 = speed_factor(interPoints(vertices(Point(1,1), r, d), 8), 3)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The variable name is arbitrary, but these are a sequence of polygons along the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; axes of
some plot area.&lt;/p&gt;
&lt;p&gt;One thing that I really like about Julia is that &lt;em&gt;anything&lt;/em&gt; can be in an &lt;code&gt;Array&lt;/code&gt; (similar to lists in R) so
I can combine these groups of points into an &lt;code&gt;Array&lt;/code&gt; of &lt;code&gt;Array&lt;/code&gt;s&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;allx = [tx1, tx2, tx3, tx4, tx5]
ally = [ty1, ty2, ty3, ty4, ty5]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, how to calculate all the intersections? Julia of course does “broadcasting” where we can take some
operation and (in R parlance) “vectorize it”. That initially led me to&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;intersection.(allx, ally)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which does indeed do that - it produces a &lt;code&gt;5-element Array{Array{Float64,2},1}&lt;/code&gt; but that’s not what I wanted…
this &lt;em&gt;only&lt;/em&gt; calculates the ‘diagonal’ of &lt;code&gt;intersection(tx1, ty1)&lt;/code&gt;, &lt;code&gt;intersection(tx2, ty2)&lt;/code&gt;, …&lt;/p&gt;
&lt;p&gt;Thankfully, Julia &lt;em&gt;also&lt;/em&gt; has list comprehensions, so the full ‘matrix’ of intersections is actually&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;allint = [intersection(x, y) for x in allx, y in ally]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which produces a &lt;code&gt;5×5 Array{Array{Float64,2},2}&lt;/code&gt; - the full matrix! With that in place, we now have all the
pieces we need, so we just need to plot them.&lt;/p&gt;
&lt;p&gt;The following sets up a plot on every ‘timestep’ (one per point in the interpolation) where it redraws the canvas,
with the progressive drawing of each polygon and the intersections, plus some tracking lines along the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;
extractions. One of the very neat things I entirely failed to appreciate earlier was the concept of
enumerated objects - Julia knows that if I ask for &lt;code&gt;x in obj&lt;/code&gt; I want to iterate over all the elements&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;bbox = Point(6.5,6.5);

anim3 = @animate for t in 1:size(tx1,2)
    plot(xlim=(0,bbox[2]), ylim=(0,bbox[2]), 
        legend=false, ratio=1, axis=nothing, border=:none, 
        background_color=&amp;quot;black&amp;quot;, size=(1200,1200))
    for p in 1:size(allx,1)
        plot!(allx[p][1,1:t], allx[p][2,1:t], color=p, linewidth=6)
        plot!(ally[p][1,1:t], ally[p][2,1:t], color=p, linewidth=6)
        
        plot!([allx[p][1,t], allx[p][1,t]], [0.5, allx[p][2,t]], color=&amp;quot;grey&amp;quot;, alpha=0.5, linewidth=5)
        plot!([ally[p][1,t], bbox[2]], [ally[p][2,t], ally[p][2,t]], color=&amp;quot;grey&amp;quot;, alpha=0.5, linewidth=5)
    end
    for p in allint
        plot!(p[1,1:t], p[2,1:t], color=&amp;quot;blue&amp;quot;, linewidth=5)
    end
end

gif(anim3, &amp;quot;n3.gif&amp;quot;, fps=12)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And, finally, the result&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/n3.gif&#34; /&gt;&lt;/p&gt;
&lt;p&gt;With all that in place, it’s reasonably straightforward to adapt this to other polygons. For &lt;code&gt;n=4&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;r = 0.4;
d = 4;

tx1 = interPoints(vertices(Point(2,6), r, d), 24)
tx2 = speed_factor(interPoints(vertices(Point(3,6), r, d), 16), 1.5)
tx3 = speed_factor(interPoints(vertices(Point(4,6), r, d), 12), 2)
tx4 = speed_factor(interPoints(vertices(Point(5,6), r, d), 10), 2.4)
tx5 = speed_factor(interPoints(vertices(Point(6,6), r, d), 8), 3)

ty1 = interPoints(vertices(Point(1,5), r, d), 24)
ty2 = speed_factor(interPoints(vertices(Point(1,4), r, d), 16), 1.5)
ty3 = speed_factor(interPoints(vertices(Point(1,3), r, d), 12), 2)
ty4 = speed_factor(interPoints(vertices(Point(1,2), r, d), 10), 2.4)
ty5 = speed_factor(interPoints(vertices(Point(1,1), r, d), 8), 3)

allx = [tx1, tx2, tx3, tx4, tx5]
ally = [ty1, ty2, ty3, ty4, ty5]
allint = [intersection(x, y) for x in allx, y in ally]

bbox = Point(6.5,6.5);

anim4 = @animate for t in 1:size(tx1,2)
    plot(xlim=(0,bbox[2]), ylim=(0,bbox[2]), 
        legend=false, ratio=1, axis=nothing, border=:none, 
        background_color=&amp;quot;black&amp;quot;, size=(1200,1200))
    for p in 1:size(allx,1)
        plot!(allx[p][1,1:t], allx[p][2,1:t], color=p, linewidth=6)
        plot!(ally[p][1,1:t], ally[p][2,1:t], color=p, linewidth=6)
        
        plot!([allx[p][1,t], allx[p][1,t]], [0.5, allx[p][2,t]], color=&amp;quot;grey&amp;quot;, alpha=0.5, linewidth=5)
        plot!([ally[p][1,t], bbox[2]], [ally[p][2,t], ally[p][2,t]], color=&amp;quot;grey&amp;quot;, alpha=0.5, linewidth=5)
    end
    for p in allint
        plot!(p[1,1:t], p[2,1:t], color=&amp;quot;blue&amp;quot;, linewidth=5)
    end
end

gif(anim4, &amp;quot;n4.gif&amp;quot;, fps=12)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;images/n4.gif&#34; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;n=5&lt;/code&gt; (very similar code)&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/n5.gif&#34; /&gt;&lt;/p&gt;
&lt;p&gt;and &lt;code&gt;n=6&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/n6.gif&#34; /&gt;&lt;/p&gt;
&lt;p&gt;I was extremely happy to see these come together, and I’m genuinely surprised by how little code it took. I could
certainly imagine trying to do the same in R, but I have doubts that it would come together quite so cleanly.&lt;/p&gt;
&lt;p&gt;This is definitely still part of my journey towards learning Julia, so if there’s something in here you can spot
that I could have done better, I do encourage you to let me know! Either here in the comments or on &lt;a href=&#34;https://twitter.com/carroll_jono&#34;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The code for generating all of this can be found &lt;a href=&#34;https://gist.github.com/jonocarroll/e22ea4982a27e6663ec75b82b55b3ec3&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 21.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2022-05-12                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date       lib source        
##  blogdown      1.8     2022-02-16 [1] CRAN (R 4.1.2)
##  bookdown      0.24    2021-09-02 [1] CRAN (R 4.1.2)
##  brio          1.1.1   2021-01-20 [3] CRAN (R 4.0.3)
##  bslib         0.3.1   2021-10-06 [1] CRAN (R 4.1.2)
##  cachem        1.0.3   2021-02-04 [3] CRAN (R 4.0.3)
##  callr         3.7.0   2021-04-20 [1] CRAN (R 4.1.2)
##  cli           3.2.0   2022-02-14 [1] CRAN (R 4.1.2)
##  crayon        1.5.0   2022-02-14 [1] CRAN (R 4.1.2)
##  desc          1.4.1   2022-03-06 [1] CRAN (R 4.1.2)
##  devtools      2.4.3   2021-11-30 [1] CRAN (R 4.1.2)
##  digest        0.6.27  2020-10-24 [3] CRAN (R 4.0.3)
##  ellipsis      0.3.2   2021-04-29 [1] CRAN (R 4.1.2)
##  evaluate      0.14    2019-05-28 [3] CRAN (R 4.0.1)
##  fastmap       1.1.0   2021-01-25 [3] CRAN (R 4.0.3)
##  fs            1.5.0   2020-07-31 [3] CRAN (R 4.0.2)
##  glue          1.6.1   2022-01-22 [1] CRAN (R 4.1.2)
##  htmltools     0.5.2   2021-08-25 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [1] CRAN (R 4.1.2)
##  jsonlite      1.7.2   2020-12-09 [3] CRAN (R 4.0.3)
##  JuliaCall     0.17.4  2021-05-16 [1] CRAN (R 4.1.2)
##  knitr         1.37    2021-12-16 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.1   2021-09-24 [1] CRAN (R 4.1.2)
##  magrittr      2.0.1   2020-11-17 [3] CRAN (R 4.0.3)
##  memoise       2.0.0   2021-01-26 [3] CRAN (R 4.0.3)
##  pkgbuild      1.2.0   2020-12-15 [3] CRAN (R 4.0.3)
##  pkgload       1.2.4   2021-11-30 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.5.2   2021-04-30 [1] CRAN (R 4.1.2)
##  ps            1.5.0   2020-12-05 [3] CRAN (R 4.0.3)
##  purrr         0.3.4   2020-04-17 [3] CRAN (R 4.0.1)
##  R6            2.5.0   2020-10-28 [3] CRAN (R 4.0.2)
##  Rcpp          1.0.6   2021-01-15 [3] CRAN (R 4.0.3)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.0.1   2022-02-03 [1] CRAN (R 4.1.2)
##  rmarkdown     2.13    2022-03-10 [1] CRAN (R 4.1.2)
##  rprojroot     2.0.2   2020-11-15 [3] CRAN (R 4.0.3)
##  rstudioapi    0.13    2020-11-12 [3] CRAN (R 4.0.3)
##  sass          0.4.0   2021-05-12 [1] CRAN (R 4.1.2)
##  sessioninfo   1.1.1   2018-11-05 [3] CRAN (R 4.0.1)
##  stringi       1.5.3   2020-09-09 [3] CRAN (R 4.0.2)
##  stringr       1.4.0   2019-02-10 [3] CRAN (R 4.0.1)
##  testthat      3.1.2   2022-01-20 [1] CRAN (R 4.1.2)
##  usethis       2.1.5   2021-12-09 [1] CRAN (R 4.1.2)
##  withr         2.5.0   2022-03-03 [1] CRAN (R 4.1.2)
##  xfun          0.30    2022-03-02 [1] CRAN (R 4.1.2)
##  yaml          2.2.1   2020-02-01 [3] CRAN (R 4.0.1)
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Where for (loop) ARt Thou?</title>
      <link>https://jcarroll.com.au/2022/04/22/where-for-loop-art-thou/</link>
      <pubDate>Fri, 22 Apr 2022 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2022/04/22/where-for-loop-art-thou/</guid>
      <description>&lt;p&gt;I’ve long been interested in exactly &lt;em&gt;how&lt;/em&gt; R works - not quite enough for me to learn &lt;em&gt;all&lt;/em&gt; the
internals, but I was surprised that I could not find a clear guide towards exactly how vectorization works at the deepest level.&lt;/p&gt;
&lt;p&gt;Let’s say we want to add two vectors which we’ve defined as &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- c(2, 4, 6)
y &amp;lt;- c(1, 3, 2)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One way to do this (the verbose, elementwise way) would be to add each pair of elements&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;c(x[1] + y[1], x[2] + y[2], x[3] + y[3])&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3 7 8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but if you are familiar with not repeating yourself, you might write this in a loop. Best practice
involves pre-filling the result to the correct size&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;res &amp;lt;- c(NA, NA, NA)
for (i in 1:3) {
  res[i] &amp;lt;- x[i] + y[i]
}
res&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3 7 8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There, we wrote a &lt;code&gt;for&lt;/code&gt; loop.&lt;/p&gt;
&lt;p&gt;Now, if you’ve ever seen R tutorials or discussions, you’ve probably had it drilled into you that
this is “bad” and should be replaced with something else. One of those options is an &lt;code&gt;apply&lt;/code&gt; family
function&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plus &amp;lt;- function(i) {
  x[i] + y[i]
}
sapply(1:3, plus)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3 7 8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or something ‘tidier’&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;purrr::map_dbl(1:3, plus)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3 7 8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(yes, yes, these functions are ‘bad’ because they don’t take &lt;code&gt;x&lt;/code&gt; or &lt;code&gt;y&lt;/code&gt; as arguments) but this stil
performs the operation elementwise. If you’ve seen even more R tutorais/discussions you’ve
probably been seen that &lt;em&gt;vectorization&lt;/em&gt; is very handy - The R function &lt;code&gt;+&lt;/code&gt; knows what to do with objects that
aren’t just a single value, and does what you might expect&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x + y&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3 7 8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if you’ve really read a lot about R, you’ll know that ‘under the hood’ a &lt;code&gt;for&lt;/code&gt;-loop
is involved in every one of these, but it’s “lower down”, “at the C level”. Jenny Bryan makes the
point that &lt;a href=&#34;https://speakerdeck.com/jennybc/row-oriented-workflows-in-r-with-the-tidyverse?slide=16&#34;&gt;“Of course someone has to write loops / It doesn’t have to be you”&lt;/a&gt; and for this reason,
vectorization in R is of great benefit.&lt;/p&gt;
&lt;p&gt;So, there &lt;em&gt;is&lt;/em&gt; a loop, but where exactly does that happen?&lt;/p&gt;
&lt;p&gt;At some point, the computer needs to add the elements of &lt;code&gt;x&lt;/code&gt; to the elements of &lt;code&gt;y&lt;/code&gt;, and the simplest versions of this
happens one element at a time, in a loop. There’s a big sidetrack here about &lt;a href=&#34;https://en.wikipedia.org/wiki/SIMD&#34;&gt;SIMD&lt;/a&gt;
which I’ll try to avoid, but I will mention that the Microsoft fork of R (&lt;a href=&#34;https://mran.revolutionanalytics.com/open/&#34;&gt;artist, formerly known as Revolution R&lt;/a&gt;) running on Intel chips can do SIMD in MKL.&lt;/p&gt;
&lt;p&gt;So, let’s start at the operator.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;`+`&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## function (e1, e2)  .Primitive(&amp;quot;+&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Digging into primitives is a little tricky, but &lt;code&gt;{pryr}&lt;/code&gt; can help&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;pryr::show_c_source(.Primitive(&amp;quot;+&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r bg-success&#34;&gt;&lt;code&gt;+ is implemented by do_arith with op = PLUSOP&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can browse a copy of the source for &lt;code&gt;do_arith&lt;/code&gt; (in arithmetic.c) &lt;a href=&#34;https://github.com/wch/r-source/blob/fe82da3baf849fcd3cc7dbc31c6abc72b57aa083/src/main/arithmetic.c#L417&#34;&gt;here&lt;/a&gt; where we see some
logic paths for scalars and vectors. Let’s assume we’re working with our example which has &lt;code&gt;length(x) == length(y) &amp;gt; 1&lt;/code&gt;. With two non-scalar arguments&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;if !IS_SCALAR and argc == length(arg) == 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/wch/r-source/blob/fe82da3baf849fcd3cc7dbc31c6abc72b57aa083/src/main/arithmetic.c#L525&#34;&gt;This leads&lt;/a&gt; us to call &lt;a href=&#34;https://github.com/wch/r-source/blob/fe82da3baf849fcd3cc7dbc31c6abc72b57aa083/src/main/arithmetic.c#L549&#34;&gt;&lt;code&gt;R_binary&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Depending on the class of the arguments, we need to call different functions, but for the sake of our example let’s say we have non-integer real numbers so we fork to &lt;a href=&#34;https://github.com/wch/r-source/blob/fe82da3baf849fcd3cc7dbc31c6abc72b57aa083/src/main/arithmetic.c#L975&#34;&gt;&lt;code&gt;real_binary&lt;/code&gt;&lt;/a&gt;. This takes a &lt;code&gt;code&lt;/code&gt; argument for which type of operation we’re performing, and in our case it’s &lt;code&gt;PLUSOP&lt;/code&gt; (noted above). There’s a &lt;a href=&#34;https://github.com/wch/r-source/blob/fe82da3baf849fcd3cc7dbc31c6abc72b57aa083/src/main/arithmetic.c#L991&#34;&gt;&lt;code&gt;case&lt;/code&gt; branch for this&lt;/a&gt; in which case, provided the arguments are of the same length (&lt;code&gt;n1 == n2&lt;/code&gt;) we &lt;a href=&#34;https://github.com/wch/r-source/blob/fe82da3baf849fcd3cc7dbc31c6abc72b57aa083/src/main/arithmetic.c#L1004-L1005&#34;&gt;call&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;R_ITERATE_CHECK(NINTERRUPT, n, i, da[i] = dx[i] + dy[i];);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s starting to look a lot like a loop - there’s an iterator &lt;code&gt;i&lt;/code&gt; and we’re going to call another function.&lt;/p&gt;
&lt;p&gt;This jumps us over to a &lt;a href=&#34;https://github.com/wch/r-source/blob/d22ee2fc0dc8142b23eed9f46edf76ea9d3ca69a/src/include/R_ext/Itermacros.h#L53&#34;&gt;different file&lt;/a&gt; where we see &lt;code&gt;LOOP_WITH_INTERRUPT_CHECK&lt;/code&gt; definitely performs some sort of loop. This takes the body above and the argument &lt;a href=&#34;https://github.com/wch/r-source/blob/d22ee2fc0dc8142b23eed9f46edf76ea9d3ca69a/src/include/R_ext/Itermacros.h#L44&#34;&gt;&lt;code&gt;LOOP_ITERATE_CORE&lt;/code&gt;&lt;/a&gt; which is finally the actual loop!&lt;/p&gt;
&lt;pre class=&#34;c&#34;&gt;&lt;code&gt;#define R_ITERATE_CORE(n, i, loop_body) do {    \
   for (; i &amp;lt; n; ++i) { loop_body } \
} while (0)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so, that’s where the &lt;em&gt;actual&lt;/em&gt; loop in a vectorized R call happens! &lt;em&gt;ALL&lt;/em&gt; that sits behind the innocent-looking &lt;code&gt;+&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That was thoroughly satisfying, but I did originally have in mind comparing R to another language - one where loops aren’t frowned upon because of performance, but rather encouraged… How do Julia loops differ?&lt;/p&gt;
&lt;p&gt;Julia is not a vectorized language per se, but it has a neat ability to “vectorize” any operation, though in Julia syntax it’s “broadcasting”.&lt;/p&gt;
&lt;p&gt;Simple addition can combine scalar values&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;3+4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 7&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Julia actually has scalar values (in R, even a single value is just a vector of length 1) so a single value could be&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;typeof(3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## Int64&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;whereas several values need to be an &lt;code&gt;Array&lt;/code&gt;, even if it only has 1 dimension&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;Vector{Int64}([1, 2, 3])&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 3-element Array{Int64,1}:
##  1
##  2
##  3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Trying to add two &lt;code&gt;Arrays&lt;/code&gt; does work&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;[1, 2, 3] + [4, 5, 6]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 3-element Array{Int64,1}:
##  5
##  7
##  9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but only because a specific method has been written for this case, i.e.&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;methods(+, (Array, Array))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # 1 method for generic function &amp;quot;+&amp;quot;:
## [1] +(A::Array, Bs::Array...) in Base at arraymath.jl:43&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One thing I particularly like is that we can see &lt;em&gt;exactly&lt;/em&gt; which method was called using the &lt;code&gt;@which&lt;/code&gt; macro&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;@which [1, 2, 3, 4] + [1, 2, 3, 4]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia bg-success&#34;&gt;&lt;code&gt;+(A::Array, Bs::Array...) in Base at arraymath.jl:43&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;something that I really wish &lt;a href=&#34;https://twitter.com/BrodieGaslam/status/971771827335974915?s=20&amp;amp;t=z-p-4RoHzw5rZ656Igxp_g&#34;&gt;was easier to do in R&lt;/a&gt;. The &lt;code&gt;@edit&lt;/code&gt; macro even jumps us right into the actual code for this dispatched call.&lt;/p&gt;
&lt;p&gt;This ‘add vectors’ problem &lt;em&gt;can&lt;/em&gt; be solved through broadcasting, which performs an operation elementwise&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;[1, 2, 3] .+ [4, 5, 6]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 3-element Array{Int64,1}:
##  5
##  7
##  9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The fun fact about this &lt;a href=&#34;https://twitter.com/carroll_jono/status/1501164366233624582?s=20&amp;amp;t=WUpy7m-RL2SQCoUN_S5SbA&#34;&gt;I recently learned&lt;/a&gt; was that broadcasting works on &lt;em&gt;any&lt;/em&gt; operation, even if that’s the pipe itself&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;[&amp;quot;a&amp;quot;, &amp;quot;list&amp;quot;, &amp;quot;of&amp;quot;, &amp;quot;strings&amp;quot;] .|&amp;gt; [uppercase, reverse, titlecase, length]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 4-element Array{Any,1}:
##   &amp;quot;A&amp;quot;
##   &amp;quot;tsil&amp;quot;
##   &amp;quot;Of&amp;quot;
##  7&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Back to our loops, the method for &lt;code&gt;+&lt;/code&gt; on two &lt;code&gt;Array&lt;/code&gt;s points us to &lt;a href=&#34;https://github.com/JuliaLang/julia/blob/3cff21e725097673f969c19f8f0992c9a0838ab3/base/arraymath.jl#L12&#34;&gt;arraymath.jl&lt;/a&gt; (linked to current relevant line) which contains&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;function +(A::Array, Bs::Array...)
    for B in Bs
        promote_shape(A, B) # check size compatibility
    end
    broadcast_preserving_zero_d(+, A, Bs...)
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last part of that is the meaningful part, and that leads to &lt;a href=&#34;https://github.com/JuliaLang/julia/blame/b5871eb1b5def4b6ef6be15a8ef53cfb8e4fe309/base/broadcast.jl#L847&#34;&gt;&lt;code&gt;Broadcast.broadcast_preserving_zero_d&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This starts to get out of my depth, but essentially&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;@inline function broadcast_preserving_zero_d(f, As...)
    bc = broadcasted(f, As...)
    r = materialize(bc)
    return length(axes(bc)) == 0 ? fill!(similar(bc, typeof(r)), r) : r
end

@inline broadcast(f, t::NTuple{N,Any}, ts::Vararg{NTuple{N,Any}}) where {N} = map(f, t, ts...)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;involves a &lt;code&gt;map&lt;/code&gt; operation to achieve the broadcasting.&lt;/p&gt;
&lt;p&gt;Perhaps that’s a problem to tackle when I’m better at digging through Julia.&lt;/p&gt;
&lt;p&gt;As always, comments, suggestions, and anything else welcome!&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 21.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2022-04-22                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date       lib source        
##  blogdown      1.8     2022-02-16 [1] CRAN (R 4.1.2)
##  bookdown      0.24    2021-09-02 [1] CRAN (R 4.1.2)
##  brio          1.1.1   2021-01-20 [3] CRAN (R 4.0.3)
##  bslib         0.3.1   2021-10-06 [1] CRAN (R 4.1.2)
##  cachem        1.0.3   2021-02-04 [3] CRAN (R 4.0.3)
##  callr         3.7.0   2021-04-20 [1] CRAN (R 4.1.2)
##  cli           3.2.0   2022-02-14 [1] CRAN (R 4.1.2)
##  crayon        1.5.0   2022-02-14 [1] CRAN (R 4.1.2)
##  desc          1.4.1   2022-03-06 [1] CRAN (R 4.1.2)
##  devtools      2.4.3   2021-11-30 [1] CRAN (R 4.1.2)
##  digest        0.6.27  2020-10-24 [3] CRAN (R 4.0.3)
##  ellipsis      0.3.2   2021-04-29 [1] CRAN (R 4.1.2)
##  evaluate      0.14    2019-05-28 [3] CRAN (R 4.0.1)
##  fastmap       1.1.0   2021-01-25 [3] CRAN (R 4.0.3)
##  fs            1.5.0   2020-07-31 [3] CRAN (R 4.0.2)
##  glue          1.6.1   2022-01-22 [1] CRAN (R 4.1.2)
##  htmltools     0.5.2   2021-08-25 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [1] CRAN (R 4.1.2)
##  jsonlite      1.7.2   2020-12-09 [3] CRAN (R 4.0.3)
##  JuliaCall   * 0.17.4  2021-05-16 [1] CRAN (R 4.1.2)
##  knitr         1.37    2021-12-16 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.1   2021-09-24 [1] CRAN (R 4.1.2)
##  magrittr      2.0.1   2020-11-17 [3] CRAN (R 4.0.3)
##  memoise       2.0.0   2021-01-26 [3] CRAN (R 4.0.3)
##  pkgbuild      1.2.0   2020-12-15 [3] CRAN (R 4.0.3)
##  pkgload       1.2.4   2021-11-30 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.5.2   2021-04-30 [1] CRAN (R 4.1.2)
##  ps            1.5.0   2020-12-05 [3] CRAN (R 4.0.3)
##  purrr         0.3.4   2020-04-17 [3] CRAN (R 4.0.1)
##  R6            2.5.0   2020-10-28 [3] CRAN (R 4.0.2)
##  Rcpp          1.0.6   2021-01-15 [3] CRAN (R 4.0.3)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.0.1   2022-02-03 [1] CRAN (R 4.1.2)
##  rmarkdown     2.13    2022-03-10 [1] CRAN (R 4.1.2)
##  rprojroot     2.0.2   2020-11-15 [3] CRAN (R 4.0.3)
##  rstudioapi    0.13    2020-11-12 [3] CRAN (R 4.0.3)
##  sass          0.4.0   2021-05-12 [1] CRAN (R 4.1.2)
##  sessioninfo   1.1.1   2018-11-05 [3] CRAN (R 4.0.1)
##  stringi       1.5.3   2020-09-09 [3] CRAN (R 4.0.2)
##  stringr       1.4.0   2019-02-10 [3] CRAN (R 4.0.1)
##  testthat      3.1.2   2022-01-20 [1] CRAN (R 4.1.2)
##  usethis       2.1.5   2021-12-09 [1] CRAN (R 4.1.2)
##  withr         2.5.0   2022-03-03 [1] CRAN (R 4.1.2)
##  xfun          0.30    2022-03-02 [1] CRAN (R 4.1.2)
##  yaml          2.2.1   2020-02-01 [3] CRAN (R 4.0.1)
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Codegolf - Lisp Edition</title>
      <link>https://jcarroll.com.au/2022/04/02/codegolf-lisp-edition/</link>
      <pubDate>Sat, 02 Apr 2022 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2022/04/02/codegolf-lisp-edition/</guid>
      <description>&lt;p&gt;I occasionally like a round of code-golf (e.g. &lt;a href=&#34;https://jcarroll.com.au/2022/03/26/codegolfing-minecraft-lighting/&#34;&gt;recently&lt;/a&gt;) and I try to solve these with R, but &lt;a href=&#34;https://codegolf.stackexchange.com/questions/245778/numbers-in-2050&#34;&gt;this one&lt;/a&gt; gave me some hope that I could make use of a really cool feature I knew about in common lisp.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;2022/04/02/codegolf-lisp-edition/images/lisp_cycles.png&#34; alt=&#34;&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;lisp is timeless. &lt;a href=&#34;https://xkcd.com/297&#34; class=&#34;uri&#34;&gt;https://xkcd.com/297&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I have occasionally tinkered with lisp - initially because I learned emacs, but later because it’s really interesting and does &lt;a href=&#34;https://www.milesmcbain.com/posts/the-roots-of-quotation/&#34;&gt;teach a lot about quoting&lt;/a&gt;. &lt;a href=&#34;https://www.amazon.com.au/Practical-Common-LISP-Peter-Seibel/dp/1590592395&#34;&gt;Practical Common Lisp&lt;/a&gt; is a book I’m still (slowly) making my way through, but it’s a great read so far.&lt;/p&gt;
&lt;p&gt;There’s a lot you can do with lisp - you can even &lt;a href=&#34;https://github.com/dirkschumacher/llr&#34;&gt;connect it up to R&lt;/a&gt; (sort of).&lt;/p&gt;
&lt;p&gt;Anyway, back to the code-golf. The problem as stated:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s 2050, and people have decided to write numbers in a new way. They want less to memorize, and number to be able to be written quicker.
For every place value(ones, tens, hundreds, etc.) the number is written with the number in that place, a hyphen, and the place value name. “zero” and it’s place value does not need to be written.
The number 0 and negative numbers do not need to be handled, so don’t worry about those.&lt;/p&gt;
&lt;p&gt;Input:
The input will be a positive integer up to 3 digits.&lt;/p&gt;
&lt;p&gt;Output:
The output should be a string that looks like something below.&lt;/p&gt;
&lt;p&gt;Test cases:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;56 =&amp;gt; five-ten six
11 =&amp;gt; ten one
72 =&amp;gt; seven-ten two
478 =&amp;gt; four-hundred seven-ten eight
754 =&amp;gt; seven-hundred five-ten four
750 =&amp;gt; seven-hundred five-ten
507 =&amp;gt; five-hundred seven&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On it’s own, this seems like it’s going to need some sort of mapping from digits to words. R &lt;em&gt;does&lt;/em&gt; have one of those in the &lt;a href=&#34;https://cran.r-project.org/package=english&#34;&gt;{english}&lt;/a&gt; package (I know this because I used it the last example in &lt;a href=&#34;https://jcarroll.com.au/2020/03/09/iseven-without-modulo/&#34;&gt;this post&lt;/a&gt;) but code-golf doesn’t really allow you to use external packages (mostly).&lt;/p&gt;
&lt;p&gt;What gave me hope is something I really wish R had natively, and that the &lt;code&gt;&#34;~R&#34;&lt;/code&gt; option of lisp’s format method&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(format nil &amp;quot;~R&amp;quot; 14000605) &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;&amp;quot;fourteen million six hundred five&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works really nicely, and seemed like an efficient route to a code-golf solution.&lt;/p&gt;
&lt;p&gt;What was missing from this? For starters, we explicity need the tens digits to be of the form ‘n-ten’, which isn’t the case here&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(format nil &amp;quot;~R&amp;quot; 478) &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;&amp;quot;four hundred seventy-eight&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I considered trying to do a text replacement of “ty” to “-ten” but, alas,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(format nil &amp;quot;~R&amp;quot; 56) &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;&amp;quot;fifty-six&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;is going to break that pattern.&lt;/p&gt;
&lt;p&gt;The alternative, I suppose, is to split out the digits and add the “-hundred” and “-ten” parts. This took me down a rabbit hole, but eventually I managed to pull together enough stack overflow answers to achieve&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(map &amp;#39;list #&amp;#39;digit-char-p (prin1-to-string 458))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;(4 5 8)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s (hopefully) a faster way to do that, but it works.&lt;/p&gt;
&lt;p&gt;Converting each of these digits to words means applying the format in a map. That… also took a while to figure out, and this is probably overkill&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(mapcar (lambda (it) (format nil &amp;quot;~R&amp;quot; it)) (map &amp;#39;list #&amp;#39;digit-char-p (prin1-to-string 458)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;(&amp;quot;four&amp;quot; &amp;quot;five&amp;quot; &amp;quot;eight&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pasting together this result with a list of suffixes requires the &lt;code&gt;concatenate&lt;/code&gt; operator, again in a map, but with a lambda function to do this pairwise, otherwise it just appends the lists&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(mapcar (lambda(j k) (concatenate &amp;#39;string j k)) (mapcar (lambda (it) (format nil &amp;quot;~R&amp;quot; it)) (map &amp;#39;list #&amp;#39;digit-char-p (prin1-to-string 458))) &amp;#39;(&amp;quot;-hundred&amp;quot; &amp;quot;-ten&amp;quot; &amp;quot;&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;(&amp;quot;four-hundred&amp;quot; &amp;quot;five-ten&amp;quot; &amp;quot;eight&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nearly there! Or so I thought. How does this suffixing work when there isn’t a hundred digit, e.g. &lt;code&gt;21&lt;/code&gt;?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(print (mapcar (lambda(j k) (concatenate &amp;#39;string j k)) (mapcar (lambda (it) (format nil &amp;quot;~R&amp;quot; it)) (map &amp;#39;list #&amp;#39;digit-char-p (prin1-to-string 21))) &amp;#39;(&amp;quot;-hundred&amp;quot; &amp;quot;-ten&amp;quot; &amp;quot;&amp;quot;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;(&amp;quot;two-hundred&amp;quot; &amp;quot;one-ten&amp;quot;) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, that’s not right. But lisp seems okay with having the unequal sized lists. How about starting from the ones digit (i.e. reversed)? That means reversing the split digits list and reversing the suffixes list, doing the operations, then reversing the result&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(print (reverse (mapcar (lambda(j k) (concatenate &amp;#39;string j k)) (mapcar (lambda (it) (format nil &amp;quot;~R&amp;quot; it)) (reverse (map &amp;#39;list #&amp;#39;digit-char-p (prin1-to-string 21)))) (reverse &amp;#39;(&amp;quot;-hundred&amp;quot; &amp;quot;-ten&amp;quot; &amp;quot;&amp;quot;)))))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;(&amp;quot;two-ten&amp;quot; &amp;quot;one&amp;quot;) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fantastic! And the larger digits?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(print (reverse (mapcar (lambda(j k) (concatenate &amp;#39;string j k)) (mapcar (lambda (it) (format nil &amp;quot;~R&amp;quot; it)) (reverse (map &amp;#39;list #&amp;#39;digit-char-p (prin1-to-string 458)))) (reverse &amp;#39;(&amp;quot;-hundred&amp;quot; &amp;quot;-ten&amp;quot; &amp;quot;&amp;quot;)))))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;(&amp;quot;four-hundred&amp;quot; &amp;quot;five-ten&amp;quot; &amp;quot;eight&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Woohoo!&lt;/p&gt;
&lt;p&gt;The last step is to manually reverse the suffix list, make it a function, and try out the test cases, which you can &lt;a href=&#34;https://ato.pxeger.com/run?1=hVBNToQwFI5bzuDipS4oiyaDGWSSiXMIb9CBAh2hJe1jxpUXcYOJXsU76GlsB4cBNjZpmrzv9_Xtw-6zun8PPjss2Ob7i-ai6BQUVEVAjTgKYwXQhrcZN0Br3uxzTg_w7NBMq4yjUO5CaNFIVYJHoiUfqEQ3LLRpOIKSNZDXJwJuuMiAsJYW4S7MZSmRZRU3rAXaOuuYoWZ_ISpyB0JKCBDmCvin6lRuRE48FMCwzc_N7VmLLhuSB6fZbuFxB4U8Cq8DK1-CKyOOR4YHtRITML0fQesaq7MeT3pCWaeba4TuzKXTRCBkWeHUNVkvbC-asaN3milW_ygm5GSVzpeeNRo-qe-H9xc&#34;&gt;try out for yourself here&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(defun f(n) (reverse (mapcar (lambda(j k) (concatenate &amp;#39;string j k)) (mapcar (lambda (it) (format nil &amp;quot;~R&amp;quot; it)) (reverse (map &amp;#39;list #&amp;#39;digit-char-p (prin1-to-string n)))) &amp;#39;(&amp;quot;&amp;quot; &amp;quot;-ten&amp;quot; &amp;quot;-hundred&amp;quot;))))

(print (f 56))
(print (f 11))
(print (f 72))
(print (f 478))
(print (f 754))
(print (f 750))
(print (f 507))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;(&amp;quot;five-ten&amp;quot; &amp;quot;six&amp;quot;) 
(&amp;quot;one-ten&amp;quot; &amp;quot;one&amp;quot;) 
(&amp;quot;seven-ten&amp;quot; &amp;quot;two&amp;quot;) 
(&amp;quot;four-hundred&amp;quot; &amp;quot;seven-ten&amp;quot; &amp;quot;eight&amp;quot;) 
(&amp;quot;seven-hundred&amp;quot; &amp;quot;five-ten&amp;quot; &amp;quot;four&amp;quot;) 
(&amp;quot;seven-hundred&amp;quot; &amp;quot;five-ten&amp;quot; &amp;quot;zero&amp;quot;) 
(&amp;quot;five-hundred&amp;quot; &amp;quot;zero-ten&amp;quot; &amp;quot;seven&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s soemwhat close to what the challenge wants, and the ‘Attempt This Online’ tool linked about claims 198 bytes for this solution, but it’s not &lt;em&gt;quite&lt;/em&gt; there yet:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;these should be a single string per test, which I presume involves collapsing the list into a &lt;code&gt;&#39;string&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;I still have the &lt;code&gt;&#34;zero-ten&#34;&lt;/code&gt; and &lt;code&gt;&#34;zero&#34;&lt;/code&gt; entries which break the tests&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&#34;one&#34;&lt;/code&gt; should only appear in the ones entry, so &lt;code&gt;11&lt;/code&gt; should produce &lt;code&gt;&#34;ten one&#34;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this point, it was 1am, and I figured I’d learned enough for the day. If anyone would like to improve on this solution, please be my guest.&lt;/p&gt;
&lt;p&gt;What’s also great to see is that there’s &lt;a href=&#34;https://codegolf.stackexchange.com/a/245816/26763&#34;&gt;a Julia solution now&lt;/a&gt;!&lt;/p&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;!n=n&amp;lt;10 ? split(&amp;quot; one two three four five six seven eight nine&amp;quot;,&amp;quot; &amp;quot;)[n+1] :
n&amp;lt;20 ? &amp;quot;ten &amp;quot;*!(n-10) :
n&amp;lt;(H=100) ? !(n÷10)*&amp;quot;-&amp;quot;*!(10+n%10) :
n&amp;lt;2H ? &amp;quot;hundred &amp;quot;*!(n-H) :
!(n÷H)*&amp;quot;-&amp;quot;*!(H+n%H)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ! (generic function with 1 method)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;julia&#34;&gt;&lt;code&gt;tests = [1; 11; 56; 72; 478; 754; 750; 507];
for t in tests
    println(t =&amp;gt; !t)
end&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 1 =&amp;gt; &amp;quot;one&amp;quot;
## 11 =&amp;gt; &amp;quot;ten one&amp;quot;
## 56 =&amp;gt; &amp;quot;five-ten six&amp;quot;
## 72 =&amp;gt; &amp;quot;seven-ten two&amp;quot;
## 478 =&amp;gt; &amp;quot;four-hundred seven-ten eight&amp;quot;
## 754 =&amp;gt; &amp;quot;seven-hundred five-ten four&amp;quot;
## 750 =&amp;gt; &amp;quot;seven-hundred five-ten &amp;quot;
## 507 =&amp;gt; &amp;quot;five-hundred seven&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ll be trying to make sense of this for sure. You can &lt;a href=&#34;https://ato.pxeger.com/run?1=NZAxboNAEEV7TvFZKRLYRtpFdrBsE7dbp7VcRGIwG6HBgsHOXdK48Rmi1DlFbpOFmC1mR3_--9LM5_29r93b7XbvpUzWv98h57wzGnt059pJpNAwQa4NpGqJUDZ9i9JdCJ37QEcXYpA7VQJ2TGqhoOIDz80Rm4B36RCkxHvULIw4MToe9cjmRvt-D6_-fHl5ppLBYvScnyZXage66rloqXgk2GE0QnZirEds_FjgVaiTDjkOZmPSLVbPW2T-X2Zr36yWQ9Fe1tkxKJsWAscYmQD-nVvHUnMkyF8QShwQF__J04n-AA&#34;&gt;try it out yourself here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As usual, the journey was the important part of this - I got to play with and learn some more lisp. There’s no prize for the challenge aside from arbitrary internet points, so I’m entirely happy with how this turned out.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 21.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2022-04-02                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date       lib source        
##  assertthat    0.2.1   2019-03-21 [3] CRAN (R 4.0.1)
##  blogdown      1.8     2022-02-16 [1] CRAN (R 4.1.2)
##  bookdown      0.24    2021-09-02 [1] CRAN (R 4.1.2)
##  brio          1.1.1   2021-01-20 [3] CRAN (R 4.0.3)
##  bslib         0.3.1   2021-10-06 [1] CRAN (R 4.1.2)
##  cachem        1.0.3   2021-02-04 [3] CRAN (R 4.0.3)
##  callr         3.7.0   2021-04-20 [1] CRAN (R 4.1.2)
##  cli           3.2.0   2022-02-14 [1] CRAN (R 4.1.2)
##  crayon        1.5.0   2022-02-14 [1] CRAN (R 4.1.2)
##  DBI           1.1.1   2021-01-15 [3] CRAN (R 4.0.3)
##  desc          1.4.1   2022-03-06 [1] CRAN (R 4.1.2)
##  devtools      2.4.3   2021-11-30 [1] CRAN (R 4.1.2)
##  digest        0.6.27  2020-10-24 [3] CRAN (R 4.0.3)
##  dplyr       * 1.0.8   2022-02-08 [1] CRAN (R 4.1.2)
##  ellipsis      0.3.2   2021-04-29 [1] CRAN (R 4.1.2)
##  evaluate      0.14    2019-05-28 [3] CRAN (R 4.0.1)
##  fansi         0.4.2   2021-01-15 [3] CRAN (R 4.0.3)
##  fastmap       1.1.0   2021-01-25 [3] CRAN (R 4.0.3)
##  fs            1.5.0   2020-07-31 [3] CRAN (R 4.0.2)
##  generics      0.1.0   2020-10-31 [3] CRAN (R 4.0.3)
##  glue          1.6.1   2022-01-22 [1] CRAN (R 4.1.2)
##  htmltools     0.5.2   2021-08-25 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [1] CRAN (R 4.1.2)
##  jsonlite      1.7.2   2020-12-09 [3] CRAN (R 4.0.3)
##  JuliaCall     0.17.4  2021-05-16 [1] CRAN (R 4.1.2)
##  knitr         1.37    2021-12-16 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.1   2021-09-24 [1] CRAN (R 4.1.2)
##  magrittr      2.0.1   2020-11-17 [3] CRAN (R 4.0.3)
##  memoise       2.0.0   2021-01-26 [3] CRAN (R 4.0.3)
##  pillar        1.7.0   2022-02-01 [1] CRAN (R 4.1.2)
##  pkgbuild      1.2.0   2020-12-15 [3] CRAN (R 4.0.3)
##  pkgconfig     2.0.3   2019-09-22 [3] CRAN (R 4.0.1)
##  pkgload       1.2.4   2021-11-30 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.5.2   2021-04-30 [1] CRAN (R 4.1.2)
##  ps            1.5.0   2020-12-05 [3] CRAN (R 4.0.3)
##  purrr         0.3.4   2020-04-17 [3] CRAN (R 4.0.1)
##  R6            2.5.0   2020-10-28 [3] CRAN (R 4.0.2)
##  Rcpp          1.0.6   2021-01-15 [3] CRAN (R 4.0.3)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.0.1   2022-02-03 [1] CRAN (R 4.1.2)
##  rmarkdown     2.13    2022-03-10 [1] CRAN (R 4.1.2)
##  rprojroot     2.0.2   2020-11-15 [3] CRAN (R 4.0.3)
##  rstudioapi    0.13    2020-11-12 [3] CRAN (R 4.0.3)
##  sass          0.4.0   2021-05-12 [1] CRAN (R 4.1.2)
##  sessioninfo   1.1.1   2018-11-05 [3] CRAN (R 4.0.1)
##  stringi       1.5.3   2020-09-09 [3] CRAN (R 4.0.2)
##  stringr       1.4.0   2019-02-10 [3] CRAN (R 4.0.1)
##  testthat      3.1.2   2022-01-20 [1] CRAN (R 4.1.2)
##  tibble        3.1.6   2021-11-07 [1] CRAN (R 4.1.2)
##  tidyselect    1.1.2   2022-02-21 [1] CRAN (R 4.1.2)
##  usethis       2.1.5   2021-12-09 [1] CRAN (R 4.1.2)
##  utf8          1.1.4   2018-05-24 [3] CRAN (R 4.0.2)
##  vctrs         0.3.8   2021-04-29 [1] CRAN (R 4.1.2)
##  withr         2.5.0   2022-03-03 [1] CRAN (R 4.1.2)
##  xfun          0.30    2022-03-02 [1] CRAN (R 4.1.2)
##  yaml          2.2.1   2020-02-01 [3] CRAN (R 4.0.1)
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Codegolfing Minecraft Lighting</title>
      <link>https://jcarroll.com.au/2022/03/26/codegolfing-minecraft-lighting/</link>
      <pubDate>Sat, 26 Mar 2022 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2022/03/26/codegolfing-minecraft-lighting/</guid>
      <description>&lt;p&gt;I occasionally like to participate in an odd sport known as ‘code golf’ where the aim is to write some code to achieve a given task using the smallest number of characters.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;2022/03/26/codegolfing-minecraft-lighting/images/cheatatgolf.jpg&#34; alt=&#34;&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;The tradtional way to cheat at golf is to lower your score&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;R isn’t optimised for this in the slightest (why would it be?) and there are other languages which have expanded character sets which are, e.g. &lt;a href=&#34;https://mlochbaum.github.io/BQN/&#34;&gt;BQL&lt;/a&gt;, &lt;a href=&#34;https://github.com/lmendo/MATL&#34;&gt;MATL&lt;/a&gt;, and &lt;a href=&#34;https://github.com/Adriandmen/05AB1E&#34;&gt;05AB1E&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These are typically short, contained problems which can be solved in a variety of ways, so they usually include some restrictions and test cases. Some are more amenable to using R, while others have better support in other languages.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://codegolf.stackexchange.com/questions/245451/recreate-minecrafts-lighting&#34;&gt;This one&lt;/a&gt; caught my eye, partly because my kids are obsessed with Minecraft. The problem as stated:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Minecraft has a fairly unique lighting system. Each block’s light value is either one less than the brightest one surrounding it, or it is a light source itself. Your task is to write a method that takes in a 2D array of light source values, and then returns a 2D array with spread out lighting, where 0 is the minimum value.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;Input1 = [
         [0, 0, 4, 0], 
         [0, 0, 0, 0], 
         [0, 2, 0, 0], 
         [0, 0, 0, 0]
        ]

Output1 = [
         [2, 3, 4, 3], 
         [1, 2, 3, 2], 
         [1, 2, 2, 1], 
         [0, 1, 1, 0]
        ]

Input2 = [
         [2, 0, 0, 3], 
         [0, 0, 0, 0], 
         [0, 0, 0, 0], 
         [0, 0, 0, 0]
        ]

Output2 = [
         [2, 1, 2, 3], 
         [1, 0, 1, 2], 
         [0, 0, 0, 1], 
         [0, 0, 0, 0]
        ]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Matrix operations? That sounds like something R can work with. I decided to have a go. There were already some answers using the golfing languages, and I can’t even read those, so those aren’t any help. There was at least one python answer, but I didn’t want to confuse myself trying to translate an existing answer when the tooling doesn’t quite work that way.&lt;/p&gt;
&lt;p&gt;Defining the input matrices is straightforward enough&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mtest1 &amp;lt;- matrix(c(0, 0, 4, 0,
                   0, 0, 0, 0,
                   0, 2, 0, 0,
                   0, 0, 0, 0), 4, 4, byrow = TRUE)
mtest1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3] [,4]
## [1,]    0    0    4    0
## [2,]    0    0    0    0
## [3,]    0    2    0    0
## [4,]    0    0    0    0&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mtest2 &amp;lt;- matrix(c(2, 0, 0, 3,
                   0, 0, 0, 0,
                   0, 0, 0, 0,
                   0, 0, 0, 0), 4, 4, byrow = TRUE)
mtest2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3] [,4]
## [1,]    2    0    0    3
## [2,]    0    0    0    0
## [3,]    0    0    0    0
## [4,]    0    0    0    0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but do remember to set &lt;code&gt;byrow = TRUE&lt;/code&gt; if you’re writing your matrix out … by rows.&lt;/p&gt;
&lt;p&gt;I needed a way to identify the locations and values of these light sources. I know that &lt;code&gt;which()&lt;/code&gt; can return array indices with &lt;code&gt;arr.ind = TRUE&lt;/code&gt; so I tried that&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;which(mtest1 &amp;gt; 0, arr.ind = TRUE)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      row col
## [1,]   3   2
## [2,]   1   3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ll also need the values at those sources&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mtest1[mtest1 &amp;gt; 0]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So far, so good. Now, I’ll need to spread ‘light’ out from each of those sources. That seems… trickier.&lt;/p&gt;
&lt;p&gt;A few options came to mind, including a convolution operation, but I couldn’t get that to work. I eventually ended up writing a loop to set decreasing values along the row and column of each light source, forwards and backwards.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;for (r in seq_along(y)) {
    q &amp;lt;- p &amp;lt;- y[[r]]
    q &amp;lt;- rbind(q, data.frame(l=p$l-seq_along(p$c:n)+1, r=p$r, c=p$c:n))
    q &amp;lt;- rbind(q, data.frame(l=p$l-seq_along(p$c:1)+1, r=p$r, c=p$c:1))
    q &amp;lt;- rbind(q, data.frame(l=p$l-seq_along(p$r:n)+1, r=p$r:n, c=p$c))
    q &amp;lt;- rbind(q, data.frame(l=p$l-seq_along(p$r:1)+1, r=p$r:1, c=p$c))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This involved creating a &lt;code&gt;data.frame&lt;/code&gt; of row and column values, plus the value of the light at that position. This isn’t efficient at all, and not just from the processing side - it uses a lot of characters.&lt;/p&gt;
&lt;p&gt;One way to get around this in codegolf is to use a short alias to a longer named function, e.g. &lt;code&gt;d = data.frame&lt;/code&gt;, &lt;code&gt;b = rbind&lt;/code&gt;. This saves a lot of characters.&lt;/p&gt;
&lt;p&gt;The idea of creating indices at which to set values comes from the fact that a matrix can be subset by another matrix that specifies the rows and columns. i.e.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## create a matrix
m = matrix(1:9, 3, 3, byrow = TRUE)
m&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
## [3,]    7    8    9&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## specify the extraction of the elements as (1, 2) and (3, 2)
msub = matrix(c(1, 2, 3, 2), 2, 2, byrow = TRUE)
msub&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2]
## [1,]    1    2
## [2,]    3    2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m[msub]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can essentially ‘un-&lt;code&gt;which()&lt;/code&gt;’ a matrix.&lt;/p&gt;
&lt;p&gt;Once I had the reduced values in each direction away from a light source, for each light source, the last step was to combine these and take the maximum value at each element. &lt;code&gt;Reduce()&lt;/code&gt; does this nicely with the function &lt;code&gt;pmax()&lt;/code&gt; (parallel maximum which works across multiple vectors rather than the global maximum).&lt;/p&gt;
&lt;p&gt;Lastly, a second pass using all these new points as light sources ensures that the ‘light’ is propagated in all directions.&lt;/p&gt;
&lt;p&gt;The solution, as I had it, worked and produced the test case results, but it was not yet golfed.&lt;/p&gt;
&lt;p&gt;To “golf” some R code there’s some optimisations we can make.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Delete spaces where possible&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;=&lt;/code&gt; over &lt;code&gt;&amp;lt;-&lt;/code&gt; to save a character each time&lt;/li&gt;
&lt;li&gt;For R&amp;gt;=4.1, use the shorthand syntax for &lt;code&gt;function()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f=\(x)x^2
f(3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 9&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;use &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;F&lt;/code&gt; for &lt;code&gt;TRUE&lt;/code&gt; and &lt;code&gt;FALSE&lt;/code&gt; - generally inadvisable in regular code, but here they save some characters.&lt;/li&gt;
&lt;li&gt;use partial argument matching where possible - it’s a dangerous feature of the language, but you only “need” to use as many letters of a function argument so that it’s uniquely specified, so&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;which(mtest1&amp;gt;0, arr.ind = TRUE)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      row col
## [1,]   3   2
## [2,]   1   3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;can be shortened to&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;which(mtest1&amp;gt;0,a=T)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      row col
## [1,]   3   2
## [2,]   1   3&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Create aliases to functions - just remember to alias the &lt;em&gt;name&lt;/em&gt; of the function, not the call (with parentheses)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;d=determinant.matrix
identical(
  d(mtest1),
  determinant.matrix(mtest1)
)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Use the prefix notation version of functions which require many characters, e.g. &lt;code&gt;if&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;if (3 &amp;gt; 2) {
  &amp;quot;res1&amp;quot;
} else {
  &amp;quot;res2&amp;quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;vs&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;`if`(3&amp;gt;2,&amp;quot;res1&amp;quot;,&amp;quot;res2&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;keeping in mind that &lt;code&gt;ifelse()&lt;/code&gt; requires the same structure in both returned results (and it evaluates both), which tripped me up&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ifelse(TRUE, 1:4, 2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With all those in place, I landed at 377 characters for my solution. Certainly not great, considering the python answer was ~200.&lt;/p&gt;
&lt;p&gt;I really wanted a better way to “spread” the light out from a single point, but I wasn’t finding any nice solutions to that simpler sub-problem. A great way to get a solution is to ask other people, so I wrote a short post on &lt;a href=&#34;https://jcarroll.xyz/2022/03/25/r-challenge-contour.html&#34;&gt;my new mini blog&lt;/a&gt; asking the simpler question of how to achieve this. That cross-posts to Twitter, where &lt;a href=&#34;https://twitter.com/yjunechoe/status/1507344665514848258?s=20&amp;amp;t=27rn8zNl-36D-3ppsslAjw&#34;&gt;June Choe&lt;/a&gt; provided a great &lt;code&gt;outer()&lt;/code&gt; solution. I’d tried something like that but not so cleverly.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;vx &amp;lt;- 4
vy &amp;lt;- 3
vv &amp;lt;- 5
n &amp;lt;- 8
outer(1:n, 1:n, function(x, y) pmax(vv - abs(x - vx) - abs(y - vy), 0))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
## [1,]    0    1    2    1    0    0    0    0
## [2,]    1    2    3    2    1    0    0    0
## [3,]    2    3    4    3    2    1    0    0
## [4,]    3    4    5    4    3    2    1    0
## [5,]    2    3    4    3    2    1    0    0
## [6,]    1    2    3    2    1    0    0    0
## [7,]    0    1    2    1    0    0    0    0
## [8,]    0    0    1    0    0    0    0    0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This greatly improves R’s chances at solving this efficiently because now we can condense all the ‘spread light’ stuff into this one function, and because it’s not iterative, we can &lt;code&gt;lapply()&lt;/code&gt; over the results.&lt;/p&gt;
&lt;p&gt;The “final” version, after some more clean up, is &lt;a href=&#34;https://codegolf.stackexchange.com/a/245581/26763&#34;&gt;an okay 182 characters&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ls=\(m,w=T) {
  n=ncol(m)
  p=m&amp;gt;1
  i=which(p,a=T)
  y=lapply(1:nrow(i),\(j)outer(1:n,1:n,\(x,y)pmax(m[p][j]-abs(x-i[j,1])-abs(y-i[j,2]),0)))
  z=Reduce(pmax,y)
  `if`(w,ls(z,F),z)
}

ls(mtest1)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3] [,4]
## [1,]    2    3    4    3
## [2,]    1    2    3    2
## [3,]    1    2    2    1
## [4,]    0    1    1    0&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ls(mtest2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##      [,1] [,2] [,3] [,4]
## [1,]    2    1    2    3
## [2,]    1    0    1    2
## [3,]    0    0    0    1
## [4,]    0    0    0    0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m still of course interested if there are more optimisations to be made, so do let me know if you can spot any!&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 4.1.2 (2021-11-01)
##  os       Pop!_OS 21.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2022-03-26                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date       lib source        
##  assertthat    0.2.1   2019-03-21 [3] CRAN (R 4.0.1)
##  blogdown      1.8     2022-02-16 [1] CRAN (R 4.1.2)
##  bookdown      0.24    2021-09-02 [1] CRAN (R 4.1.2)
##  brio          1.1.1   2021-01-20 [3] CRAN (R 4.0.3)
##  bslib         0.3.1   2021-10-06 [1] CRAN (R 4.1.2)
##  cachem        1.0.3   2021-02-04 [3] CRAN (R 4.0.3)
##  callr         3.7.0   2021-04-20 [1] CRAN (R 4.1.2)
##  cli           3.2.0   2022-02-14 [1] CRAN (R 4.1.2)
##  crayon        1.5.0   2022-02-14 [1] CRAN (R 4.1.2)
##  DBI           1.1.1   2021-01-15 [3] CRAN (R 4.0.3)
##  desc          1.4.1   2022-03-06 [1] CRAN (R 4.1.2)
##  devtools      2.4.3   2021-11-30 [1] CRAN (R 4.1.2)
##  digest        0.6.27  2020-10-24 [3] CRAN (R 4.0.3)
##  dplyr       * 1.0.8   2022-02-08 [1] CRAN (R 4.1.2)
##  ellipsis      0.3.2   2021-04-29 [1] CRAN (R 4.1.2)
##  evaluate      0.14    2019-05-28 [3] CRAN (R 4.0.1)
##  fansi         0.4.2   2021-01-15 [3] CRAN (R 4.0.3)
##  fastmap       1.1.0   2021-01-25 [3] CRAN (R 4.0.3)
##  forcats     * 0.5.1   2021-01-27 [3] CRAN (R 4.0.3)
##  fs            1.5.0   2020-07-31 [3] CRAN (R 4.0.2)
##  generics      0.1.0   2020-10-31 [3] CRAN (R 4.0.3)
##  glue          1.6.1   2022-01-22 [1] CRAN (R 4.1.2)
##  htmltools     0.5.2   2021-08-25 [1] CRAN (R 4.1.2)
##  jquerylib     0.1.4   2021-04-26 [1] CRAN (R 4.1.2)
##  jsonlite      1.7.2   2020-12-09 [3] CRAN (R 4.0.3)
##  knitr         1.37    2021-12-16 [1] CRAN (R 4.1.2)
##  lifecycle     1.0.1   2021-09-24 [1] CRAN (R 4.1.2)
##  magrittr      2.0.1   2020-11-17 [3] CRAN (R 4.0.3)
##  memoise       2.0.0   2021-01-26 [3] CRAN (R 4.0.3)
##  pillar        1.7.0   2022-02-01 [1] CRAN (R 4.1.2)
##  pkgbuild      1.2.0   2020-12-15 [3] CRAN (R 4.0.3)
##  pkgconfig     2.0.3   2019-09-22 [3] CRAN (R 4.0.1)
##  pkgload       1.2.4   2021-11-30 [1] CRAN (R 4.1.2)
##  prettyunits   1.1.1   2020-01-24 [3] CRAN (R 4.0.1)
##  processx      3.5.2   2021-04-30 [1] CRAN (R 4.1.2)
##  ps            1.5.0   2020-12-05 [3] CRAN (R 4.0.3)
##  purrr         0.3.4   2020-04-17 [3] CRAN (R 4.0.1)
##  R6            2.5.0   2020-10-28 [3] CRAN (R 4.0.2)
##  remotes       2.4.2   2021-11-30 [1] CRAN (R 4.1.2)
##  rlang         1.0.1   2022-02-03 [1] CRAN (R 4.1.2)
##  rmarkdown     2.13    2022-03-10 [1] CRAN (R 4.1.2)
##  rprojroot     2.0.2   2020-11-15 [3] CRAN (R 4.0.3)
##  rstudioapi    0.13    2020-11-12 [3] CRAN (R 4.0.3)
##  sass          0.4.0   2021-05-12 [1] CRAN (R 4.1.2)
##  sessioninfo   1.1.1   2018-11-05 [3] CRAN (R 4.0.1)
##  stringi       1.5.3   2020-09-09 [3] CRAN (R 4.0.2)
##  stringr       1.4.0   2019-02-10 [3] CRAN (R 4.0.1)
##  testthat      3.1.2   2022-01-20 [1] CRAN (R 4.1.2)
##  tibble        3.1.6   2021-11-07 [1] CRAN (R 4.1.2)
##  tidyselect    1.1.2   2022-02-21 [1] CRAN (R 4.1.2)
##  usethis       2.1.5   2021-12-09 [1] CRAN (R 4.1.2)
##  utf8          1.1.4   2018-05-24 [3] CRAN (R 4.0.2)
##  vctrs         0.3.8   2021-04-29 [1] CRAN (R 4.1.2)
##  withr         2.5.0   2022-03-03 [1] CRAN (R 4.1.2)
##  xfun          0.30    2022-03-02 [1] CRAN (R 4.1.2)
##  yaml          2.2.1   2020-02-01 [3] CRAN (R 4.0.1)
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.1
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Adventures in x86 ASM with rx86</title>
      <link>https://jcarroll.com.au/2021/12/23/adventures-in-x86-asm/</link>
      <pubDate>Thu, 23 Dec 2021 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2021/12/23/adventures-in-x86-asm/</guid>
      <description>&lt;p&gt;I just finished &lt;a href=&#34;https://en.wikipedia.org/wiki/Code:_The_Hidden_Language_of_Computer_Hardware_and_Software&#34;&gt;‘Code: The Hidden Language of Computer Hardware and Software’&lt;/a&gt; by Charles Petzold which was a really well-written (in my opinion) guided journey from flashing a light in morse code through to building a whole computer, and everything needed along the way.&lt;/p&gt;
&lt;p&gt;The section on encoding instructions for the processor (built up from logic gates) - assembly instructions as a human readable version of the machine code - was particularly interesting to me, and as I was describing this to a colleague I
remembered that it’s not the first time I’ve played with assembly…&lt;/p&gt;
&lt;p&gt;Years and years ago (I don’t recall how it actually started) I spent some time trying to solve a puzzle. I don’t recall whether I saw the puzzle or a solution first, but I do remember wanting to be able to understand it properly, and ideally be able to use some software &lt;em&gt;I wrote&lt;/em&gt; to reach the solution.&lt;/p&gt;
&lt;p&gt;The puzzle was just a set of characters on a poster for the (then named) Australian Defence Signals Directorate (now the &lt;a href=&#34;https://www.asd.gov.au/&#34;&gt;Australian Signals Directorate&lt;/a&gt; - one of our Secret Squirrel orgs) at &lt;a href=&#34;https://ruxcon.org.au/&#34;&gt;ruxcon&lt;/a&gt; in 2011&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;images/dsd_poster.JPG&#34; alt=&#34;&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;ruxcon2011 DSD poster&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Yes, that was a long time ago, but I never wrote up what I did, and now seems like a good enough time to get really distracted.&lt;/p&gt;
&lt;p&gt;I would be surprised if I understood it well enough at the time, so I suspect I was aware of &lt;a href=&#34;http://0xdec0.blogspot.com/2011/12/ruxcon-dsd-challenge.html&#34;&gt;this blogpost&lt;/a&gt; which walks through the solution (spoilers). Nonetheless, I wanted to be able to do that myself, not just follow some instructions - I was confident that I could write enough code (of some sort) to go from this sequence of letters and symbols to the final solution.&lt;/p&gt;
&lt;p&gt;My attempts at the time were mostly command-line attempts; the blog post linked above uses only web services, so that felt like I could make it ‘my own’. I first needed to get the characters into my computer - that’s just writing them out to a text file, say, a file called &lt;code&gt;dsd&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;# dsd:
6AAAAABbi8uDwx4zwDPSigOK
ETLCiAM8AHQrg8EBg8MB6+wz
/7/z+TEct0SlpGf5dRyl53US
YQEE56Ri7Kdkj8IAABkcOsw=&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Knowing that this is base-64 encoded, I can decode it with &lt;code&gt;hexdump&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;cat dsd | base64 -d | hexdump -C

00000000  e8 00 00 00 00 5b 8b cb  83 c3 1e 33 c0 33 d2 8a  |.....[.....3.3..|
00000010  03 8a 11 32 c2 88 03 3c  00 74 2b 83 c1 01 83 c3  |...2...&amp;lt;.t+.....|
00000020  01 eb ec 33 ff bf f3 f9  31 1c b7 44 a5 a4 67 f9  |...3....1..D..g.|
00000030  75 1c a5 e7 75 12 61 01  04 e7 a4 62 ec a7 64 8f  |u...u.a....b..d.|
00000040  c2 00 00 19 1c 3a cc                              |.....:.|
00000047&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To just get the bytecode, I used some different options and saved the file as &lt;code&gt;dsd.hex&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;cat dsd | base64 -d | hexdump  -v -e &amp;#39;/1 %02X &amp;#39; &amp;gt; dsd.hex

# dsd.hex:
E8 00 00 00 00 5B 8B CB 83 C3 1E 33 C0 33 D2 8A 03 8A 11 32 C2 88 03 3C 00 74 2B 83 C1 01 83 C3 01 EB EC 33 FF BF F3 F9 31 1C B7 44 A5 A4 67 F9 75 1C A5 E7 75 12 61 01 04 E7 A4 62 EC A7 64 8F C2 00 00 19 1C 3A CC &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I did go a similar route to the linked blogpost and converted these bytes to shellcode, wrapped them in a C program and disassembled it with &lt;code&gt;gdb&lt;/code&gt;, but much simpler was to use a better tool, in this case &lt;a href=&#34;http://udis86.sourceforge.net/&#34;&gt;udis&lt;/a&gt; which I needed to install separately. This
gives the same result as the blogpost, which was nice&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;udcli -x dsd.hex &amp;gt; dsd.hex.asm

# dsd.hex.asm:
0000000000000000 e800000000       call 0x5                
0000000000000005 5b               pop ebx                 
0000000000000006 8bcb             mov ecx, ebx            
0000000000000008 83c31e           add ebx, 0x1e           
000000000000000b 33c0             xor eax, eax            
000000000000000d 33d2             xor edx, edx            
000000000000000f 8a03             mov al, [ebx]           
0000000000000011 8a11             mov dl, [ecx]           
0000000000000013 32c2             xor al, dl              
0000000000000015 8803             mov [ebx], al           
0000000000000017 3c00             cmp al, 0x0             
0000000000000019 742b             jz 0x46                 
000000000000001b 83c101           add ecx, 0x1            
000000000000001e 83c301           add ebx, 0x1            
0000000000000021 ebec             jmp 0xf                 
0000000000000023 33ff             xor edi, edi            
0000000000000025 bff3f9311c       mov edi, 0x1c31f9f3     
000000000000002a b744             mov bh, 0x44            
000000000000002c a5               movsd                   
000000000000002d a4               movsb                   
000000000000002e 67f9             a16 stc                 
0000000000000030 751c             jnz 0x4e                
0000000000000032 a5               movsd                   
0000000000000033 e775             out 0x75, eax           
0000000000000035 126101           adc ah, [ecx+0x1]       
0000000000000038 04e7             add al, 0xe7            
000000000000003a a4               movsb                   
000000000000003b 62ec             invalid                 
000000000000003d a7               cmpsd                   
000000000000003e 648fc2           pop edx                 
0000000000000041 0000             add [eax], al           
0000000000000043 191c3a           sbb [edx+edi], ebx      
0000000000000046 cc               int3                    &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, I got a bit lost (at the time) because I didn’t understand assembly well enough (or at all), so, continuing with the logic presented in the linked blogpost, I considered just working with the bytes directly.&lt;/p&gt;
&lt;p&gt;All we really need to do it take the bytes starting at &lt;code&gt;0x5&lt;/code&gt; and &lt;code&gt;0x23&lt;/code&gt; and &lt;code&gt;xor&lt;/code&gt; them. I figured I’ll need the decimal value of these addresses; &lt;code&gt;0x5&lt;/code&gt; is just 5, but &lt;code&gt;0x23&lt;/code&gt; = 16*2 + 3 = 35. We can of course get this via &lt;code&gt;printf&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;printf &amp;quot;%d\n&amp;quot; 0x23 &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 35&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or less simply with the built-in calculator tool &lt;code&gt;bc&lt;/code&gt;, going from (input) base 16 to (output) base 10&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;echo &amp;quot;obase=10;ibase=16; 23&amp;quot; | bc&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 35&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I placed the bytes in sequence (removing spaces) with&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;str=$(cat dsd.hex | sed &amp;#39;s/ //g&amp;#39;)
echo $str&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## E8000000005B8BCB83C31E33C033D28A038A1132C288033C00742B83C10183C301EBEC33FFBFF3F9311CB744A5A467F9751CA5E77512610104E7A462ECA7648FC20000191C3ACC&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since I have 2 characters per hex, &lt;code&gt;0x5&lt;/code&gt; starts at character 10, and &lt;code&gt;0x23&lt;/code&gt; starts at character 70, so we define our strings as&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;astr=${str:70} # 0x23 to end
echo $astr&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 33FFBFF3F9311CB744A5A467F9751CA5E77512610104E7A462ECA7648FC20000191C3ACC&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;$ bstr=${str:10} # 0x5 to end
$ echo $bstr&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 5B8BCB83C31E33C033D28A038A1132C288033C00742B83C10183C301EBEC33FFBFF3F9311CB744A5A467F9751CA5E77512610104E7A462ECA7648FC20000191C3ACC&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is overlap here, which we will have to deal with when we get to it. For now, we want to &lt;code&gt;xor&lt;/code&gt; these. Let’s cut these down to 60 characters (where they start to overlap)&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;trimastr=${astr:0:60}
echo $trimastr&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 33FFBFF3F9311CB744A5A467F9751CA5E77512610104E7A462ECA7648FC2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;trimbstr=${bstr:0:60}
echo $trimbstr&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 5B8BCB83C31E33C033D28A038A1132C288033C00742B83C10183C301EBEC&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command &lt;code&gt;xor&lt;/code&gt; (&lt;code&gt;^&lt;/code&gt;) chokes on this many digits (in fact, any more than about 8) so I’ve written a script to &lt;code&gt;xor&lt;/code&gt; the characters one at a time:&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;for i in {0..59} ; do echo $(( 0x${astr:$i:1} ^ 0x${bstr:$i:1} )) | awk &amp;#39;{printf &amp;quot;%X&amp;quot;,$0}&amp;#39; ; done &amp;gt; xor.dat

# xor.dat:
687474703A2F2F7777772E6473642E676F762E61752F6465636F6465642E&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What about that bit that overlapped? we only xored the first 60 characters, but the length of the string is&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;echo ${#astr}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 72&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so we need those first 12 (72-12) characters (6 hex) of overlap&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;olap1=${astr:60:12}
echo $olap1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 0000191C3ACC&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The assembly code would have overwritten the overlapped part by the time it reached there, so we need to &lt;code&gt;xor&lt;/code&gt; with the &lt;code&gt;xor&lt;/code&gt;’d part, i.e. the first 12 characters of &lt;code&gt;xor.dat&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;olap2=$(cat xor.dat | cut -c -12)
echo $olap2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 687474703A2F&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, finally, do the last &lt;code&gt;xor&lt;/code&gt; (&lt;code&gt;^&lt;/code&gt;)&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;for i in {0..11} ; do echo $(( 0x${olap1:$i:1} ^ 0x${olap2:$i:1} )) | awk &amp;#39;{printf &amp;quot;%X&amp;quot;,$0}&amp;#39; ; done &amp;gt; xorolap.dat

# xorolap.dat:
68746D6C00E3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so this needs to go at the end of our xor.dat&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;cat xor.dat xorolap.dat &amp;gt; xorfinal.dat

# xorfinal.dat:
687474703A2F2F7777772E6473642E676F762E61752F6465636F6465642E68746D6C00E3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final &lt;code&gt;00&lt;/code&gt; and after is useless, so let’s drop it. Finally, we just need to convert this back to text using &lt;code&gt;xxd -r&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;cat xorfinal.dat | sed &amp;#39;s/[0]\{2\}.*//&amp;#39; | xxd -r -p &amp;gt; dsd.sol&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Phew. I’m not going to reveal the solution just yet, because this isn’t the end of the story (but I did get the right answer).&lt;/p&gt;
&lt;p&gt;So, that’s a commandline solution to (at least this part) of the puzzle. But now I know R!&lt;/p&gt;
&lt;p&gt;Learning more about assembly from the book ‘Code’, it occurred to me that the
operations - which could be implemented with something as simple as telegraph relays (or &lt;a href=&#34;https://hackaday.com/2012/09/28/making-logic-gates-out-of-crabs/&#34;&gt;crabs&lt;/a&gt;) - were just operations on data. Given an input, produce an output (sort of). A &lt;code&gt;MOV&lt;/code&gt; operation just moved some value stored at some address to another address (or to/from a register). This felt like it could be simple enough to encode in some R functions. Perhaps not some “pure” R functions, because I &lt;em&gt;want&lt;/em&gt; the side-effect of altering a global memory bank, but surely I could do simple things like &lt;code&gt;ADD&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I looked around to see if someone else had done this before. As is usually the case with odd requests, Mike (a.k.a. &lt;a href=&#34;https://github.com/coolbutuseless&#34;&gt;&lt;span class=&#34;citation&#34;&gt;@coolbutuseless&lt;/span&gt;&lt;/a&gt;) has done something similar in the form of &lt;a href=&#34;https://github.com/coolbutuseless/r64&#34;&gt;r64&lt;/a&gt; which I didn’t appreciate was a sufficiently distinct flavour of assembly (I never had a Commodore64, we had an &lt;a href=&#34;https://en.wikipedia.org/wiki/Amstrad_CPC#CPC664&#34;&gt;Amstrad CPC664&lt;/a&gt; on which I really only played games). After a quick &lt;a href=&#34;https://github.com/coolbutuseless/r64/pull/1&#34;&gt;PR&lt;/a&gt; to bring that repo up to date with other changes by the author (a migration of one dependency) I realised this wasn’t what I needed, but did learn a lot from how it was structured.&lt;/p&gt;
&lt;p&gt;Okay, on to building something myself. I knew I’d need some memory and some registers. The registers seemed easy - they wouldn’t hold a lot and I could address them by name, e.g. &lt;code&gt;eax&lt;/code&gt;. An environment seemed natural, both because of the named list structure, and because I knew it would be mutable. That seemed like a benefit for this use-case - having a global set of registers I could move data in and out of without making copies of the thing or passing it around everywhere.&lt;/p&gt;
&lt;p&gt;Next I’d need memory. I figured a vector of hex value made sense, but I wanted to be able to refer to the first one as &lt;code&gt;0x00&lt;/code&gt;. Now, the names of a vector need to be a character vector - you can’t use the actual hex values&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;memory &amp;lt;- c(0x00 = 0x19, 0x01 = 0x1a, 0x02 = 0x1b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error: &amp;lt;text&amp;gt;:1:18: unexpected &amp;#39;=&amp;#39;
## 1: memory &amp;lt;- c(0x00 =
##                      ^&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so we need to use character strings&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;memory &amp;lt;- c(&amp;quot;0x00&amp;quot; = 0x19, &amp;quot;0x01&amp;quot; = 0x1a, &amp;quot;0x02&amp;quot; = 0x1b)
memory&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 0x00 0x01 0x02 
##   25   26   27&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More importantly, we’ll need to ensure we &lt;em&gt;only&lt;/em&gt; refer to these by the character
strings because &lt;code&gt;[&lt;/code&gt; first tries a coercion to integer, which, side-note, is why this works&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;(1:10)[2.3] # since as.integer(2.3) == 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;(1:10)[4.7] # since as.integer(4.7) == 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The risk is that we use a hex value to extract an element, in which case we might accidentally try to get the first value with&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;memory[0x00]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## named numeric(0)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead, we want&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;memory[&amp;quot;0x00&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 0x00 
##   25&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to make sure we always do this, we need a &lt;code&gt;sanitize()&lt;/code&gt; function which
always returns the string.&lt;/p&gt;
&lt;p&gt;We can convert a value to hexmode with &lt;code&gt;as.hexmode&lt;/code&gt;, but that’s a lot of typing, so I added an alias as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;hex &amp;lt;- as.hexmode&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For processing assembly instructions, we might see something like&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;mov eax, 0x5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which should move the value &lt;code&gt;0x5&lt;/code&gt; into the register &lt;code&gt;eax&lt;/code&gt;… so we’ll need a way
to distinguish direct addresses from registers. Worse still, we might refer to the address stored in a register, as &lt;code&gt;[eax]&lt;/code&gt;. A &lt;code&gt;reg_or_val()&lt;/code&gt; function would identify anything which points to an address (containing a &lt;code&gt;[&lt;/code&gt;), any of the named registers, or a value, and would return the address (or where that points).&lt;/p&gt;
&lt;p&gt;With all of those pieces, the only thing left is to actually be able to run code.&lt;/p&gt;
&lt;p&gt;Assembly runs sequentially through the instructions, unless we encounter some flow
control opcodes (e.g. &lt;code&gt;JMP&lt;/code&gt; - jump to address - I’ll keep calling them opcodes but mnemonics is a more correct term). The basic process would then be to
read in the instruction, identify the opcode and the arguments, and execute, modifying the memory and registers in-place. Once that’s done, we move to the next instruction.&lt;/p&gt;
&lt;p&gt;With flow control we might need to identify a &lt;em&gt;different&lt;/em&gt; address to go to next, and that might depend on the status of the registers, for example &lt;code&gt;JNZ 0x00&lt;/code&gt; jumps to address &lt;code&gt;0x00&lt;/code&gt; if the zero flag is &lt;em&gt;not&lt;/em&gt; set. So, we can execute the current instruction but then apply any flag-based logic to see if we need to go to a new address, and go wherever we should go go next. This is implemented as &lt;code&gt;runasm()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;That takes care of running the code, but what are we running? Oh, operations. Right. Well, we need some of those. Going through the opcodes I need for the puzzle, I’ll need the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;call
pop
mov
add
xor
cmp
jz
jmp
halt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;CALL&lt;/code&gt; just pushes a value onto the stack (register &lt;code&gt;esp&lt;/code&gt;), &lt;code&gt;POP&lt;/code&gt; retrieves it and
stores it at an address, &lt;code&gt;MOV&lt;/code&gt; as we said moves a value from place to place, &lt;code&gt;ADD&lt;/code&gt;
adds two values, &lt;code&gt;XOR&lt;/code&gt; does what it suggests, and so on. These don’t seem tricky to implement, for example&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mov &amp;lt;- function(x, y) {
  # copy y into x
  res &amp;lt;- hex(reg_or_val(y))
  if (x %in% names(registers)) {
    assign(x, res, envir = registers)
  } else {
    mem[sanitize(x)] &amp;lt;&amp;lt;- sanitize(res)
  }
  return(invisible(NULL))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The wrinkle will be that particular instructions &lt;em&gt;also&lt;/em&gt; update registers, for
example an &lt;code&gt;ADD&lt;/code&gt; stores whether the result was &lt;code&gt;0x00&lt;/code&gt; in the zero-flag register&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;function(x, y) {
  # add y to x and save in x
  res &amp;lt;- hex(reg_or_val(x)) + hex(reg_or_val(y))
  if (x %in% names(registers)) {
    assign(x, res, envir = registers)
  } else {
    mem[sanitize(x)] &amp;lt;&amp;lt;- sanitize(res)
  }
  assign(&amp;quot;zf&amp;quot;, hex(as.integer(res == 0x00)), envir = registers)
  return(invisible(x))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;JMP&lt;/code&gt; (or other jump) will check this register and jump (or not) accordingly.&lt;/p&gt;
&lt;p&gt;With these pieces in place, an R package was a natural home for the code, so I can now present the &lt;code&gt;{rx86}&lt;/code&gt; package: &lt;a href=&#34;https://github.com/jonocarroll/rx86&#34; class=&#34;uri&#34;&gt;https://github.com/jonocarroll/rx86&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let’s use it to solve the puzzle!!!&lt;/p&gt;
&lt;p&gt;Starting with the puzzle string&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dsd &amp;lt;- &amp;quot;6AAAAABbi8uDwx4zwDPSigOK
ETLCiAM8AHQrg8EBg8MB6+wz
/7/z+TEct0SlpGf5dRyl53US
YQEE56Ri7Kdkj8IAABkcOsw=&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;we decode it (this time in R)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;(b64 &amp;lt;- base64enc::base64decode(dsd))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] e8 00 00 00 00 5b 8b cb 83 c3 1e 33 c0 33 d2 8a 03 8a 11 32 c2 88 03 3c 00
## [26] 74 2b 83 c1 01 83 c3 01 eb ec 33 ff bf f3 f9 31 1c b7 44 a5 a4 67 f9 75 1c
## [51] a5 e7 75 12 61 01 04 e7 a4 62 ec a7 64 8f c2 00 00 19 1c 3a cc&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will be the only non-R part: we still need to disassemble the bytecode into assembly, but we can do that &lt;em&gt;from&lt;/em&gt; R with a &lt;code&gt;system()&lt;/code&gt; call to &lt;code&gt;udcli&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;(disas &amp;lt;- system(&amp;quot;udcli -x&amp;quot;, input = paste(b64, collapse = &amp;quot; &amp;quot;), intern = TRUE))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] &amp;quot;0000000000000000 e800000000       call 0x5                &amp;quot;
##  [2] &amp;quot;0000000000000005 5b               pop ebx                 &amp;quot;
##  [3] &amp;quot;0000000000000006 8bcb             mov ecx, ebx            &amp;quot;
##  [4] &amp;quot;0000000000000008 83c31e           add ebx, 0x1e           &amp;quot;
##  [5] &amp;quot;000000000000000b 33c0             xor eax, eax            &amp;quot;
##  [6] &amp;quot;000000000000000d 33d2             xor edx, edx            &amp;quot;
##  [7] &amp;quot;000000000000000f 8a03             mov al, [ebx]           &amp;quot;
##  [8] &amp;quot;0000000000000011 8a11             mov dl, [ecx]           &amp;quot;
##  [9] &amp;quot;0000000000000013 32c2             xor al, dl              &amp;quot;
## [10] &amp;quot;0000000000000015 8803             mov [ebx], al           &amp;quot;
## [11] &amp;quot;0000000000000017 3c00             cmp al, 0x0             &amp;quot;
## [12] &amp;quot;0000000000000019 742b             jz 0x46                 &amp;quot;
## [13] &amp;quot;000000000000001b 83c101           add ecx, 0x1            &amp;quot;
## [14] &amp;quot;000000000000001e 83c301           add ebx, 0x1            &amp;quot;
## [15] &amp;quot;0000000000000021 ebec             jmp 0xf                 &amp;quot;
## [16] &amp;quot;0000000000000023 33ff             xor edi, edi            &amp;quot;
## [17] &amp;quot;0000000000000025 bff3f9311c       mov edi, 0x1c31f9f3     &amp;quot;
## [18] &amp;quot;000000000000002a b744             mov bh, 0x44            &amp;quot;
## [19] &amp;quot;000000000000002c a5               movsd                   &amp;quot;
## [20] &amp;quot;000000000000002d a4               movsb                   &amp;quot;
## [21] &amp;quot;000000000000002e 67f9             a16 stc                 &amp;quot;
## [22] &amp;quot;0000000000000030 751c             jnz 0x4e                &amp;quot;
## [23] &amp;quot;0000000000000032 a5               movsd                   &amp;quot;
## [24] &amp;quot;0000000000000033 e775             out 0x75, eax           &amp;quot;
## [25] &amp;quot;0000000000000035 126101           adc ah, [ecx+0x1]       &amp;quot;
## [26] &amp;quot;0000000000000038 04e7             add al, 0xe7            &amp;quot;
## [27] &amp;quot;000000000000003a a4               movsb                   &amp;quot;
## [28] &amp;quot;000000000000003b 62ec             invalid                 &amp;quot;
## [29] &amp;quot;000000000000003d a7               cmpsd                   &amp;quot;
## [30] &amp;quot;000000000000003e 648fc2           pop edx                 &amp;quot;
## [31] &amp;quot;0000000000000041 0000             add [eax], al           &amp;quot;
## [32] &amp;quot;0000000000000043 191c3a           sbb [edx+edi], ebx      &amp;quot;
## [33] &amp;quot;0000000000000046 cc               int3                    &amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We then read this back into R as a data.frame&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;asm &amp;lt;- suppressWarnings(
  readr::read_fwf(paste(disas, collapse = &amp;quot;\n&amp;quot;), 
                  col_types = &amp;quot;ccc&amp;quot;,
                  col_positions = readr::fwf_widths(c(16, 16, 21)))
)
colnames(asm) &amp;lt;- c(&amp;quot;addr&amp;quot;, &amp;quot;bytecode&amp;quot;, &amp;quot;instr&amp;quot;)
# trim the leading 0s from addr since this is all we&amp;#39;re using
asm$addr &amp;lt;- substr(asm$addr, nchar(asm$addr)-1, nchar(asm$addr))
asm&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 33 x 3
##    addr  bytecode   instr        
##    &amp;lt;chr&amp;gt; &amp;lt;chr&amp;gt;      &amp;lt;chr&amp;gt;        
##  1 00    e800000000 call 0x5     
##  2 05    5b         pop ebx      
##  3 06    8bcb       mov ecx, ebx 
##  4 08    83c31e     add ebx, 0x1e
##  5 0b    33c0       xor eax, eax 
##  6 0d    33d2       xor edx, edx 
##  7 0f    8a03       mov al, [ebx]
##  8 11    8a11       mov dl, [ecx]
##  9 13    32c2       xor al, dl   
## 10 15    8803       mov [ebx], al
## # … with 23 more rows&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last instruction, &lt;code&gt;int3&lt;/code&gt;, is an interrupt, but let’s generalise it to a &lt;code&gt;halt&lt;/code&gt; because we’ll be done&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;asm[33, &amp;quot;instr&amp;quot;] &amp;lt;- &amp;quot;halt&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can run this with &lt;code&gt;{rx86}&lt;/code&gt;… we need a memory array and some registers&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mem &amp;lt;- create_mem()
registers &amp;lt;- create_reg()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we can run the code&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;runasm(asm)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As we saw earlier, the ‘code’ part of the asm is stored in &lt;code&gt;0x00&lt;/code&gt; to &lt;code&gt;0x21&lt;/code&gt; with the remaining addresses being used for temporary storage, from &lt;code&gt;0x23&lt;/code&gt;. The operations encoded
perform an &lt;code&gt;XOR&lt;/code&gt; between the values stored at &lt;code&gt;0x05&lt;/code&gt; through to &lt;code&gt;0x21&lt;/code&gt; with those starting at &lt;code&gt;0x23&lt;/code&gt;, storing the results starting at &lt;code&gt;0x23&lt;/code&gt;.
Extracting the memory from this offset onward (up to where it zeroes) results in&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;(mem_offset &amp;lt;- mem[which(names(mem) == &amp;quot;0x23&amp;quot;):length(mem)])&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   0x23   0x24   0x25   0x26   0x27   0x28   0x29   0x2a   0x2b   0x2c   0x2d 
## &amp;quot;0x68&amp;quot; &amp;quot;0x74&amp;quot; &amp;quot;0x74&amp;quot; &amp;quot;0x70&amp;quot; &amp;quot;0x3a&amp;quot; &amp;quot;0x2f&amp;quot; &amp;quot;0x2f&amp;quot; &amp;quot;0x77&amp;quot; &amp;quot;0x77&amp;quot; &amp;quot;0x77&amp;quot; &amp;quot;0x2e&amp;quot; 
##   0x2e   0x2f   0x30   0x31   0x32   0x33   0x34   0x35   0x36   0x37   0x38 
## &amp;quot;0x64&amp;quot; &amp;quot;0x73&amp;quot; &amp;quot;0x64&amp;quot; &amp;quot;0x2e&amp;quot; &amp;quot;0x67&amp;quot; &amp;quot;0x6f&amp;quot; &amp;quot;0x76&amp;quot; &amp;quot;0x2e&amp;quot; &amp;quot;0x61&amp;quot; &amp;quot;0x75&amp;quot; &amp;quot;0x2f&amp;quot; 
##   0x39   0x3a   0x3b   0x3c   0x3d   0x3e   0x3f   0x40   0x41   0x42   0x43 
## &amp;quot;0x64&amp;quot; &amp;quot;0x65&amp;quot; &amp;quot;0x63&amp;quot; &amp;quot;0x6f&amp;quot; &amp;quot;0x64&amp;quot; &amp;quot;0x65&amp;quot; &amp;quot;0x64&amp;quot; &amp;quot;0x2e&amp;quot; &amp;quot;0x68&amp;quot; &amp;quot;0x74&amp;quot; &amp;quot;0x6d&amp;quot; 
##   0x44   0x45   0x46   0x47   0x48   0x49   0x4a   0x4b   0x4c   0x4d   0x4e 
## &amp;quot;0x6c&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0xcc&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; 
##   0x4f   0x50   0x51   0x52   0x53   0x54   0x55   0x56   0x57   0x58   0x59 
## &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; 
##   0x5a   0x5b   0x5c   0x5d   0x5e   0x5f   0x60   0x61   0x62   0x63   0x64 
## &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; 
##   0x65   0x66   0x67   0x68   0x69   0x6a   0x6b   0x6c   0x6d   0x6e   0x6f 
## &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; 
##   0x70   0x71   0x72   0x73   0x74   0x75   0x76   0x77   0x78   0x79   0x7a 
## &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; 
##   0x7b   0x7c   0x7d   0x7e   0x7f 
## &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot; &amp;quot;0x00&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then lastly, we need to convert this sequence of hex values into characters. I’ve added a helper which achieves this, dropping everything after the first null-terminating byte (&lt;code&gt;0x00&lt;/code&gt;) then&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;hex2string(mem_offset)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;http://www.dsd.gov.au/decoded.html&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;TADA!&lt;/p&gt;
&lt;p&gt;This example is stored along with the package as a vignette, so&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;vignette(&amp;quot;dsd_ruxcon_challenge&amp;quot;, package = &amp;quot;rx86&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The link in this solution just redirects to the ASD frontpage since the puzzle is now over 10 years old, but when it was active it led to a page with some binary&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0100 0011 0100 1111 0100 1110 0100 0111 0101 0010 0100 0001 0101 0100 0101
0101 0100 1100 0100 0001 0101 0100 0100 1001 0100 1111 0100 1110 0101 0011&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Originally, I solved this part at the command line by storing this code in a file named &lt;code&gt;decoded&lt;/code&gt; and running a similar &lt;code&gt;bc&lt;/code&gt; conversion to before, but this time from binary (ibase=2) to hex (obase=16), storing the result in &lt;code&gt;decoded.hex&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;for bin in $(cat decoded) ; do echo &amp;quot;obase=16;ibase=2; $bin&amp;quot; | bc &amp;gt;&amp;gt; decoded.hex ; done&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From there, removing the line breaks and spaces, and passing through &lt;code&gt;xxd&lt;/code&gt; in reverse (similar to &lt;code&gt;hexdump&lt;/code&gt; but reverse works on my machine)&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;cat decoded.hex | tr &amp;#39;\n&amp;#39; &amp;#39; &amp;#39; | sed &amp;#39;s/ //g&amp;#39; | xxd -r -p &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, I’ll hold off showing the answer, but it was correct.&lt;/p&gt;
&lt;p&gt;It would be satisfying to also do this in R, so I added another helper in &lt;code&gt;{rx86}&lt;/code&gt; that does this conversion - it’s not terribly complex, but involves splitting a string into pairs of strings (split at some point) and a conversion&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;split_pairs &amp;lt;- function(x, split = &amp;quot;&amp;quot;) {
  sst &amp;lt;- strsplit(x, split)[[1]]
  out &amp;lt;- paste0(sst[c(TRUE, FALSE)], sst[c(FALSE, TRUE)])
  paste0(out, collapse = &amp;quot;,&amp;quot;)
}

bin2ascii &amp;lt;- function(bin) {
  nolb &amp;lt;- gsub(&amp;quot;\n&amp;quot;, &amp;quot; &amp;quot;, bin)
  split &amp;lt;- strsplit(split_pairs(paste(nolb, collapse = &amp;quot; &amp;quot;), split = &amp;quot; &amp;quot;), &amp;quot;,&amp;quot;)[[1]]
  ints &amp;lt;- strtoi(split, base = 2)
  intToUtf8(ints)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It appears to do the job&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;binary &amp;lt;- &amp;quot;0100 0011 0100 1111 0100 1110 0100 0111 0101 0010 0100 0001 0101 0100 0101
0101 0100 1100 0100 0001 0101 0100 0100 1001 0100 1111 0100 1110 0101 0011&amp;quot;

bin2ascii(binary)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;CONGRATULATIONS&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There, an (almost) entirely R solution to the puzzle, and all it took was writing my own x86 assembly parser.&lt;/p&gt;
&lt;p&gt;I did want to see if I’d made my parser too specific and it only worked with this one example around which I’d designed it, so I wanted to add another example. This
journey started with the book ‘Code’, so it felt fitting to use an example from there. In the book, an example of multiplying two 8-bit numbers is used, which
involved an &lt;code&gt;ADC&lt;/code&gt; (add with carry) operation to handle overflow. This seemed like a good candidate, and I started coding it, but soon realised that the exact routine
relied on an &lt;code&gt;add al, 0xff&lt;/code&gt; which has the effect of adding -1 in 8-bit, but on my machine&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as.integer(0xff)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 255&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as.hexmode(-1)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;ffffffff&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which isn’t compatible. I &lt;em&gt;could&lt;/em&gt; instead code a &lt;code&gt;SUB&lt;/code&gt; opcode and &lt;code&gt;sub al, 0x01&lt;/code&gt; (which I did) but at this point I decided to abandon the 8-bit idea and simplify down to just doing essential part of the program which multiplies 127 and 28 through repeated additions (via a loop). The asm for this is also stored in the package, and executing it is as simple as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mult_asm &amp;lt;- suppressWarnings(
  readr::read_fwf(system.file(&amp;quot;asm&amp;quot;, &amp;quot;mult.asm&amp;quot;, package = &amp;quot;rx86&amp;quot;), 
                  col_types = &amp;quot;ccc&amp;quot;,
                  col_positions = readr::fwf_widths(c(3, 6, 20)))
)
colnames(mult_asm) &amp;lt;- c(&amp;quot;addr&amp;quot;, &amp;quot;bytecode&amp;quot;, &amp;quot;instr&amp;quot;)
print(mult_asm)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 14 x 3
##    addr  bytecode instr         
##    &amp;lt;chr&amp;gt; &amp;lt;chr&amp;gt;    &amp;lt;chr&amp;gt;         
##  1 00    101005   mov al, [0x22]
##  2 03    201001   add al, [0x20]
##  3 06    111005   mov [0x22], al
##  4 09    101004   mov al, [0x21]
##  5 0c    221000   sub al, 0x01  
##  6 0f    111004   mov 0x21, al  
##  7 12    101003   jnz 0x00      
##  8 15    20001e   halt          
##  9 18    111003   invalid       
## 10 1b    330000   invalid       
## 11 1e    ff00     invalid       
## 12 20    a7       data 167      
## 13 21    1c       data 28       
## 14 22    00       result&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, we need a new memory array and some registers&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mem &amp;lt;- create_mem(len = 64)
registers &amp;lt;- create_reg()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then run the code&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;runasm(mult_asm)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final result can be extracted but it is still a hex value&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mem[sanitize(0x22)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##     0x22 
## &amp;quot;0x1244&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Converting it to an integer gives the expected result&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as.integer(mem[sanitize(0x22)])&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4676&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;167*28&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4676&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This, too, is stored as a vignette in the package, and can be found with&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;vignette(&amp;quot;mult_code_petzold&amp;quot;, package = &amp;quot;rx86&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The package is far from perfect, and only supports what I needed it to, but I’ve learned a lot about assembly and got to build something I’ve always wanted to. Plus I’ve finally written up my process for this puzzle that has been sitting on a disused laptop for a decade.&lt;/p&gt;
&lt;p&gt;That’s not quite the end, though - I really wanted to test out what I’ve learned so far, and what good is a new programming ability without a “Hello, world!” example?&lt;/p&gt;
&lt;p&gt;Almost all of the examples I found floating around use ‘modern’ asm (without the bytecode) and allow such luxuries as “storing a string” and “system calls” - none of that here, thank you. Instead, I added a new opcode mnemonic &lt;code&gt;int 0x80&lt;/code&gt; which sort of does what it should - it writes to screen the value (converted to character) of whatever is in the register &lt;code&gt;eax&lt;/code&gt;. That’s helpful, but I still need
the assembly that will use that. This is where I feel I’ve actually hand-programmed something myself. This is a piece of code that could literally have been punched into a &lt;a href=&#34;https://en.wikipedia.org/wiki/Punched_card&#34;&gt;card&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;images/Used_Punchcard_(5151286161).jpg&#34; alt=&#34;&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;Punch card&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The whole thing works, of course&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;hello_asm &amp;lt;- suppressWarnings(
  readr::read_fwf(system.file(&amp;quot;asm&amp;quot;, &amp;quot;helloworld.asm&amp;quot;, package = &amp;quot;rx86&amp;quot;), 
                  col_types = &amp;quot;ccc&amp;quot;,
                  col_positions = readr::fwf_widths(c(3, 3, 20)))
)
colnames(hello_asm) &amp;lt;- c(&amp;quot;addr&amp;quot;, &amp;quot;bytecode&amp;quot;, &amp;quot;instr&amp;quot;)
print(hello_asm)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 23 x 3
##    addr  bytecode instr        
##    &amp;lt;chr&amp;gt; &amp;lt;chr&amp;gt;    &amp;lt;chr&amp;gt;        
##  1 00    10       mov ecx, 0x0e
##  2 01    10       mov al, 0x08 
##  3 02    10       mov eax, [al]
##  4 03    cc       int 0x80     
##  5 04    28       sub ecx, 0x01
##  6 05    70       jz 0x17      
##  7 06    05       add al, 0x01 
##  8 07    e9       jmp 0x02     
##  9 08    48       data         
## 10 09    65       data         
## # … with 13 more rows&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mem &amp;lt;- create_mem()
registers &amp;lt;- create_reg()

runasm(hello_asm)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## Hello, world!&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and I find that honestly, ridiculously pleasing.&lt;/p&gt;
&lt;p&gt;This, too, is included in the package as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;vignette(&amp;quot;helloworld&amp;quot;, package = &amp;quot;rx86&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m satisfied that &lt;code&gt;{rx86}&lt;/code&gt; works, at least in some sense.&lt;/p&gt;
&lt;p&gt;I’ve learned a lot along the way, and who knows, maybe I’ll add some &lt;a href=&#34;https://en.wikipedia.org/wiki/X86_instruction_listings&#34;&gt;more opcodes&lt;/a&gt; to the package. If you have some suggestions, please let me know!&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 4.0.3 (2020-10-10)
##  os       Pop!_OS 20.10               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2021-12-23                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date       lib source        
##  base64enc     0.1-3   2015-07-28 [1] CRAN (R 4.0.3)
##  blogdown      1.7     2021-12-19 [1] CRAN (R 4.0.3)
##  bookdown      0.24    2021-09-02 [1] CRAN (R 4.0.3)
##  bslib         0.3.1   2021-10-06 [1] CRAN (R 4.0.3)
##  callr         3.5.1   2020-10-13 [1] CRAN (R 4.0.3)
##  cli           3.1.0   2021-10-27 [1] CRAN (R 4.0.3)
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 4.0.3)
##  desc          1.4.0   2021-09-28 [1] CRAN (R 4.0.3)
##  devtools      2.3.2   2020-09-18 [1] CRAN (R 4.0.3)
##  digest        0.6.27  2020-10-24 [1] CRAN (R 4.0.3)
##  dplyr         1.0.2   2020-08-18 [1] CRAN (R 4.0.3)
##  ellipsis      0.3.1   2020-05-15 [1] CRAN (R 4.0.3)
##  evaluate      0.14    2019-05-28 [1] CRAN (R 4.0.3)
##  fansi         0.4.1   2020-01-08 [1] CRAN (R 4.0.3)
##  fastmap       1.1.0   2021-01-25 [1] CRAN (R 4.0.3)
##  fs            1.5.0   2020-07-31 [1] CRAN (R 4.0.3)
##  generics      0.1.0   2020-10-31 [1] CRAN (R 4.0.3)
##  glue          1.4.2   2020-08-27 [1] CRAN (R 4.0.3)
##  hms           0.5.3   2020-01-08 [1] CRAN (R 4.0.3)
##  htmltools     0.5.2   2021-08-25 [1] CRAN (R 4.0.3)
##  jquerylib     0.1.4   2021-04-26 [1] CRAN (R 4.0.3)
##  jsonlite      1.7.2   2020-12-09 [1] CRAN (R 4.0.3)
##  knitr         1.37    2021-12-16 [1] CRAN (R 4.0.3)
##  lifecycle     1.0.1   2021-09-24 [1] CRAN (R 4.0.3)
##  magrittr      2.0.1   2020-11-17 [1] CRAN (R 4.0.3)
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 4.0.3)
##  pillar        1.4.7   2020-11-20 [1] CRAN (R 4.0.3)
##  pkgbuild      1.2.0   2020-12-15 [1] CRAN (R 4.0.3)
##  pkgconfig     2.0.3   2019-09-22 [1] CRAN (R 4.0.3)
##  pkgload       1.1.0   2020-05-29 [1] CRAN (R 4.0.3)
##  prettyunits   1.1.1   2020-01-24 [1] CRAN (R 4.0.3)
##  processx      3.4.5   2020-11-30 [1] CRAN (R 4.0.3)
##  ps            1.5.0   2020-12-05 [1] CRAN (R 4.0.3)
##  purrr         0.3.4   2020-04-17 [1] CRAN (R 4.0.3)
##  R6            2.5.0   2020-10-28 [1] CRAN (R 4.0.3)
##  readr         1.4.0   2020-10-05 [1] CRAN (R 4.0.3)
##  remotes       2.2.0   2020-07-21 [1] CRAN (R 4.0.3)
##  rlang         0.4.10  2020-12-30 [1] CRAN (R 4.0.3)
##  rmarkdown     2.11    2021-09-14 [1] CRAN (R 4.0.3)
##  rprojroot     2.0.2   2020-11-15 [1] CRAN (R 4.0.3)
##  rstudioapi    0.13    2020-11-12 [1] CRAN (R 4.0.3)
##  rx86        * 0.1.0   2021-12-22 [1] local         
##  sass          0.4.0   2021-05-12 [1] CRAN (R 4.0.3)
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 4.0.3)
##  stringi       1.5.3   2020-09-09 [1] CRAN (R 4.0.3)
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 4.0.3)
##  testthat      3.0.1   2020-12-17 [1] CRAN (R 4.0.3)
##  tibble        3.0.4   2020-10-12 [1] CRAN (R 4.0.3)
##  tidyr         1.1.2   2020-08-27 [1] CRAN (R 4.0.3)
##  tidyselect    1.1.0   2020-05-11 [1] CRAN (R 4.0.3)
##  usethis       2.1.5   2021-12-09 [1] CRAN (R 4.0.3)
##  utf8          1.1.4   2018-05-24 [1] CRAN (R 4.0.3)
##  vctrs         0.3.6   2020-12-17 [1] CRAN (R 4.0.3)
##  withr         2.3.0   2020-09-22 [1] CRAN (R 4.0.3)
##  xfun          0.29    2021-12-14 [1] CRAN (R 4.0.3)
##  yaml          2.2.1   2020-02-01 [1] CRAN (R 4.0.3)
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.0
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Improving a Visualization</title>
      <link>https://jcarroll.com.au/2021/07/02/improving-a-visualization/</link>
      <pubDate>Fri, 02 Jul 2021 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2021/07/02/improving-a-visualization/</guid>
      <description>&lt;p&gt;I saw &lt;a href=&#34;https://www.reddit.com/r/dataisbeautiful/comments/mtld5f/oc_us_streaming_services_market_share_2020_vs_2021/&#34;&gt;this post&lt;/a&gt;
on Reddit’s r/dataisbeautiful showing this plot of streaming services market
share, comparing 2020 to 2021&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;images/streaming.png&#34; alt=&#34;&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;US Streaming Services Market Share, 2020 vs 2021&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;and thought it looked like a good candidate for trying out some plot improvement techniques.&lt;/p&gt;
&lt;p&gt;Yes, that was a reasonably long while ago, this post has taken quite some time to put together. Life.&lt;/p&gt;
&lt;p&gt;I’ve played with &lt;a href=&#34;https://jcarroll.com.au/2019/08/13/ggtext-for-images-as-x-axis-labels/&#34;&gt;adding images to plot axes&lt;/a&gt;
several times (also &lt;a href=&#34;https://jcarroll.com.au/2016/06/02/images-as-x-axis-labels/&#34;&gt;here&lt;/a&gt;, &lt;a href=&#34;https://jcarroll.com.au/2016/06/03/images-as-x-axis-labels-updated/&#34;&gt;here&lt;/a&gt;, &lt;a href=&#34;https://jcarroll.com.au/2018/10/16/even-more-images-as-x-axis-labels/&#34;&gt;here&lt;/a&gt;) so that part shouldn’t pose
too much of a challenge. First, I’ll try to rebuild the original. The &lt;a href=&#34;https://www.reddit.com/r/dataisbeautiful/comments/mtld5f/oc_us_streaming_services_market_share_2020_vs_2021/gv0bv4j?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&#34;&gt;original was built in powerpoint&lt;/a&gt; but I’ll be reproducing it with R (surprise, surprise).&lt;/p&gt;
&lt;p&gt;The data itself appears to be captured from something like &lt;a href=&#34;https://www.thewrap.com/netflix-streaming-us-market-share-chart/&#34;&gt;this page&lt;/a&gt; (paywalled) but the precise values aren’t important; I’ll just take them directly from the original plot manually&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;streaming &amp;lt;- tibble::tribble(
  ~service, ~`2020`, ~`2021`,
  &amp;quot;netflix&amp;quot;,    29, 20,
  &amp;quot;prime&amp;quot;,      21, 16,
  &amp;quot;hulu&amp;quot;,       16, 13,
  &amp;quot;disney&amp;quot;,     12, 11,
  &amp;quot;apple&amp;quot;,       4,  5,
  &amp;quot;peacock&amp;quot;,     0,  5,
  &amp;quot;hbo&amp;quot;,         3, 12,
  &amp;quot;paramount&amp;quot;,   2,  3,
  &amp;quot;other&amp;quot;,      13, 15,
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can build a simple barplot from this data with &lt;code&gt;{ggplot2}&lt;/code&gt;. First we’ll need it in long format, with the services ordered as
they are in the original. From that I can build a basic bar plot with dodged bars. There’s a few fiddly bits to work out, which I’ll try to
go through with code comments.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)

## pivot to long format with the 
## year and share as their own columns
streaming_long &amp;lt;- tidyr::pivot_longer(streaming, 
                                      cols = -service, 
                                      names_to = &amp;quot;year&amp;quot;, 
                                      values_to = &amp;quot;share&amp;quot;)

## plot the years side-by-side in the original order
p &amp;lt;- ggplot(streaming_long) + 
  geom_col(aes(factor(service, levels = streaming$service), 
               share, fill = year), position = position_dodge(width = 0.9)) + 
  ## add a hidden set of points to make the legend circles easily
  geom_point(aes(x = service, y = -10, color = year, fill = year), size = 4) + 
  ## add the percentages just above each bar
  geom_text(aes(service, share + 1, label = paste0(share, &amp;quot;%&amp;quot;), group = year),
            position = position_dodge(width = 0.9), size = 3) +
  ## use similar colours to the original
  scale_fill_manual(values = c(`2020` = &amp;quot;red3&amp;quot;, `2021` = &amp;quot;black&amp;quot;)) +
  scale_color_manual(values = c(`2020` = &amp;quot;red3&amp;quot;, `2021` = &amp;quot;black&amp;quot;)) + 
  ## hide the fill legend and make the color legend horizontal
  guides(fill = &amp;quot;none&amp;quot;, color = guide_legend(direction = &amp;quot;horizontal&amp;quot;)) +
  scale_y_continuous(labels = scales::percent_format(scale = 1), 
                     limits = c(0, 35)) +
  labs(title = &amp;quot;US Streaming Market Share&amp;quot;, 
       subtitle = &amp;quot;2020 vs 2021&amp;quot;, 
       caption = &amp;quot;Source: Ampere Analytics via The Wrap
       
       Other Streatming Services include ESPN+, Showtime,
       Sling TV, Youtube TV, and Starz&amp;quot;,
       x = &amp;quot;&amp;quot;, y = &amp;quot;&amp;quot;) +
  theme_minimal() + 
  theme(axis.text = element_text(size = 10),
        plot.title = element_text(size = 28, hjust= 0.5), 
        plot.subtitle = element_text(size = 28, hjust = 0.5),
        plot.caption = element_text(size = 7, color = &amp;quot;grey60&amp;quot;),
        plot.background = element_rect(fill = &amp;quot;#f4f7fc&amp;quot;, size = 0),
        legend.title = element_blank(),
        legend.text= element_text(size = 12),
        panel.grid = element_blank(),
        ## move the color legend to an inset 
        legend.position = c(0.85, 0.8)) 
p&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-warning text-warning&#34;&gt;&lt;code&gt;## Warning: Removed 18 rows containing missing values (geom_point).&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;staticunnamed-chunk-2-1.png&#34; width=&#34;100%&#34; /&gt;
Not bad. Let’s get some of the other elements looking right. I used a font identifying site to pick a similar font
which seems to be &lt;a href=&#34;https://www.ffonts.net/Josefin-Slab-SemiBold-Italic.font.download&#34;&gt;Josefin Slab SemiBold&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(extrafont)
fontfamily &amp;lt;- &amp;quot;Josefin Slab SemiBold&amp;quot;

p &amp;lt;- p + theme(plot.title = element_text(family = fontfamily),
               plot.subtitle = element_text(family = fontfamily))
p&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-warning text-warning&#34;&gt;&lt;code&gt;## Warning: Removed 18 rows containing missing values (geom_point).&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;staticunnamed-chunk-3-1.png&#34; width=&#34;100%&#34; /&gt;
That’s fairly close. For the logos I’ll use the versions on Wikipedia&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;wiki &amp;lt;- &amp;quot;https://upload.wikimedia.org/wikipedia/commons/thumb/&amp;quot;
logos &amp;lt;- tibble::tribble(
  ~service, ~logo,
  &amp;quot;netflix&amp;quot;, paste0(wiki, &amp;quot;0/08/Netflix_2015_logo.svg/340px-Netflix_2015_logo.svg.png&amp;quot;),
  &amp;quot;prime&amp;quot;, paste0(wiki, &amp;quot;1/11/Amazon_Prime_Video_logo.svg/450px-Amazon_Prime_Video_logo.svg.png&amp;quot;),
  &amp;quot;hulu&amp;quot;, paste0(wiki, &amp;quot;e/e4/Hulu_Logo.svg/440px-Hulu_Logo.svg.png&amp;quot;),
  &amp;quot;disney&amp;quot;, paste0(wiki, &amp;quot;3/3e/Disney%2B_logo.svg/320px-Disney%2B_logo.svg.png&amp;quot;),
  &amp;quot;apple&amp;quot;,  paste0(wiki, &amp;quot;2/28/Apple_TV_Plus_Logo.svg/500px-Apple_TV_Plus_Logo.svg.png&amp;quot;),
  &amp;quot;peacock&amp;quot;, paste0(wiki, &amp;quot;d/d3/NBCUniversal_Peacock_Logo.svg/440px-NBCUniversal_Peacock_Logo.svg.png&amp;quot;),
  &amp;quot;hbo&amp;quot;, paste0(wiki, &amp;quot;d/de/HBO_logo.svg/440px-HBO_logo.svg.png&amp;quot;),
  &amp;quot;paramount&amp;quot;, paste0(wiki, &amp;quot;a/a5/Paramount_Plus.svg/440px-Paramount_Plus.svg.png&amp;quot;),
  &amp;quot;other&amp;quot;, &amp;quot;other.png&amp;quot;
) %&amp;gt;% 
  mutate(path = file.path(&amp;quot;images&amp;quot;, paste(service, tools::file_ext(logo), sep = &amp;quot;.&amp;quot;)))
labels &amp;lt;- setNames(paste0(&amp;quot;&amp;lt;img src=&amp;#39;&amp;quot;, logos$path, &amp;quot;&amp;#39; width=&amp;#39;35&amp;#39; /&amp;gt;&amp;quot;), logos$service)
labels[[&amp;quot;other&amp;quot;]] &amp;lt;- &amp;quot;other&amp;lt;br /&amp;gt;streaming&amp;lt;br /&amp;gt;services&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and save a local copy for faster loading/just in case&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;for (r in 1:8) {
  download.file(logos$logo[r], logos$path[r])
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can leverage &lt;code&gt;{ggtext}&lt;/code&gt; to set these as the axis labels&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p &amp;lt;- p + 
  scale_x_discrete(labels = labels) + 
  theme(axis.text.x = ggtext::element_markdown())
p&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-warning text-warning&#34;&gt;&lt;code&gt;## Warning: Removed 18 rows containing missing values (geom_point).&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;staticunnamed-chunk-6-1.png&#34; width=&#34;100%&#34; /&gt;
That’s not too bad - for the sake of scrolling, here’s the original again&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;images/streaming.png&#34; alt=&#34;&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;US Streaming Services Market Share, 2020 vs 2021&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Now to try to improve it.&lt;/p&gt;
&lt;p&gt;My first thought on seeing this plot with the legend was that &lt;code&gt;{ggtext}&lt;/code&gt; makes this a lot easier to read by using the
title &lt;em&gt;as&lt;/em&gt; the legend. For the sake of the ‘removed rows containing missing values’ warning I’ll also drop the points layer&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p$layers[[2]] &amp;lt;- NULL ## drop the geom_points layer
p &amp;lt;- p + 
  labs(subtitle = &amp;quot;&amp;lt;span style = &amp;#39;color: red3;&amp;#39;&amp;gt;2020&amp;lt;/span&amp;gt; vs 2021&amp;quot;) + 
  theme(plot.subtitle = ggtext::element_markdown(), legend.position = &amp;quot;none&amp;quot;)
p&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;staticunnamed-chunk-7-1.png&#34; width=&#34;100%&#34; /&gt;
To help make the black bars more distinct from the text, we could make these a different colour&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p &amp;lt;- p + 
  scale_fill_manual(values = c(`2020` = &amp;quot;red3&amp;quot;, `2021` = &amp;quot;darkcyan&amp;quot;)) + 
  labs(subtitle = paste0(&amp;quot;&amp;lt;span style = &amp;#39;color: red3;&amp;#39;&amp;gt;2020&amp;lt;/span&amp;gt; &amp;quot;,
                         &amp;quot;vs &amp;lt;span style = &amp;#39;color: darkcyan;&amp;#39;&amp;gt;2021&amp;lt;/span&amp;gt;&amp;quot;)) + 
  theme(plot.subtitle = ggtext::element_markdown(), legend.position = &amp;quot;none&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Scale for &amp;#39;fill&amp;#39; is already present. Adding another scale for &amp;#39;fill&amp;#39;, which
## will replace the existing scale.&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;staticunnamed-chunk-8-1.png&#34; width=&#34;100%&#34; /&gt;
Now to see if there’s a better way to represent this data. These are fractions of the total share… would a pie chart be a candidate?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;streaming_pie &amp;lt;- left_join(streaming_long, logos, by = &amp;quot;service&amp;quot;)

p_pie &amp;lt;- ggplot(streaming_pie, aes(1, share, fill = service, image = path)) + 
  geom_col() + 
  coord_polar(&amp;quot;y&amp;quot;) +
  ggimage::geom_image(size = 0.12, position = position_stack(vjust = 0.5)) +
  facet_wrap(~year, strip.position = &amp;quot;bottom&amp;quot;) +
  guides(fill = &amp;quot;none&amp;quot;, color = guide_legend(direction = &amp;quot;horizontal&amp;quot;)) +
  labs(title = &amp;quot;US Streaming Market Share&amp;quot;, subtitle = &amp;quot;2020 vs 2021&amp;quot;, x = &amp;quot;&amp;quot;, y = &amp;quot;&amp;quot;) +
  theme_void() + 
  theme(text = element_text(size = 32),
        plot.title = element_text(family = fontfamily, size = 26, hjust = 0.5), 
        plot.subtitle = element_text(family = fontfamily, size = 26, hjust = 0.5),
        plot.background = element_rect(fill = &amp;quot;#f4f7fc&amp;quot;, size = 0),
        legend.title = element_blank())
p_pie&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;staticunnamed-chunk-9-1.png&#34; width=&#34;100%&#34; /&gt;
No, that’s harder for making comparisons. Forget that idea.&lt;/p&gt;
&lt;p&gt;This should possibly be a horizontal bar plot so that the labels read nicely&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p + 
  coord_flip() + 
  scale_x_discrete(labels = labels, limits = rev(streaming$service)) + 
  theme(axis.text.y = ggtext::element_markdown())&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Scale for &amp;#39;x&amp;#39; is already present. Adding another scale for &amp;#39;x&amp;#39;, which will
## replace the existing scale.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;staticunnamed-chunk-10-1.png&#34; width=&#34;100%&#34; /&gt;
The ‘insight’ this is trying to display is how each service’s share has grown
or shrunk. It wasn’t obvious to me that the original was ordered by that - decreases shown first, then increases (in some order, I’m still
not sure what). What might make for a better plot to center it on the 2020 share and show the growth (positive or negative)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;streaming_delta &amp;lt;- dplyr::mutate(streaming, growth = `2021` - `2020`)

p &amp;lt;- ggplot(streaming_delta) + 
  geom_col(aes(factor(service, levels = streaming$service), growth, fill = growth &amp;gt; 0)) + 
  labs(title = &amp;quot;US Streaming Market Share Growth&amp;quot;, x = &amp;quot;&amp;quot;, y = &amp;quot;&amp;quot;) +
  theme_minimal() + 
  theme(text = element_text(family = fontfamily),
        plot.title = element_text(size = 26), 
        plot.subtitle = element_text(size = 26)) + 
  scale_x_discrete(labels = labels) + 
  coord_flip() +
  theme(axis.text.y = ggtext::element_markdown()) +
  scale_fill_manual(values = c(`TRUE` = &amp;quot;darkcyan&amp;quot;, `FALSE` = &amp;quot;red3&amp;quot;)) + 
  labs(subtitle = paste0(&amp;quot;&amp;lt;span style = &amp;#39;color: darkcyan;&amp;#39;&amp;gt;Growth&amp;lt;/span&amp;gt; &amp;quot;,
                         &amp;quot;vs &amp;lt;span style = &amp;#39;color: red3;&amp;#39;&amp;gt;Loss&amp;lt;/span&amp;gt; (% of 2020)&amp;quot;)) + 
  theme(plot.subtitle = ggtext::element_markdown(),
        plot.background = element_rect(fill = &amp;quot;#f4f7fc&amp;quot;, size = 0))
p&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;staticunnamed-chunk-11-1.png&#34; width=&#34;100%&#34; /&gt;
Each comparison in the original required two bars, and the separation between the services didn’t make that easy to read. In this version,
the absolute scale is lost (services starting high and decreasing aren’t so distinct from those starting low and gaining slightly)
so what about using a dumbbell plot to show the separation between the two values while retaining their overall scales, rather than relying on comparing two bars?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggalt, include.only = &amp;quot;geom_dumbbell&amp;quot;)

p &amp;lt;- ggplot(streaming) + 
  ggalt::geom_dumbbell(aes(factor(service, levels = rev(streaming$service)), 
                           x = `2020`, xend = `2021`), 
                       colour_x = &amp;quot;red3&amp;quot;, size_x = 6,
                       colour_xend = &amp;quot;darkcyan&amp;quot;, size_xend = 6,
                       size = 1, dot_guide = TRUE, 
                       dot_guide_size = 0.5, 
                       dot_guide_colour = &amp;quot;grey25&amp;quot;) + 
  scale_x_continuous(labels = scales::percent_format(scale = 1), 
                   limits = c(0, 35)) +
  scale_y_discrete(labels = labels) + 
  labs(title = &amp;quot;US Streaming Market Share&amp;quot;, x = &amp;quot;&amp;quot;, y = &amp;quot;&amp;quot;) +
  labs(subtitle = paste0(&amp;quot;&amp;lt;span style = &amp;#39;color: red3;&amp;#39;&amp;gt;2020&amp;lt;/span&amp;gt; &amp;quot;,
                         &amp;quot;vs &amp;lt;span style = &amp;#39;color: darkcyan;&amp;#39;&amp;gt;2021&amp;lt;/span&amp;gt;&amp;quot;)) + 
  theme_minimal() +
  theme(plot.title = element_text(family = fontfamily, size = 26), 
        plot.subtitle = element_text(family = fontfamily, size = 26)) +
  theme(axis.text.y = ggtext::element_markdown(), 
        plot.subtitle = ggtext::element_markdown(), 
        plot.background = element_rect(fill = &amp;quot;#f4f7fc&amp;quot;, size = 0),
        legend.position = &amp;quot;none&amp;quot;) 
p&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-warning text-warning&#34;&gt;&lt;code&gt;## Warning: Use of `streaming$service` is discouraged. Use `service` instead.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;staticunnamed-chunk-12-1.png&#34; width=&#34;100%&#34; /&gt;
One last option to bring this data to life would be to animate between the two states…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(gganimate)

p &amp;lt;- ggplot(streaming_long) + 
  geom_point(aes(share, 
                 factor(service, levels = streaming$service)), 
             size = 5, color = &amp;quot;darkcyan&amp;quot;) + 
  scale_y_discrete(labels = labels) +
  labs(title = &amp;quot;US Streaming Market Share&amp;quot;, x = &amp;quot;&amp;quot;, y = &amp;quot;&amp;quot;) +
  labs(subtitle = &amp;quot;{closest_state}&amp;quot;) + 
  scale_x_continuous(labels = scales::percent_format(scale = 1), 
                     limits = c(0, 35)) +
  theme_minimal() +
  theme(text = element_text(family = fontfamily), 
        plot.title = element_text(size = 26), 
        plot.subtitle = element_text(size = 26),
        legend.position = &amp;quot;none&amp;quot;) +
  theme(axis.text.y = ggtext::element_markdown(),
        plot.background = element_rect(fill = &amp;quot;#f4f7fc&amp;quot;, size = 0))
  
anim &amp;lt;- p + 
  transition_states(year, transition_length = 4) +
  ease_aes() +
  enter_fade() +
  exit_fade()
animate(anim, renderer = gifski_renderer())
anim_save(filename = &amp;quot;images/streaming.gif&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;images/streaming.gif&#34; style=&#34;width:100.0%&#34; /&gt;
I think these last few communicate more than the original. It’s always amazing how easy it is to bring this data into R and
start playing with different presentations. Sure, perfecting the plots can take a little while, but
the data is there to be played with.&lt;/p&gt;
&lt;p&gt;One visualization which might have been interesting would be if we had the data on the transitions between services. Then
an &lt;a href=&#34;https://en.wikipedia.org/wiki/Alluvial_diagram&#34;&gt;alluvial plot&lt;/a&gt; would be very informative. Simulating that…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;streaming_flow &amp;lt;- tibble::tribble(
    ~`2020`, ~Freq, ~`2021`,
  &amp;quot;netflix&amp;quot;,    12, &amp;quot;netflix&amp;quot;,
  &amp;quot;netflix&amp;quot;,     4, &amp;quot;prime&amp;quot;,
  &amp;quot;netflix&amp;quot;,     6, &amp;quot;disney&amp;quot;,
  &amp;quot;netflix&amp;quot;,     3, &amp;quot;apple&amp;quot;,
  &amp;quot;netflix&amp;quot;,     4, &amp;quot;hbo&amp;quot;,
  &amp;quot;prime&amp;quot;,      16, &amp;quot;prime&amp;quot;,
  &amp;quot;prime&amp;quot;,       5, &amp;quot;netflix&amp;quot;,
  &amp;quot;prime&amp;quot;,       2, &amp;quot;hulu&amp;quot;,
  &amp;quot;prime&amp;quot;,       1, &amp;quot;disney&amp;quot;,
  &amp;quot;prime&amp;quot;,       3, &amp;quot;peacock&amp;quot;,
  &amp;quot;prime&amp;quot;,       4, &amp;quot;hbo&amp;quot;,
  &amp;quot;hulu&amp;quot;,       13, &amp;quot;hulu&amp;quot;,
  &amp;quot;hulu&amp;quot;,        1, &amp;quot;netflix&amp;quot;,
  &amp;quot;hulu&amp;quot;,        2, &amp;quot;prime&amp;quot;,
  &amp;quot;hulu&amp;quot;,        1, &amp;quot;disney&amp;quot;,
  &amp;quot;disney&amp;quot;,     11, &amp;quot;disney&amp;quot;,
  &amp;quot;disney&amp;quot;,      1, &amp;quot;netflix&amp;quot;,
  &amp;quot;disney&amp;quot;,      3, &amp;quot;prime&amp;quot;,
  &amp;quot;disney&amp;quot;,      1, &amp;quot;hulu&amp;quot;,
  &amp;quot;apple&amp;quot;,       4, &amp;quot;apple&amp;quot;,
  &amp;quot;apple&amp;quot;,       2, &amp;quot;netflix&amp;quot;,
  &amp;quot;apple&amp;quot;,       1, &amp;quot;prime&amp;quot;,
  &amp;quot;peacock&amp;quot;,     2, &amp;quot;peacock&amp;quot;,
  &amp;quot;peacock&amp;quot;,     1, &amp;quot;netflix&amp;quot;,
  &amp;quot;hbo&amp;quot;,         3, &amp;quot;hbo&amp;quot;,
  &amp;quot;hbo&amp;quot;,         1, &amp;quot;prime&amp;quot;
)

library(ggalluvial)

lodes &amp;lt;- to_lodes_form(streaming_flow, axes = c(&amp;quot;2020&amp;quot;, &amp;quot;2021&amp;quot;))
lodes &amp;lt;- left_join(lodes, logos,  by = c(&amp;quot;stratum&amp;quot; = &amp;quot;service&amp;quot;))
lodes &amp;lt;- arrange(lodes, stratum)

ggplot(lodes, aes(x = x, stratum = stratum, alluvium = alluvium, 
                  y = Freq, fill = stratum, label = stratum, image = path)) + 
  geom_flow() +
  geom_stratum(alpha = 0.6) + 
  geom_text(stat = &amp;quot;stratum&amp;quot;, size = 4) +
  scale_x_discrete(limits = c(&amp;quot;2020&amp;quot;, &amp;quot;2021&amp;quot;), 
                   expand = c(0.1, 0.1)) +
  labs(title = &amp;quot; US Streaming Market Share Flow&amp;quot;, 
       subtitle = &amp;quot; 2020 to 2021&amp;quot;) +
  theme_void() +
  theme(axis.text.x = element_text(size = 20, vjust = 3),
        plot.title = element_text(family = fontfamily, size = 26), 
        plot.subtitle = element_text(family = fontfamily, size = 26),
        plot.background = element_rect(fill = &amp;quot;#f4f7fc&amp;quot;, size = 0),
        legend.position = &amp;quot;none&amp;quot;) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;staticunnamed-chunk-14-1.png&#34; width=&#34;100%&#34; /&gt;
I spent way too long trying to get the logos into this one, but there seems to be
a fundamental issue with combining &lt;code&gt;{ggalluvial}&lt;/code&gt; with &lt;code&gt;{ggimage}&lt;/code&gt; which I coulnd’t resolve.&lt;/p&gt;
&lt;p&gt;Do you have a better way to present this data? Let me know in the comments or on &lt;a href=&#34;https://twitter.com/carroll_jono&#34;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 4.0.3 (2020-10-10)
##  os       Pop!_OS 20.10               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2021-07-02                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package      * version  date       lib source        
##  ash            1.0-15   2015-09-01 [1] CRAN (R 4.0.3)
##  assertthat     0.2.1    2019-03-21 [1] CRAN (R 4.0.3)
##  BiocManager    1.30.12  2021-03-28 [1] CRAN (R 4.0.3)
##  blogdown       1.2      2021-03-04 [1] CRAN (R 4.0.3)
##  bookdown       0.21     2020-10-13 [1] CRAN (R 4.0.3)
##  callr          3.5.1    2020-10-13 [1] CRAN (R 4.0.3)
##  cli            2.2.0    2020-11-20 [1] CRAN (R 4.0.3)
##  colorspace     2.0-0    2020-11-11 [1] CRAN (R 4.0.3)
##  crayon         1.3.4    2017-09-16 [1] CRAN (R 4.0.3)
##  desc           1.2.0    2018-05-01 [1] CRAN (R 4.0.3)
##  devtools       2.3.2    2020-09-18 [1] CRAN (R 4.0.3)
##  digest         0.6.27   2020-10-24 [1] CRAN (R 4.0.3)
##  dplyr        * 1.0.2    2020-08-18 [1] CRAN (R 4.0.3)
##  ellipsis       0.3.1    2020-05-15 [1] CRAN (R 4.0.3)
##  evaluate       0.14     2019-05-28 [1] CRAN (R 4.0.3)
##  extrafont    * 0.17     2014-12-08 [1] CRAN (R 4.0.3)
##  extrafontdb    1.0      2012-06-11 [1] CRAN (R 4.0.3)
##  fansi          0.4.1    2020-01-08 [1] CRAN (R 4.0.3)
##  farver         2.0.3    2020-01-16 [1] CRAN (R 4.0.3)
##  fs             1.5.0    2020-07-31 [1] CRAN (R 4.0.3)
##  generics       0.1.0    2020-10-31 [1] CRAN (R 4.0.3)
##  ggalluvial   * 0.12.3   2020-12-05 [1] CRAN (R 4.0.3)
##  ggalt        * 0.4.0    2017-02-15 [1] CRAN (R 4.0.3)
##  gganimate    * 1.0.7    2020-10-15 [1] CRAN (R 4.0.3)
##  ggimage      * 0.2.8    2020-04-02 [1] CRAN (R 4.0.3)
##  ggplot2      * 3.3.3    2020-12-30 [1] CRAN (R 4.0.3)
##  ggplotify      0.0.7    2021-05-11 [1] CRAN (R 4.0.3)
##  ggtext         0.1.1    2020-12-17 [1] CRAN (R 4.0.3)
##  gifski         1.4.3-1  2021-05-02 [1] CRAN (R 4.0.3)
##  glue           1.4.2    2020-08-27 [1] CRAN (R 4.0.3)
##  gridGraphics   0.5-1    2020-12-13 [1] CRAN (R 4.0.3)
##  gridtext       0.1.4    2020-12-10 [1] CRAN (R 4.0.3)
##  gtable         0.3.0    2019-03-25 [1] CRAN (R 4.0.3)
##  hms            0.5.3    2020-01-08 [1] CRAN (R 4.0.3)
##  htmltools      0.5.0    2020-06-16 [1] CRAN (R 4.0.3)
##  jsonlite       1.7.2    2020-12-09 [1] CRAN (R 4.0.3)
##  KernSmooth     2.23-18  2020-10-29 [4] CRAN (R 4.0.3)
##  knitr          1.30     2020-09-22 [1] CRAN (R 4.0.3)
##  labeling       0.4.2    2020-10-20 [1] CRAN (R 4.0.3)
##  lifecycle      0.2.0    2020-03-06 [1] CRAN (R 4.0.3)
##  magick         2.6.0    2021-01-13 [1] CRAN (R 4.0.3)
##  magrittr       2.0.1    2020-11-17 [1] CRAN (R 4.0.3)
##  maps           3.3.0    2018-04-03 [1] CRAN (R 4.0.3)
##  markdown       1.1      2019-08-07 [1] CRAN (R 4.0.3)
##  MASS           7.3-53   2020-09-09 [4] CRAN (R 4.0.2)
##  memoise        1.1.0    2017-04-21 [1] CRAN (R 4.0.3)
##  munsell        0.5.0    2018-06-12 [1] CRAN (R 4.0.3)
##  pillar         1.4.7    2020-11-20 [1] CRAN (R 4.0.3)
##  pkgbuild       1.2.0    2020-12-15 [1] CRAN (R 4.0.3)
##  pkgconfig      2.0.3    2019-09-22 [1] CRAN (R 4.0.3)
##  pkgload        1.1.0    2020-05-29 [1] CRAN (R 4.0.3)
##  png            0.1-7    2013-12-03 [1] CRAN (R 4.0.3)
##  prettyunits    1.1.1    2020-01-24 [1] CRAN (R 4.0.3)
##  processx       3.4.5    2020-11-30 [1] CRAN (R 4.0.3)
##  progress       1.2.2    2019-05-16 [1] CRAN (R 4.0.3)
##  proj4          1.0-10.1 2021-01-26 [1] CRAN (R 4.0.3)
##  ps             1.5.0    2020-12-05 [1] CRAN (R 4.0.3)
##  purrr          0.3.4    2020-04-17 [1] CRAN (R 4.0.3)
##  R6             2.5.0    2020-10-28 [1] CRAN (R 4.0.3)
##  RColorBrewer   1.1-2    2014-12-07 [1] CRAN (R 4.0.3)
##  Rcpp           1.0.5    2020-07-06 [1] CRAN (R 4.0.3)
##  remotes        2.2.0    2020-07-21 [1] CRAN (R 4.0.3)
##  rlang          0.4.10   2020-12-30 [1] CRAN (R 4.0.3)
##  rmarkdown      2.6      2020-12-14 [1] CRAN (R 4.0.3)
##  rprojroot      2.0.2    2020-11-15 [1] CRAN (R 4.0.3)
##  Rttf2pt1       1.3.8    2020-01-10 [1] CRAN (R 4.0.3)
##  rvcheck        0.1.8    2020-03-01 [1] CRAN (R 4.0.3)
##  scales         1.1.1    2020-05-11 [1] CRAN (R 4.0.3)
##  sessioninfo    1.1.1    2018-11-05 [1] CRAN (R 4.0.3)
##  stringi        1.5.3    2020-09-09 [1] CRAN (R 4.0.3)
##  stringr        1.4.0    2019-02-10 [1] CRAN (R 4.0.3)
##  testthat       3.0.1    2020-12-17 [1] CRAN (R 4.0.3)
##  tibble         3.0.4    2020-10-12 [1] CRAN (R 4.0.3)
##  tidyr          1.1.2    2020-08-27 [1] CRAN (R 4.0.3)
##  tidyselect     1.1.0    2020-05-11 [1] CRAN (R 4.0.3)
##  tweenr         1.0.2    2021-03-23 [1] CRAN (R 4.0.3)
##  usethis        2.0.0    2020-12-10 [1] CRAN (R 4.0.3)
##  vctrs          0.3.6    2020-12-17 [1] CRAN (R 4.0.3)
##  withr          2.3.0    2020-09-22 [1] CRAN (R 4.0.3)
##  xfun           0.22     2021-03-11 [1] CRAN (R 4.0.3)
##  xml2           1.3.2    2020-04-23 [1] CRAN (R 4.0.3)
##  yaml           2.2.1    2020-02-01 [1] CRAN (R 4.0.3)
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/4.0
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>isEven without modulo</title>
      <link>https://jcarroll.com.au/2020/03/09/iseven-without-modulo/</link>
      <pubDate>Mon, 09 Mar 2020 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2020/03/09/iseven-without-modulo/</guid>
      <description>&lt;p&gt;You may have seen the memes going around about fun ways to program the
straightforward function &lt;code&gt;isEven()&lt;/code&gt; which returns &lt;code&gt;TRUE&lt;/code&gt; if the input is even,
and &lt;code&gt;FALSE&lt;/code&gt; otherwise. I had a play with this and it turned into enough for a
blog post, and a nice walk through some features of R.&lt;/p&gt;
&lt;p&gt;The ‘traditional’ way to check if an integer is even is to check if it is
divisible by 2. This can be achieved with the modulo operator &lt;code&gt;%%&lt;/code&gt; which
gives the remainder after dividing by another number. For example, &lt;code&gt;5 modulo 2&lt;/code&gt;
or &lt;code&gt;5 %% 2&lt;/code&gt; gives 1 because 2 goes into 5 twice with 1 leftover. If a number &lt;code&gt;x&lt;/code&gt; is
even, it is an exact multiple of 2, and so &lt;code&gt;x %% 2 == 0&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;5 %% 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 1&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;6 %% 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A function which tests values of &lt;code&gt;x&lt;/code&gt; for this property could be written as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 1
isEven &amp;lt;- function(x) {
    ## traditional modulo check
    x %% 2 == 0
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;==&lt;/code&gt; operation checks that the left side is equal to the right side (but not
necessarily identical, e.g. the classes can be different) and returns either &lt;code&gt;TRUE&lt;/code&gt;
or &lt;code&gt;FALSE&lt;/code&gt; (or &lt;code&gt;NA&lt;/code&gt;, but that’s not an issue for the cases we’re looking at here).
I’ve also relied on the fact that the result of the last statement in a function
body is used as the return value if no explicit &lt;code&gt;return()&lt;/code&gt; is used.&lt;/p&gt;
&lt;p&gt;Confirming that this works is as easy as trying some values. It’s always good to
check that your function produces results you expect. It’s also a good idea to try
some odd values to ensure you don’t hit edge-cases.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;isEven(0)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;isEven(3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;isEven(4)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;isEven(-1)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;isEven(-6)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the process of playing with this function I refined how I tested my code. I started
with a set of confirming evaluations like above. Then I wanted to confirm that they
actually gave the results I expect, so I refined it to&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;test_isEven &amp;lt;- function() {
    all(
        isEven(0) == TRUE,
        isEven(3) == FALSE,
        isEven(4) == TRUE,
        isEven(-1) == FALSE,
        isEven(-6) == TRUE
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I just had one function to call which confirmed that all these tests gave
the expected results. Once I had explained this layout to myself with the word
‘expected’, I realised what I actually wanted was a test suite, and &lt;code&gt;testthat&lt;/code&gt;
is a great candidate for that. Refactoring the above into a series of expectations
might look like&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(testthat)
test_isEven &amp;lt;- function() {
    test_that(&amp;quot;isEven peforms as expected&amp;quot;, {
        expect_true(isEven(0))
        expect_false(isEven(3))
        expect_true(isEven(4))
        expect_false(isEven(-1))
        expect_true(isEven(-6))
    })
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I can test any implementation of &lt;code&gt;isEven()&lt;/code&gt; with just one function call, and if
one of the expectations fails I’ll know which it is. Running this with the above
&lt;code&gt;isEven()&lt;/code&gt; produces no output, so the tests succeeded&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The ‘no output’ might be concerning, so we can also run a negative control to make
sure it breaks when things are broken. Let’s break the &lt;code&gt;isEven()&lt;/code&gt; by reversing the
test&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 1a
isEven &amp;lt;- function(x) {
    ## (broken) traditional modulo check
    x %% 2 == 1
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error: Test failed: &amp;#39;isEven peforms as expected&amp;#39;
## * &amp;lt;text&amp;gt;:4: isEven(0) isn&amp;#39;t true.
## * &amp;lt;text&amp;gt;:5: isEven(3) isn&amp;#39;t false.
## * &amp;lt;text&amp;gt;:6: isEven(4) isn&amp;#39;t true.
## * &amp;lt;text&amp;gt;:7: isEven(-1) isn&amp;#39;t false.
## * &amp;lt;text&amp;gt;:8: isEven(-6) isn&amp;#39;t true.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, we can trust that if we make a mistake or don’t implement this properly,
we’ll know. Typically a function you write would have a lot more safety checking,
such as ensuring that we actually passed a value, and that it’s an integer, but for
the sake of this post I’m going to assume that these are both guaranteed to be true.&lt;/p&gt;
&lt;p&gt;This version of &lt;code&gt;isEven()&lt;/code&gt; is simple and it works, but that’s not what the internet
wants - a common challenge is to make a version of &lt;code&gt;isEven()&lt;/code&gt; which &lt;em&gt;doesn’t&lt;/em&gt; use
modulo. Now we need to think a little more, but we can at least check any
implementation with our tests.&lt;/p&gt;
&lt;p&gt;I came up with a few, both from borrowing from other solutions and on my own. Let’s see…&lt;/p&gt;
&lt;p&gt;If the last digit is any of 0, 2, 4, 6, or 8, then it’s an even number&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 2
isEven &amp;lt;- function(x) {
    ## ends with an even digit
    grepl(&amp;quot;[02468]$&amp;quot;, x)
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that same idea, if the least significant bit (binary) is unset then it’s even&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 3
isEven &amp;lt;- function(x) {
    ## least significant bit is unset
    x == 0 || !bitwAnd(x, 1)
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Continuing down the bitwise path, if we can shift left and right and get back to
the original number, then it’s even&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 4
isEven &amp;lt;- function(x) {
    ## bitwise shift right then left
    !(x-(bitwShiftL(bitwShiftR(x, 1), 1)))
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we alternate &lt;code&gt;FALSE&lt;/code&gt; and &lt;code&gt;TRUE&lt;/code&gt; counting from 0 to &lt;code&gt;x&lt;/code&gt; then we get our answer&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 5
isEven &amp;lt;- function(x) {
    ## alternate TRUE/FALSE
    y &amp;lt;- FALSE
    for (i in 0:x) {
        y &amp;lt;- !y
    }
    return(y)
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We could do the same thing with recursion&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 6
isEven &amp;lt;- function(x) {
    ## recursion, n-1 is odd if n is even
    if (x == 0) return(TRUE)
    !isEven(abs(x) - 1)
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not quite using modulo, integer division by 2, doubled, should
return the original value&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 7
isEven &amp;lt;- function(x) {
    ## integer division, doubled
    2*(x %/% 2) == x
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, the result of regular division cast to integer, doubled, should
return the original value&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 7a
isEven &amp;lt;- function(x) {
    ## normal division, doubled
    2*as.integer(x/2) == x
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we start from a number and count towards 0 by twos then we will hit 0
if the number is even&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 8
isEven &amp;lt;- function(x) {
    ## moving by 2s towards 0 ends at 0
    y &amp;lt;- x
    repeat({
        if (y == 0) return(TRUE)
        if (sign(x) != sign(y)) return(FALSE)
        y &amp;lt;- y - sign(x)*2
    })
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can write that a bit simpler if we only use the absolute value of &lt;code&gt;x&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 8a (abs version)
isEven &amp;lt;- function(x) {
    ## moving by 2s towards 0 ends at 0
    y &amp;lt;- abs(x)
    repeat({
        if (y == 0) return(TRUE)
        if (y &amp;lt; 0) return(FALSE)
        y &amp;lt;- y - 2
    })
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Exploiting mathematical properties, we know that -1 to any even power returns 1&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 9
isEven &amp;lt;- function(x) {
    ## -1 to an even power is 1
    (-1)**x == 1
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The relationship &lt;span class=&#34;math display&#34;&gt;\[\cos(2x) = -\cos(x)\]&lt;/span&gt; can also be exploited&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 10
isEven &amp;lt;- function(x) {
    ## cos(2x) == -cos(x)
    cos(x*pi) == -cos(pi)
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now for some more R-specific solutions… R rounds towards even integers, and
we can exploit that&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 11
isEven &amp;lt;- function(x) {
    ## R rounds even real numbers down
    round(x + 0.5) == x
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can create a vector of ‘every other integer’ and check whether a value is in
there&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 12
isEven &amp;lt;- function(x) {
    ## is x in set of &amp;#39;every other integer&amp;#39;?
    abs(x) %in% (0:abs(x))[c(TRUE, FALSE)]
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Creating a vector of &lt;code&gt;TRUE&lt;/code&gt; and &lt;code&gt;FALSE&lt;/code&gt; we can extract the element corresponding to
a value&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 13
isEven &amp;lt;- function(x) {
    ## even/odd sequence
    if (x == 0) return(TRUE)
    rep(c(FALSE, TRUE), (abs(x)/2) + 1)[abs(x)]
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, starting to get really absurd, we could solve the equation &lt;span class=&#34;math display&#34;&gt;\[2n = x\]&lt;/span&gt; which
will have an integer &lt;code&gt;n&lt;/code&gt; if &lt;code&gt;x&lt;/code&gt; is even&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 14
isEven &amp;lt;- function(x) {
    ## integer solution to 2n = x?
    n &amp;lt;- solve(2, x)
    as.integer(n) == n
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And, lastly, for the truly absurd, we can use the fact that “zero” and “eight” are
the only single digits written as English words with an “e”. This requires a
couple of extra packages, but can be done.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## 15
isEven &amp;lt;- function(x) {
    ## zero and eight are the only odd 
    ## last digit as words with an e
    last &amp;lt;- english::words(as.integer(stringr::str_sub(x, -1, -1)))
    last == &amp;quot;zero&amp;quot; || last == &amp;quot;eight&amp;quot; || !grepl(&amp;quot;e&amp;quot;, last)
}
test_isEven()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This isn’t an exhaustive list, but it seemed like a good place to stop looking.
If you can think of more then &lt;a href=&#34;https://twitter.com/carroll_jono/status/1236813430188691456?s=20&#34;&gt;add them to this thread on Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I hope this demonstrates the usefulness of writing functions and testing them with
&lt;code&gt;testthat&lt;/code&gt;. Plus, if the &lt;code&gt;%%&lt;/code&gt; operator ever breaks, you have plenty of alternatives.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.6.2 (2019-12-12)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2020-03-09                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date       lib source        
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.6.2)
##  backports     1.1.5   2019-10-02 [1] CRAN (R 3.6.2)
##  blogdown      0.18    2020-03-04 [1] CRAN (R 3.6.2)
##  bookdown      0.17    2020-01-11 [1] CRAN (R 3.6.2)
##  callr         3.4.2   2020-02-12 [1] CRAN (R 3.6.2)
##  cli           2.0.1   2020-01-08 [1] CRAN (R 3.6.2)
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.6.2)
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.6.2)
##  devtools      2.2.2   2020-02-17 [1] CRAN (R 3.6.2)
##  digest        0.6.24  2020-02-12 [1] CRAN (R 3.6.2)
##  ellipsis      0.3.0   2019-09-20 [1] CRAN (R 3.6.2)
##  english       1.2-5   2020-01-26 [1] CRAN (R 3.6.2)
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.6.2)
##  fansi         0.4.1   2020-01-08 [1] CRAN (R 3.6.2)
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.6.2)
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.6.2)
##  htmltools     0.4.0   2019-10-04 [1] CRAN (R 3.6.2)
##  knitr         1.28    2020-02-06 [1] CRAN (R 3.6.2)
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.6.2)
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.6.2)
##  pkgbuild      1.0.6   2019-10-09 [1] CRAN (R 3.6.2)
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.6.2)
##  prettyunits   1.1.1   2020-01-24 [1] CRAN (R 3.6.2)
##  processx      3.4.2   2020-02-09 [1] CRAN (R 3.6.2)
##  ps            1.3.2   2020-02-13 [1] CRAN (R 3.6.2)
##  R6            2.4.1   2019-11-12 [1] CRAN (R 3.6.2)
##  Rcpp          1.0.3   2019-11-08 [1] CRAN (R 3.6.2)
##  remotes       2.1.1   2020-02-15 [1] CRAN (R 3.6.2)
##  rlang         0.4.5   2020-03-01 [1] CRAN (R 3.6.2)
##  rmarkdown     2.1     2020-01-20 [1] CRAN (R 3.6.2)
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.6.2)
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.6.2)
##  stringi       1.4.5   2020-01-11 [1] CRAN (R 3.6.2)
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.6.2)
##  testthat    * 2.3.1   2019-12-01 [1] CRAN (R 3.6.2)
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.6.2)
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.6.2)
##  xfun          0.12    2020-01-13 [1] CRAN (R 3.6.2)
##  yaml          2.2.1   2020-02-01 [1] CRAN (R 3.6.2)
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.6
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>r-bugs :: object_size</title>
      <link>https://jcarroll.com.au/2019/10/12/r-bugs-file-info-object-size/</link>
      <pubDate>Sat, 12 Oct 2019 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2019/10/12/r-bugs-file-info-object-size/</guid>
      <description>&lt;p&gt;As soon as the &lt;a href=&#34;https://developer.r-project.org/Blog/public/2019/10/09/r-can-use-your-help-reviewing-bug-reports/index.html&#34;&gt;R-Foundation posted that they’re inviting cleanup of old bugs&lt;/a&gt;,
I knew it would be an opportunity to learn more about the way R works on the inside.&lt;/p&gt;
&lt;p&gt;I started looking through the list of open bugs for somewhere I could help out. I barely know
anything about the actual &lt;a href=&#34;https://colinfay.me/r-internals/r-internal-structures.html&#34;&gt;C internals of the language&lt;/a&gt;
(I’m hoping to learn) so I figured it would be best to start with some parts of the code I’m familiar with.&lt;/p&gt;
&lt;p&gt;I had an &lt;a href=&#34;https://bugs.r-project.org/bugzilla/show_bug.cgi?id=16877&#34;&gt;open bug report&lt;/a&gt; for the
internals of &lt;code&gt;glm&lt;/code&gt; which I extended with a reproducible example. I had another look through the
open bug reports for “glm” in case there was another report of this that I had overlooked (not that I can find)
and found another which seemed fairly straightforward - &lt;a href=&#34;https://bugs.r-project.org/bugzilla/show_bug.cgi?id=16522&#34;&gt;some out of date documentation&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://jcarroll.com.au/post/2019-10-12-r-bugs-file-info-object-size/index.en_files/glm_bug.png&#34; alt=&#34;Bug 16522&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;Bug 16522&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;That seems approachable. I tested that the documentation was still in that state (it was) and
that the example did what it said (it did). Lastly, I read through the source of that function to
double-check that the return value would indeed be more general. In fact, the &lt;code&gt;method&lt;/code&gt; return value
could be either the name of the fitting function as a character string, e.g.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;glm.fit2 &amp;lt;- glm.fit
glm(1:4 ~ rnorm(4), method = &amp;quot;glm.fit2&amp;quot;)$method&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;glm.fit2&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or the actual function definition, if it was provided that way&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;head(glm(1:4 ~ rnorm(4), method = glm.fit)$method)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##                                                                          
## 1 function (x, y, weights = rep(1, nobs), start = NULL, etastart = NULL, 
## 2     mustart = NULL, offset = rep(0, nobs), family = gaussian(),        
## 3     control = list(), intercept = TRUE, singular.ok = TRUE)            
## 4 {                                                                      
## 5     control &amp;lt;- do.call(&amp;quot;glm.control&amp;quot;, control)                         
## 6     x &amp;lt;- as.matrix(x)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(truncated for simplicity).&lt;/p&gt;
&lt;p&gt;This made for a small, (-2/+3)-line &lt;a href=&#34;https://bugs.r-project.org/bugzilla/attachment.cgi?id=2463&amp;amp;action=diff&#34;&gt;patch&lt;/a&gt;
which was accepted and is now part of the source of R.&lt;/p&gt;
&lt;p&gt;Sidenote: I made this patch using git, but I should really be doing this via SVN.
&lt;a href=&#34;https://twitter.com/michael_chirico/status/1181930491575848961&#34;&gt;This thread&lt;/a&gt;
by &lt;a href=&#34;https://twitter.com/michael_chirico&#34;&gt;Michael Chirico&lt;/a&gt; is what I’ll be following
from here on.&lt;/p&gt;
&lt;p&gt;Now, on to the next bug.&lt;/p&gt;
&lt;p&gt;I had a browse through the sections and found &lt;a href=&#34;https://bugs.r-project.org/bugzilla/show_bug.cgi?id=15389&#34;&gt;this one&lt;/a&gt;
from 2013&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://jcarroll.com.au/post//2019-10-12-r-bugs-file-info-object-size/index.en_files/file.info.png&#34; alt=&#34;Bug 15389&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;Bug 15389&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;That seems innocent enough, right? My experience with &lt;code&gt;object.size&lt;/code&gt; is when I look at how much
memory a given object is taking up (incorrectly, I now understand after reading &lt;a href=&#34;http://adv-r.had.co.nz/memory.html#object-size&#34;&gt;Advanced R&lt;/a&gt;). What I always liked about this function was that it
has a &lt;code&gt;format&lt;/code&gt; method so I could easily convert the standard output&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;object.size(mtcars)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 7208 bytes&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;into a different unit very easily&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;format(object.size(mtcars), &amp;quot;KB&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;7 Kb&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, in order to do this (to know to convert from bytes to Kb) the object needs to be classed
appropriately. That’s the case, here&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;class(object.size(mtcars))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;object_size&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That isn’t the case for the &lt;code&gt;size&lt;/code&gt; element of &lt;code&gt;file.info&lt;/code&gt;, though&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;example_file &amp;lt;- file.path(.Library, &amp;quot;base&amp;quot;, &amp;quot;R&amp;quot;, &amp;quot;base.rdb&amp;quot;)
file.info(example_file)[, c(&amp;quot;size&amp;quot;, &amp;quot;isdir&amp;quot;, &amp;quot;mode&amp;quot;)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##                                      size isdir mode
## /usr/lib/R/library/base/R/base.rdb 973156 FALSE  644&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is just a number&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;class(file.info(example_file)$size)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;numeric&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The suggestion is to make this of class &lt;code&gt;object_size&lt;/code&gt;, which would enable the
nice formatting of the unit (even though a ‘file’ is not an ‘object’). Seems fair, let’s
have a look at what needs to happen to make that work - hopefully it’s as simple as
adding a class to the &lt;code&gt;size&lt;/code&gt; element. I use RStudio, and I have a copy of the r-source
in a project, so I can simply &lt;kbd&gt;CTRL&lt;/kbd&gt;+&lt;kbd&gt;SHIFT&lt;/kbd&gt;+&lt;kbd&gt;F&lt;/kbd&gt; to search all
files in this project for “file.info”. Sure enough, it’s in &lt;a href=&#34;https://github.com/wch/r-source/blob/a5504314e6164e88953ed5bc10cd8b23e6a9685e/src/library/base/R/files.R#L164-L173&#34;&gt;&lt;code&gt;/src/library/base/R/files.R&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;file.info &amp;lt;- function(..., extra_cols = TRUE)
{
    res &amp;lt;- .Internal(file.info(fn &amp;lt;- c(...), extra_cols))
    res$mtime &amp;lt;- .POSIXct(res$mtime)
    res$ctime &amp;lt;- .POSIXct(res$ctime)
    res$atime &amp;lt;- .POSIXct(res$atime)
    class(res) &amp;lt;- &amp;quot;data.frame&amp;quot;
    attr(res, &amp;quot;row.names&amp;quot;) &amp;lt;- fn # not row.names&amp;lt;- as that does a length check
    res
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not much to it, but some surprises for sure. What immediately jumps out to me is that
the fact that the result is a &lt;code&gt;data.frame&lt;/code&gt; is achieved through the very hacky “slap a
class on it” method rather than &lt;code&gt;as.data.frame()&lt;/code&gt;. The call to &lt;code&gt;.Internal&lt;/code&gt; means the
actual work is done at the C level, so there may not be much hope changing the class of the
size there.&lt;/p&gt;
&lt;p&gt;The simplest thing would appear to be to convert &lt;code&gt;res$size&lt;/code&gt; to class &lt;code&gt;object_size&lt;/code&gt; as soon
as it’s created. There’s sometimes a converting function, e.g. &lt;code&gt;as.object_size&lt;/code&gt;, but I don’t see
one here. Looking at the internals of the &lt;code&gt;object.size&lt;/code&gt; function&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;object.size&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## function (x) 
## structure(.Call(C_objectSize, x), class = &amp;quot;object_size&amp;quot;)
## &amp;lt;bytecode: 0x564bd0b58e30&amp;gt;
## &amp;lt;environment: namespace:utils&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;suggests it’s safe enough to slap the class on an object, so let’s try that. I’ll rename
this function for now so we can see if it’s working&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;file.info2 &amp;lt;- function(..., extra_cols = TRUE)
{
    res &amp;lt;- .Internal(file.info(fn &amp;lt;- c(...), extra_cols))
    class(res$size) &amp;lt;- &amp;quot;object_size&amp;quot;
    res$mtime &amp;lt;- .POSIXct(res$mtime)
    res$ctime &amp;lt;- .POSIXct(res$ctime)
    res$atime &amp;lt;- .POSIXct(res$atime)
    class(res) &amp;lt;- &amp;quot;data.frame&amp;quot;
    attr(res, &amp;quot;row.names&amp;quot;) &amp;lt;- fn # not row.names&amp;lt;- as that does a length check
    res
}

file.info2(example_file)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in round(x/base^power, digits = digits): invalid second argument of length 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, that didn’t work. Huh. Did we do something wrong?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;file.info2(example_file)$size&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## 973156 bytes&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No, that actually works. Did it actually fail to return an object?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fi &amp;lt;- file.info2(example_file)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Huh, that works, too. Can we see what’s inside?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;str(fi)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;#39;data.frame&amp;#39;:    1 obs. of  10 variables:
##  $ size  : &amp;#39;object_size&amp;#39; num 973156
##  $ isdir : logi FALSE
##  $ mode  : &amp;#39;octmode&amp;#39; int 644
##  $ mtime : POSIXct, format: &amp;quot;2019-01-15 06:33:43&amp;quot;
##  $ ctime : POSIXct, format: &amp;quot;2019-08-10 20:44:16&amp;quot;
##  $ atime : POSIXct, format: &amp;quot;2019-08-10 20:44:13&amp;quot;
##  $ uid   : int 0
##  $ gid   : int 0
##  $ uname : chr &amp;quot;root&amp;quot;
##  $ grname: chr &amp;quot;root&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, that looks to be what we wanted - the &lt;code&gt;size&lt;/code&gt; element has the right class. If we print this, however&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;print(fi)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in round(x/base^power, digits = digits): invalid second argument of length 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, the issue seems to be in the print method somewhere. using &lt;code&gt;traceback()&lt;/code&gt; we can see
that the error comes from this line in &lt;code&gt;utils:::format.object_size&lt;/code&gt; which seems to be having
trouble finding the &lt;code&gt;digits&lt;/code&gt; value&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;paste(round(x/base^power, digits = digits), unit)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The formal arguments for &lt;code&gt;utils:::format.object_size&lt;/code&gt; has a default of &lt;code&gt;digits = 1L&lt;/code&gt; so why is it not being found? Tracing back
further we see that the &lt;code&gt;format.object_size&lt;/code&gt; method was called from &lt;code&gt;format.data.frame&lt;/code&gt; which loops through
the columns of the &lt;code&gt;data.frame&lt;/code&gt; and formats them according to each class there&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;format.data.frame &amp;lt;- function(x, ..., justify = &amp;quot;none&amp;quot;)
{
    nc &amp;lt;- length(x)
    &amp;lt;...&amp;gt;
    rval &amp;lt;- vector(&amp;quot;list&amp;quot;, nc)
    for(i in seq_len(nc))
       rval[[i]] &amp;lt;- format(x[[i]], ..., justify = justify)
    &amp;lt;...&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but there’s no mention of &lt;code&gt;digits&lt;/code&gt; here. Tracing even further back, this is called from &lt;code&gt;print.data.frame&lt;/code&gt; and
passes its &lt;code&gt;digits&lt;/code&gt; argument. That function has the signature&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;print.data.frame &amp;lt;-
    function(x, ..., digits = NULL, quote = FALSE, right = TRUE,
         row.names = TRUE, max = NULL)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and now we can see where the problem comes from - we try to print our &lt;code&gt;data.frame&lt;/code&gt; which has an &lt;code&gt;object_size&lt;/code&gt;
column, but that print method sets &lt;code&gt;digits = NULL&lt;/code&gt; which is passed to &lt;code&gt;format.data.frame&lt;/code&gt; which is passed to
&lt;code&gt;format.object_size&lt;/code&gt; which has no way to deal with &lt;code&gt;digits = NULL&lt;/code&gt;. Ugh.&lt;/p&gt;
&lt;p&gt;Can we test that? Sure, let’s create a simple &lt;code&gt;data.frame&lt;/code&gt;, make a column be &lt;code&gt;object_size&lt;/code&gt;, and try to
print it&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;df &amp;lt;- data.frame(x = 1, y = 2048)
print(df)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   x    y
## 1 1 2048&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;class(df$y) &amp;lt;- &amp;quot;object_size&amp;quot;
print(df)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in round(x/base^power, digits = digits): invalid second argument of length 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the behaviour if we auto-print an object by just referencing it by name&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;df&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in round(x/base^power, digits = digits): invalid second argument of length 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but what if we &lt;em&gt;do&lt;/em&gt; provide the &lt;code&gt;digits&lt;/code&gt; argument to an actual call?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;print(df, digits = 1L)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   x          y
## 1 1 2048 bytes&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SOLVED! But what to do about it? I see three options:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OPTION 1&lt;/strong&gt;: Don’t default to &lt;code&gt;digits = NULL&lt;/code&gt; in &lt;code&gt;print.data.frame&lt;/code&gt;. I’m not sure what the
consequence of this would be across all calls to this function, but I can’t imagine there’s much
use for that default. A better default would seem to be&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;getOption(&amp;quot;digits&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 7&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looking at &lt;code&gt;?options&lt;/code&gt; we can see how this is intended to be used&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;digits:
controls the number of significant digits to print when printing numeric values.
It is a suggestion only. Valid values are 1…22 with default 7. See the note
in print.default about values greater than 15.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;OPTION 2&lt;/strong&gt;: Make &lt;code&gt;round&lt;/code&gt; deal with &lt;code&gt;NULL&lt;/code&gt; values. I worry that is already handled in that an
error message appropriate to that function is generated&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;round(3.14159, digits = NULL)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in round(3.14159, digits = NULL): invalid second argument of length 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;OPTION 3&lt;/strong&gt;: Make &lt;code&gt;format.object_size&lt;/code&gt; capable of dealing with &lt;code&gt;digits = NULL&lt;/code&gt;. The fact that it
has no way of dealing with this value seems like an oversight, since it &lt;em&gt;must&lt;/em&gt; be a valid value
in order to pass it to &lt;code&gt;round&lt;/code&gt;. Again, the option of using a more sensible default comes to mind,
but there already &lt;em&gt;is&lt;/em&gt; a default in place here (&lt;code&gt;digits = 1L&lt;/code&gt;) it’s just being overridden.&lt;/p&gt;
&lt;p&gt;Instead, we would need some sort of handling in this situation, such as&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;digits &amp;lt;- ifelse(is.null(digits), 1L, digits)

## or 

digits &amp;lt;- ifelse(is.null(digits), getOption(&amp;quot;digits&amp;quot;), digits)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I &lt;em&gt;think&lt;/em&gt; this last option is the most satisfactory (though perhaps the first should
also be addressed) so let’s see if that’s sufficient. Unfortunately, since the issue
is deeply nested within another function’s namespace, we can’t just write a new
&lt;code&gt;format.object_size&lt;/code&gt; and call &lt;code&gt;print.data.frame&lt;/code&gt; and expect it to work (without
rebuilding R itself – learning how to do that is on my TODO list). What we can do,
though, is to write a &lt;code&gt;format.object_size3&lt;/code&gt;, class our new column as &lt;code&gt;object_size3&lt;/code&gt;, and
test &lt;em&gt;that&lt;/em&gt;. With this new function written, we get&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;format.object_size3 &amp;lt;- function(x, units = &amp;quot;b&amp;quot;, standard = &amp;quot;auto&amp;quot;, digits = 1L, ...)
{
  known_bases &amp;lt;- c(legacy = 1024, IEC = 1024, SI = 1000)
  known_units &amp;lt;- list(
    SI     = c(&amp;quot;B&amp;quot;, &amp;quot;kB&amp;quot;,  &amp;quot;MB&amp;quot;,  &amp;quot;GB&amp;quot;, &amp;quot;TB&amp;quot;, &amp;quot;PB&amp;quot;,  &amp;quot;EB&amp;quot;,  &amp;quot;ZB&amp;quot;,  &amp;quot;YB&amp;quot;),
    IEC    = c(&amp;quot;B&amp;quot;, &amp;quot;KiB&amp;quot;, &amp;quot;MiB&amp;quot;, &amp;quot;GiB&amp;quot;,&amp;quot;TiB&amp;quot;,&amp;quot;PiB&amp;quot;, &amp;quot;EiB&amp;quot;, &amp;quot;ZiB&amp;quot;, &amp;quot;YiB&amp;quot;),
    legacy = c(&amp;quot;b&amp;quot;, &amp;quot;Kb&amp;quot;,  &amp;quot;Mb&amp;quot;,  &amp;quot;Gb&amp;quot;, &amp;quot;Tb&amp;quot;, &amp;quot;Pb&amp;quot;),
    LEGACY = c(&amp;quot;B&amp;quot;, &amp;quot;KB&amp;quot;,  &amp;quot;MB&amp;quot;,  &amp;quot;GB&amp;quot;, &amp;quot;TB&amp;quot;, &amp;quot;PB&amp;quot;) # &amp;lt;- only for &amp;quot;KB&amp;quot;
  )
  
  units &amp;lt;- match.arg(units,
                     c(&amp;quot;auto&amp;quot;, unique(unlist(known_units), use.names = FALSE)))
  standard &amp;lt;- match.arg(standard, c(&amp;quot;auto&amp;quot;, names(known_bases)))
  digits &amp;lt;- ifelse(is.null(digits), 1L, digits) # added
  
  if (standard == &amp;quot;auto&amp;quot;) { ## infer &amp;#39;standard&amp;#39; from &amp;#39;units&amp;#39;:
    standard &amp;lt;- &amp;quot;legacy&amp;quot; # default; may become &amp;quot;SI&amp;quot;
    if (units != &amp;quot;auto&amp;quot;) {
      if (endsWith(units, &amp;quot;iB&amp;quot;))
        standard &amp;lt;- &amp;quot;IEC&amp;quot;
      else if (endsWith(units, &amp;quot;b&amp;quot;))
        standard &amp;lt;- &amp;quot;legacy&amp;quot;   ## keep when &amp;quot;SI&amp;quot; is the default
      else if (units == &amp;quot;kB&amp;quot;)
        ## SPECIAL: Drop when &amp;quot;SI&amp;quot; becomes the default
        stop(&amp;quot;For SI units, specify &amp;#39;standard = \&amp;quot;SI\&amp;quot;&amp;#39;&amp;quot;)
    }
  }
  base      &amp;lt;- known_bases[[standard]]
  units_map &amp;lt;- known_units[[standard]]
  
  if (units == &amp;quot;auto&amp;quot;) {
    power &amp;lt;- if (x &amp;lt;= 0) 0L else min(as.integer(log(x, base = base)),
                                     length(units_map) - 1L)
  } else {
    power &amp;lt;- match(toupper(units), toupper(units_map)) - 1L
    if (is.na(power))
      stop(gettextf(&amp;quot;Unit \&amp;quot;%s\&amp;quot; is not part of standard \&amp;quot;%s\&amp;quot;&amp;quot;,
                    sQuote(units), sQuote(standard)), domain = NA)
  }
  unit &amp;lt;- units_map[power + 1L]
  ## SPECIAL: Use suffix &amp;#39;bytes&amp;#39; instead of &amp;#39;b&amp;#39; for &amp;#39;legacy&amp;#39; (or always) ?
  if (power == 0 &amp;amp;&amp;amp; standard == &amp;quot;legacy&amp;quot;) unit &amp;lt;- &amp;quot;bytes&amp;quot;
  
  paste(round(x / base^power, digits=digits), unit)
}

file.info3 &amp;lt;- function(..., extra_cols = TRUE)
{
    res &amp;lt;- .Internal(file.info(fn &amp;lt;- c(...), extra_cols))
    class(res$size) &amp;lt;- &amp;quot;object_size3&amp;quot;
    res$mtime &amp;lt;- .POSIXct(res$mtime)
    res$ctime &amp;lt;- .POSIXct(res$ctime)
    res$atime &amp;lt;- .POSIXct(res$atime)
    class(res) &amp;lt;- &amp;quot;data.frame&amp;quot;
    attr(res, &amp;quot;row.names&amp;quot;) &amp;lt;- fn # not row.names&amp;lt;- as that does a length check
    res
}

file.info3(example_file)[, c(&amp;quot;size&amp;quot;, &amp;quot;isdir&amp;quot;, &amp;quot;mode&amp;quot;)]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##                                            size isdir mode
## /usr/lib/R/library/base/R/base.rdb 973156 bytes FALSE  644&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works!&lt;/p&gt;
&lt;p&gt;As of R 3.2.0 there are also some helper extractors of these elements (mode, mtime, size)
so our improvement extends to &lt;code&gt;file.size&lt;/code&gt;. We can test this if we update the helper to
use our version&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;file.size3 &amp;lt;- function(...) file.info3(..., extra_cols = FALSE)$size
file.size3(example_file)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 973156
## attr(,&amp;quot;class&amp;quot;)
## [1] &amp;quot;object_size3&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can format that specifically&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;format(file.size3(example_file), &amp;quot;KB&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;950.3 Kb&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but it doesn’t print nicely on its own here. This is because we’ve artificially changed
the class to &lt;code&gt;object_size3&lt;/code&gt; so we’re no longer plugging in to all the methods for &lt;code&gt;object_size&lt;/code&gt;. I
could go through and redefine all of those, but for testing, it’s easier to just reset everything
to &lt;code&gt;object_size&lt;/code&gt;, define &lt;code&gt;file.size&lt;/code&gt; to use my custom version, and test that, and that works.&lt;/p&gt;
&lt;p&gt;I’ve seen others create a package containing the modified code so that all of the namespacing
works out, but in this case it would be a large chunk of the print, subset, and format methods.&lt;/p&gt;
&lt;p&gt;Are we done? What about another look at that &lt;code&gt;class(res) &amp;lt;- &amp;quot;data.frame&amp;quot;&lt;/code&gt; business?&lt;/p&gt;
&lt;p&gt;Would it make more sense for that to use &lt;code&gt;res &amp;lt;- as.data.frame(res)&lt;/code&gt;? Let’s try&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;file.info4 &amp;lt;- function(..., extra_cols = TRUE)
{
    res &amp;lt;- .Internal(file.info(fn &amp;lt;- c(...), extra_cols))
    class(res$size) &amp;lt;- &amp;quot;object_size3&amp;quot;
    res$mtime &amp;lt;- .POSIXct(res$mtime)
    res$ctime &amp;lt;- .POSIXct(res$ctime)
    res$atime &amp;lt;- .POSIXct(res$atime)
    res &amp;lt;- as.data.frame(res)
    attr(res, &amp;quot;row.names&amp;quot;) &amp;lt;- fn # not row.names&amp;lt;- as that does a length check
    res
}

file.info4(example_file)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in as.data.frame.default(x[[i]], optional = TRUE): cannot coerce class &amp;#39;&amp;quot;object_size3&amp;quot;&amp;#39; to a data.frame&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fair enough, there’s probably no &lt;code&gt;as.data.frame.object_size3&lt;/code&gt; method (the 3 is for our convenience, but
there’s no &lt;code&gt;as.data.frame.object_size&lt;/code&gt; either). It’s simple enough to add&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as.data.frame.object_size3 &amp;lt;- as.data.frame.vector

file.info4(example_file)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in as.data.frame.default(x[[i]], optional = TRUE): cannot coerce class &amp;#39;&amp;quot;octmode&amp;quot;&amp;#39; to a data.frame&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The “mode” element has the file permissions as &lt;code&gt;octmode&lt;/code&gt;. I feel we’re getting a bit
off track if we need to add a lot of other &lt;code&gt;as.data.frame&lt;/code&gt; methods, but
here we go&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as.data.frame.octmode &amp;lt;- as.data.frame.vector

file.info4(example_file)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##                                            size isdir mode
## /usr/lib/R/library/base/R/base.rdb 973156 bytes FALSE  644
##                                                  mtime               ctime
## /usr/lib/R/library/base/R/base.rdb 2019-01-15 06:33:43 2019-08-10 20:44:16
##                                                  atime uid gid uname
## /usr/lib/R/library/base/R/base.rdb 2019-08-10 20:44:13   0   0  root
##                                    grname
## /usr/lib/R/library/base/R/base.rdb   root&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Right, that’s working. I’ll raise the question of whether or not it’s worth the
effort to support the &lt;code&gt;as.data.frame&lt;/code&gt; conversion or whether the forcing of the class is
better - I’m honestly not sure which.&lt;/p&gt;
&lt;p&gt;I wrote a &lt;a href=&#34;https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17628&#34;&gt;bug report and corresponding patch&lt;/a&gt; that adds the new test for &lt;code&gt;NULL&lt;/code&gt; line to the definition of
&lt;code&gt;format.object_size&lt;/code&gt; and submitted that.&lt;/p&gt;
&lt;p&gt;I then wrote &lt;a href=&#34;https://bugs.r-project.org/bugzilla/attachment.cgi?id=2470&amp;amp;action=diff&#34;&gt;another patch&lt;/a&gt; to &lt;a href=&#34;https://bugs.r-project.org/bugzilla/show_bug.cgi?id=15389&#34;&gt;the bug report this started with&lt;/a&gt; which
implements this (now minor) change to the size element of &lt;code&gt;file.info&lt;/code&gt;. It may be the
case that neither is welcome in the core source, and that’s fine. The bug can be closed
as WONTFIX.&lt;/p&gt;
&lt;p&gt;I’ve learned a lot about how the components of these work, and either way a bug
should get closed. I’m off to find the next one.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;Addendum&lt;/em&gt;: I wanted to test this out properly, so I rebuilt my modified version of R
(with these two patches in place) from source using docker. Assuming you have docker set up, this seems to do the trick&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;## pull the r-base docker image
## this has most of the requirements to build R
docker pull r-base

## run the image with a command-line
## with your local svn repository mounted
## your path to your svn directory will vary
docker run -ti -v /home/USER/svn/:/svn/ r-base /bin/bash 

## update whatever is necessary to build R from the svn source
apt update
apt-get install libcurl4-openssl-dev 
apt-get install texinfo ## needed to build manuals
apt-get install texlive-latex-base ## needed to build vignettes
apt-get install texlive-latex-extra ## sty files
apt-get install subversion ## to work with svn

## ensure svn is up to date
cd /svn/r-devel/
svn update

## build R and check that it works
## we&amp;#39;re just using the command line, so X11 is not needed
## we&amp;#39;re just building the source, so we don&amp;#39;t need e.g. MASS
## we don&amp;#39;t need to be using java, so don&amp;#39;t include that
./configure --with-x=no --without-recommended-packages --disable-byte-compiled-packages --disable-java
## make in parallel
make -j4
make check
make check-all
make install

bin/R
## R Under development (unstable) (2019-10-10 r77275) -- &amp;quot;Unsuffered Consequences&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Woohoo!&lt;/p&gt;
&lt;p&gt;Note that this is ephemeral - the changes won’t persist after you stop the image. To prevent
that, we can save the image for re-use (from outside the image)&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;## your image ID will be different
docker commit -m &amp;quot;build env&amp;quot; 8f42f23123dd r-build-env&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that built, we can try out our patched functions (not run locally here)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;example_file &amp;lt;- file.path(.Library, &amp;quot;base&amp;quot;, &amp;quot;R&amp;quot;, &amp;quot;base.rdb&amp;quot;)
file.info(example_file)[, c(&amp;quot;size&amp;quot;, &amp;quot;isdir&amp;quot;, &amp;quot;mode&amp;quot;)]
#&amp;gt;                                              size isdir mode
#&amp;gt; /svn/r-devel/library/base/R/base.rdb 357435 bytes FALSE  644

file.size(example_file)
#&amp;gt; 357435 bytes

format(file.size(example_file), &amp;quot;KB&amp;quot;)
#&amp;gt; [1] &amp;quot;349.1 Kb&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Success!&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-10-12                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.2.1   2019-09-24 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  ellipsis      0.3.0   2019-09-20 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  knitr         1.25    2019-09-18 [1] CRAN (R 3.5.2)                   
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>{ggtext} for images as x-axis labels</title>
      <link>https://jcarroll.com.au/2019/08/13/ggtext-for-images-as-x-axis-labels/</link>
      <pubDate>Tue, 13 Aug 2019 00:00:00 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2019/08/13/ggtext-for-images-as-x-axis-labels/</guid>
      <description>&lt;p&gt;I’ve written &lt;a href=&#34;https://jcarroll.com.au/2016/06/02/images-as-x-axis-labels/&#34;&gt;a&lt;/a&gt;
&lt;a href=&#34;https://jcarroll.com.au/2016/06/03/images-as-x-axis-labels-updated/&#34;&gt;few&lt;/a&gt;
&lt;a href=&#34;https://jcarroll.com.au/2018/10/16/even-more-images-as-x-axis-labels/&#34;&gt;times&lt;/a&gt;
about using an image as an x-axis label, and the solutions have been slowly
improving. This one blows all of them out of the water.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/clauswilke&#34;&gt;Claus Wilke&lt;/a&gt; (&lt;a href=&#34;https://twitter.com/ClausWilke&#34;&gt;@ClausWilke&lt;/a&gt;)
now has a &lt;a href=&#34;https://github.com/clauswilke/ggtext&#34;&gt;{ggtext}&lt;/a&gt; package which can very
neatly add images as x-axis labels!&lt;/p&gt;
&lt;p&gt;This makes the solution as simple as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)
library(ggtext)
library(rvest)

## GDP per capita, top 11 countries
url      &amp;lt;- &amp;quot;https://en.wikipedia.org/wiki/List_of_countries_by_GDP_(nominal)_per_capita&amp;quot;
html     &amp;lt;- xml2::read_html(url)
gdppc    &amp;lt;- html_table(html_nodes(html, &amp;quot;table&amp;quot;)[3])[[1]][1:11,]

## clean up; remove non-ASCII and perform type conversions
gdppc$Country &amp;lt;- gsub(&amp;quot;Â &amp;quot;, &amp;quot;&amp;quot;, gdppc$Country)
gdppc$Country &amp;lt;- iconv(gdppc$Country, &amp;quot;latin1&amp;quot;, &amp;quot;ASCII&amp;quot;, sub=&amp;quot;&amp;quot;)
gdppc$Country[9] &amp;lt;- &amp;quot;United States of America&amp;quot;
gdppc$Rank    &amp;lt;- iconv(gdppc$Rank,    &amp;quot;latin1&amp;quot;, &amp;quot;ASCII&amp;quot;, sub=&amp;quot;&amp;quot;)
gdppc$`US$`   &amp;lt;- as.integer(sub(&amp;quot;,&amp;quot;, &amp;quot;&amp;quot;, gdppc$`US$`))

## switching to a different source of flag images
labels &amp;lt;- setNames(
  paste0(&amp;quot;&amp;lt;img src=&amp;#39;http://www.senojflags.com/images/country-flag-icons/&amp;quot;, 
         gsub(&amp;quot; &amp;quot;, &amp;quot;-&amp;quot;, gdppc$Country), &amp;quot;-Flag.png&amp;#39;  width=&amp;#39;30&amp;#39; /&amp;gt;&amp;lt;br&amp;gt;&amp;quot;, 
         sapply(strwrap(gdppc$Country, width = 10, simplify = FALSE), 
                function(x) paste(x, collapse = &amp;quot;&amp;lt;br&amp;gt;&amp;quot;))),
  gdppc$Country
)

## create a dummy dataset
npoints &amp;lt;- length(gdppc$Country)
y       &amp;lt;- gdppc$`US$`
x       &amp;lt;- gdppc$Country
dat     &amp;lt;- data.frame(x=factor(x, levels=gdppc$Country), y=y)

## NB: #85bb65 is the color of money in the USA apparently.
gg &amp;lt;- ggplot(dat, aes(x=x, y=y/1e3L, group=1)) 
gg &amp;lt;- gg + geom_bar(col=&amp;quot;black&amp;quot;, fill=&amp;quot;#85bb65&amp;quot;, stat=&amp;quot;identity&amp;quot;)
gg &amp;lt;- gg + scale_x_discrete(name = NULL, labels = labels)
gg &amp;lt;- gg + theme_minimal()
gg &amp;lt;- gg + scale_fill_discrete(guide=FALSE)
gg &amp;lt;- gg + theme(plot.background = element_rect(fill=&amp;quot;grey90&amp;quot;))
gg &amp;lt;- gg + labs(title=&amp;quot;GDP per capita&amp;quot;, 
                subtitle=&amp;quot;Top 11 countries&amp;quot;, 
                x=&amp;quot;&amp;quot;, y=&amp;quot;$US/1000&amp;quot;, 
                caption=paste0(&amp;quot;Source: &amp;quot;,url))
## ggtext::element_markdown
gg &amp;lt;- gg + theme(axis.text.x  = element_markdown(color = &amp;quot;black&amp;quot;, size = 7), 
                 axis.text.y  = element_text(size=14),
                 axis.title.x = element_blank())
gg&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;figure&#34;&gt;&lt;span id=&#34;fig:unnamed-chunk-1&#34;&gt;&lt;/span&gt;
&lt;img src=&#34;https://jcarroll.com.au/post/2019-08-13-ggtext-for-images-as-x-axis/index.en_files/figure-html/unnamed-chunk-1-1.png&#34; alt=&#34;{ggtext} makes this easy!&#34; width=&#34;672&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;
Figure 1: {ggtext} makes this easy!
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This is an even nicer solution than I’ve been using, not only because it’s shorter
to use, but also more flexible - markdown can be processed (using &lt;code&gt;element_markdown&lt;/code&gt;)
wherever &lt;code&gt;element_text&lt;/code&gt; is used, such as axis text, legends, titles, etc…&lt;/p&gt;
&lt;p&gt;I think this finally closes this chapter, but now it’s time to make some really cool
graphs with images.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version   date       lib
##  assertthat    0.2.1     2019-03-21 [1]
##  backports     1.1.4     2019-04-10 [1]
##  bitops        1.0-6     2013-08-17 [1]
##  blogdown      0.14.1    2019-08-11 [1]
##  bookdown      0.12      2019-07-11 [1]
##  callr         3.3.1     2019-07-18 [1]
##  cli           1.1.0     2019-03-19 [1]
##  colorspace    1.4-1     2019-03-18 [1]
##  crayon        1.3.4     2017-09-16 [1]
##  curl          4.0       2019-07-22 [1]
##  desc          1.2.0     2018-05-01 [1]
##  devtools      2.1.0     2019-07-06 [1]
##  digest        0.6.20    2019-07-04 [1]
##  dplyr         0.8.3     2019-07-04 [1]
##  evaluate      0.14      2019-05-28 [1]
##  fs            1.3.1     2019-05-06 [1]
##  ggplot2     * 3.2.1     2019-08-10 [1]
##  ggtext      * 0.1.0     2019-08-13 [1]
##  glue          1.3.1     2019-03-12 [1]
##  gridtext      0.1.0     2019-08-13 [1]
##  gtable        0.3.0     2019-03-25 [1]
##  highr         0.8       2019-03-20 [1]
##  htmltools     0.3.6     2017-04-28 [1]
##  httr          1.4.1     2019-08-05 [1]
##  knitr         1.24      2019-08-08 [1]
##  labeling      0.3       2014-08-23 [1]
##  lazyeval      0.2.2     2019-03-15 [1]
##  magrittr      1.5       2014-11-22 [1]
##  markdown      1.1       2019-08-07 [1]
##  memoise       1.1.0     2017-04-21 [1]
##  munsell       0.5.0     2018-06-12 [1]
##  pillar        1.4.2     2019-06-29 [1]
##  pkgbuild      1.0.4     2019-08-05 [1]
##  pkgconfig     2.0.2     2018-08-16 [1]
##  pkgload       1.0.2     2018-10-29 [1]
##  png           0.1-7     2013-12-03 [1]
##  prettyunits   1.0.2     2015-07-13 [1]
##  processx      3.4.1     2019-07-18 [1]
##  ps            1.3.0     2018-12-21 [1]
##  purrr         0.3.2     2019-03-15 [1]
##  R6            2.4.0     2019-02-14 [1]
##  Rcpp          1.0.2     2019-07-25 [1]
##  RCurl         1.95-4.12 2019-03-04 [1]
##  remotes       2.1.0     2019-06-24 [1]
##  rlang         0.4.0     2019-06-25 [1]
##  rmarkdown     1.14      2019-07-12 [1]
##  rprojroot     1.3-2     2018-01-03 [1]
##  rvest       * 0.3.4     2019-05-15 [1]
##  scales        1.0.0     2018-08-09 [1]
##  selectr       0.4-1     2018-04-06 [1]
##  sessioninfo   1.1.1     2018-11-05 [1]
##  stringi       1.4.3     2019-03-12 [1]
##  stringr       1.4.0     2019-02-10 [1]
##  testthat      2.2.1     2019-07-25 [1]
##  tibble        2.1.3     2019-06-06 [1]
##  tidyselect    0.2.5     2018-10-11 [1]
##  usethis       1.5.1     2019-07-04 [1]
##  withr         2.1.2     2018-03-15 [1]
##  xfun          0.8       2019-06-25 [1]
##  xml2        * 1.2.2     2019-08-09 [1]
##  yaml          2.2.0     2018-07-25 [1]
##  source                              
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  Github (rstudio/blogdown@be4e91c)   
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  Github (clauswilke/ggtext@5c7cfa9)  
##  CRAN (R 3.5.2)                      
##  Github (clauswilke/gridtext@21b7198)
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.2)                      
##  CRAN (R 3.5.1)                      
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>forcats::fct_match</title>
      <link>https://jcarroll.com.au/2019/02/22/forcatsfct_match/</link>
      <pubDate>Fri, 22 Feb 2019 23:57:25 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2019/02/22/forcatsfct_match/</guid>
      <description>&lt;p&gt;This journey started almost exactly a year ago, but it’s finally been sufficiently worked through and merged! Yay, I’ve officially contributed to the &lt;a href=&#34;https://www.tidyverse.org/&#34;&gt;tidyverse&lt;/a&gt; (minor as it may be).&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://jcarroll.com.au/post/2019-02-22-forcatsfct_match_files/zoidberg_helping.jpeg&#34; alt=&#34;I’m at least as useful as Zoidberg&#34; width=&#34;300&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;I’m at least as useful as Zoidberg&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;It began with &lt;a href=&#34;https://twitter.com/carroll_jono/status/971093803099541504&#34;&gt;a tweet&lt;/a&gt;, recalling a surprise I encountered that day during some routine data processing&lt;/p&gt;
&lt;blockquote class=&#34;twitter-tweet&#34;&gt;
&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;
Source of today&#39;s mild heart-attack: I have categories W, X_Y, and Z in some data. Intending to keep only the second two:&lt;br&gt;&lt;br&gt;data %&amp;gt;% filter(g %in% c(“X Y”, “Z”)&lt;br&gt;&lt;br&gt;Did you spot that I used a space instead of an underscore? I sure as heck didn&#39;t, and filtered excessively to just Z.
&lt;/p&gt;
— Jonathan Carroll (&lt;span class=&#34;citation&#34;&gt;@carroll_jono&lt;/span&gt;) &lt;a href=&#34;https://twitter.com/carroll_jono/status/971093803099541504?ref_src=twsrc%5Etfw&#34;&gt;March 6, 2018&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
&lt;p&gt;For those of you not so comfortable with pipes and &lt;code&gt;dplyr&lt;/code&gt;, I was trying to subset a &lt;code&gt;data.frame&lt;/code&gt; ‘&lt;code&gt;data&lt;/code&gt;’ (with a column &lt;code&gt;g&lt;/code&gt; having values &lt;code&gt;&amp;quot;W&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;X_Y&amp;quot;&lt;/code&gt; and &lt;code&gt;&amp;quot;Z&amp;quot;&lt;/code&gt;) to only those rows for which the column &lt;code&gt;g&lt;/code&gt; had the value &lt;code&gt;&amp;quot;X_Y&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;Z&amp;quot;&lt;/code&gt; (not the actual values, of course, but that’s the idea). Without &lt;code&gt;dplyr&lt;/code&gt; this might simply be&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;data[data$g %in% c(&amp;quot;X Y&amp;quot;, &amp;quot;Z&amp;quot;), ]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To make that more concrete, let’s actually show it in action&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;data &amp;lt;- data.frame(a = 1:5, g = c(&amp;quot;X_Y&amp;quot;, &amp;quot;W&amp;quot;, &amp;quot;Z&amp;quot;, &amp;quot;Z&amp;quot;, &amp;quot;W&amp;quot;))
data&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   a   g
## 1 1 X_Y
## 2 2   W
## 3 3   Z
## 4 4   Z
## 5 5   W&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;data %&amp;gt;% 
   filter(g %in% c(&amp;quot;X Y&amp;quot;, &amp;quot;Z&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   a g
## 1 3 Z
## 2 4 Z&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;filter&lt;/code&gt; isn’t at fault here – the same issue would arise with &lt;code&gt;[&lt;/code&gt; – I have mis-specified the values I wish to match, so I am returned only the matching values. &lt;code&gt;%in%&lt;/code&gt; is also performing its job - it returns a logical vector; the result of comparing the values in the column &lt;code&gt;g&lt;/code&gt; to the vector &lt;code&gt;c(&amp;quot;X Y&amp;quot;, &amp;quot;Z&amp;quot;)&lt;/code&gt;. Both of these functions are behaving as they should, but the logic of what I was trying to achieve (subset to only these values) was lost.&lt;/p&gt;
&lt;p&gt;Now, in some instances, that is exactly the behaviour you want – subset this vector to &lt;em&gt;any&lt;/em&gt; of these values… where those values may not be present in the vector to begin with&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;data %&amp;gt;% 
   filter(values %in% all_known_values)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem, for me, is that there isn’t a way to say “all of these should be there”. The lack of matching happens silently. If you make a typo, you don’t get that level, and you aren’t told that it’s been skipped&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;simpsons_characters %&amp;gt;% 
   filter(first_name %in% c(&amp;quot;Homer&amp;quot;, &amp;quot;Marge&amp;quot;, &amp;quot;Bert&amp;quot;, &amp;quot;Lisa&amp;quot;, &amp;quot;Maggie&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Technically this is a double-post because I also want to sidenote this with something I am amazed I have not known about yet (I was approximately today years old when I learned about this)… I’ve used &lt;code&gt;regex&lt;/code&gt;matching for a while, and have been surprised at &lt;a href=&#34;https://twitter.com/carroll_jono/status/908186714350403584&#34;&gt;how well I’ve been able to make it work&lt;/a&gt; occasionally. I’m familiar with counting patterns (&lt;code&gt;(A){2}&lt;/code&gt; to match two occurrences of &lt;code&gt;A&lt;/code&gt;) and ranges of counts (&lt;code&gt;(A){2,4}&lt;/code&gt; Sto match between two and four occurrences of &lt;code&gt;A&lt;/code&gt;) but I was not aware that you can specify a number of &lt;strong&gt;mistakes&lt;/strong&gt; that can be included to still make a match…;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;grep(&amp;quot;Bart&amp;quot;, c(&amp;quot;Bart&amp;quot;, &amp;quot;Bort&amp;quot;, &amp;quot;Brat&amp;quot;), value = TRUE)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;Bart&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;grep(&amp;quot;(Bart){~1}&amp;quot;, c(&amp;quot;Bart&amp;quot;, &amp;quot;Bort&amp;quot;, &amp;quot;Brat&amp;quot;), value = TRUE)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;Bart&amp;quot; &amp;quot;Bort&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(“Are you matching to me?”… “No, my regex &lt;em&gt;also&lt;/em&gt; matches to ‘Bort’”)&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;(pattern){~n}&lt;/code&gt;to allow up to &lt;code&gt;n&lt;/code&gt;substitutions in the pattern matching. Refer &lt;a href=&#34;https://twitter.com/klmr/status/1098238987968438273?s=20&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;https://laurikari.net/tre/documentation/regex-syntax/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Back to the original problem – &lt;code&gt;filter&lt;/code&gt;and &lt;code&gt;%in%&lt;/code&gt;are doing their jobs, but we aren’t getting the result we want because we made a typo, and we aren’t told that we’ve done so.&lt;/p&gt;
&lt;p&gt;Enter a &lt;a href=&#34;https://github.com/tidyverse/forcats/pull/127&#34;&gt;new PR&lt;/a&gt; to &lt;code&gt;forcats&lt;/code&gt; (originally to &lt;code&gt;dplyr&lt;/code&gt;, but &lt;code&gt;forcats&lt;/code&gt; does make more sense) which implements &lt;code&gt;fct_match(f, lvls)&lt;/code&gt;. This checks that all of the values in &lt;code&gt;lvls&lt;/code&gt; are actually present in &lt;code&gt;f&lt;/code&gt; before returning the logical vector of which entries they correspond to. With this, the pattern becomes (after loading the development version of &lt;code&gt;forcats&lt;/code&gt; from &lt;a href=&#34;https://github.com/tidyverse/forcats&#34;&gt;github&lt;/a&gt;)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;data %&amp;gt;% 
   filter(fct_match(g, c(&amp;quot;X Y&amp;quot;, &amp;quot;Z&amp;quot;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error: Levels not present in factor: &amp;quot;X Y&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yay! We’re notified that we’ve made an error. &lt;code&gt;&amp;quot;X Y&amp;quot;&lt;/code&gt; isn’t actually in our column &lt;code&gt;g&lt;/code&gt;. If we don’t make the error, we get the result we actually wanted in the first place. We can now use this successfully&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;data %&amp;gt;% 
   filter(fct_match(g, c(&amp;quot;X_Y&amp;quot;, &amp;quot;Z&amp;quot;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   a   g
## 1 1 X_Y
## 2 3   Z
## 3 4   Z&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It took a while for the PR to be addressed (the tidyverse crew have plenty of backlog, no doubt) but after some minor requested changes and a very neat cleanup by Hadley himself, it’s been merged.&lt;/p&gt;
&lt;p&gt;My original version had a few bells and whistles that the current implementation has put aside. The first was inverting the matching with &lt;code&gt;fct_exclude&lt;/code&gt; to make it easier to negate the matching without having to create a new anonymous function, i.e. &lt;code&gt;~!fct_match(.x)&lt;/code&gt;. I find this particularly useful since a pipe expects a call/named function, not a lambda/anonymous function, which is actually quite painful to construct&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;data %&amp;gt;%
   pull(g) %&amp;gt;%
   (function(x) !fct_match(x, c(&amp;quot;X_Y&amp;quot;, &amp;quot;Z&amp;quot;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE  TRUE FALSE FALSE  TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;whereas if we defined&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fct_exclude &amp;lt;- function(f, lvls, ...) !fct_match(f, lvls, ...)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;we can use&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;data %&amp;gt;%
   pull(g) %&amp;gt;%
   fct_exclude(c(&amp;quot;X_Y&amp;quot;, &amp;quot;Z&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE  TRUE FALSE FALSE  TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The other was specifying whether or not to include missing levels when considering if &lt;code&gt;lvls&lt;/code&gt; is a valid value in &lt;code&gt;f&lt;/code&gt; since &lt;code&gt;unique(f)&lt;/code&gt; and &lt;code&gt;levels(f)&lt;/code&gt; can return different answers.&lt;/p&gt;
&lt;p&gt;The cleanup really made me think about how much ‘fluff’ some of my code can have. Sure, it’s nice to encapsulate some logic in a small additional function, but sometimes you can actually replace all of that with a one-liner and not need all that. If you’re ever in the mood to see how compact internal code can really be, check out the source of &lt;code&gt;forcats&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Hopefully this pattern of &lt;code&gt;filter(fct_match(f, lvls))&lt;/code&gt; is useful to others. It’s certainly going to save me overlooking some typos.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.1.0   2019-07-06 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  dplyr       * 0.8.3   2019-07-04 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  forcats     * 0.4.0   2019-02-17 [1] CRAN (R 3.5.1)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  knitr         1.24    2019-08-08 [1] CRAN (R 3.5.2)                   
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  pillar        1.4.2   2019-06-29 [1] CRAN (R 3.5.2)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgconfig     2.0.2   2018-08-16 [1] CRAN (R 3.5.1)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  purrr         0.3.2   2019-03-15 [1] CRAN (R 3.5.2)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  tibble        2.1.3   2019-06-06 [1] CRAN (R 3.5.2)                   
##  tidyselect    0.2.5   2018-10-11 [1] CRAN (R 3.5.1)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Even more images as x-axis labels</title>
      <link>https://jcarroll.com.au/2018/10/16/even-more-images-as-x-axis-labels/</link>
      <pubDate>Tue, 16 Oct 2018 23:18:32 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2018/10/16/even-more-images-as-x-axis-labels/</guid>
      <description>&lt;/p&gt;
&lt;p&gt;This is the last update to this strange saga… I hope.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://jcarroll.com.au/post/2018-10-16-even-more-images-as-x-axis-labels_files/labels.jpg&#34; alt=&#34;Image labels… Photo: http://www.premierpaper.com/shop/custom-labels/&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;Image labels… Photo: &lt;a href=&#34;http://www.premierpaper.com/shop/custom-labels/&#34; class=&#34;uri&#34;&gt;http://www.premierpaper.com/shop/custom-labels/&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Easily two of the most popular posts on my blog are &lt;a href=&#34;https://jonocarroll.com.au/2016-06-02-images-as-x-axis-labels.html%22&#34;&gt;this one&lt;/a&gt; and &lt;a href=&#34;https://jonocarroll.com.au/2016-06-03-images-as-x-axis-labels-updated.html%22&#34;&gt;this one&lt;/a&gt; describing a couple of ways in which I managed to hack together using an image as a category label in a ggplot.&lt;/p&gt;
&lt;p&gt;There are likely many people who believe one should &lt;em&gt;never&lt;/em&gt; do such a thing, but given the popularity, it seems a lot of people aren’t listening to that. Good on you.&lt;/p&gt;
&lt;div style=&#34;width:100%;height:0;padding-bottom:54%;position:relative;&#34;&gt;
&lt;iframe src=&#34;https://giphy.com/embed/bqalUGFYfyHzW&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;position:absolute&#34; frameBorder=&#34;0&#34; class=&#34;giphy-embed&#34; allowFullScreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;a href=&#34;https://giphy.com/gifs/good-hang-breastfeeding-bqalUGFYfyHzW&#34;&gt;via GIPHY&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;One of these posts was recently shared again by the amazing &lt;a href=&#34;https://twitter.com/dataandme%22&#34;&gt;#rstats amplifier Mara Averick&lt;/a&gt; (if you’re not following her on Twitter, you’re missing out) and &lt;span class=&#34;citation&#34;&gt;[@baptiste_auguie]&lt;/span&gt;(&lt;a href=&#34;https://twitter.com/baptiste_auguie&#34; class=&#34;uri&#34;&gt;https://twitter.com/baptiste_auguie&lt;/a&gt;&amp;quot;) (the saviour of the previous implementation) mentioned that he had written a ‘hack’ to get chemical symbols as a categorical axis label using &lt;code&gt;tikzDevice&lt;/code&gt;. That package leverages &lt;span class=&#34;math inline&#34;&gt;\(\LaTeX\)&lt;/span&gt; (of which I am &lt;em&gt;very&lt;/em&gt; familiar, having written my PhD thesis entirely in &lt;span class=&#34;math inline&#34;&gt;\(\LaTeX\)&lt;/span&gt; many moons ago) to treat all of the text in an image as potential &lt;span class=&#34;math inline&#34;&gt;\(\LaTeX\)&lt;/span&gt; commands and produce a working source code which generates the required plot.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://groups.google.com/forum/#!topic/ggplot2/OPhpWtVcwtY&#34;&gt;example code&lt;/a&gt; is straightforward enough&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;options(tikzLatexPackages = c(getOption(&amp;#39;tikzLatexPackages&amp;#39;),
                              &amp;quot;\\usepackage{acide-amine}\n&amp;quot;)) 

d = data.frame(x=1:10, y=1:10, f=factor(sample(letters[1:2], 10, repl=TRUE))) 

p &amp;lt;- qplot(x,y,data=d) + theme_bw() + 
  theme(plot.margin = unit(c(1, 1, 5, 1), &amp;quot;lines&amp;quot;), 
       axis.text.x = element_text(size = 12 * 
        0.8, lineheight = 0.9, vjust = 10)) + 
  scale_x_continuous(breaks = c(2, 8), labels=c(&amp;quot;\\phe{15}&amp;quot;, &amp;quot;\\leu{15}&amp;quot;)) 

tikz(&amp;quot;annotation.tex&amp;quot;, standAlone=T, width=4, height=4) 
print(p) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and produces this&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2018-10-16-even-more-images-as-x-axis-labels_files/annotation.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;This got me curious, though – if it can process &lt;em&gt;arbitrary&lt;/em&gt; &lt;span class=&#34;math inline&#34;&gt;\(\LaTeX\)&lt;/span&gt;, could it process a &lt;code&gt;\\includegraphics&lt;/code&gt; call?&lt;/p&gt;
&lt;blockquote class=&#34;twitter-tweet&#34;&gt;
&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;
Efficient! If it&#39;s arbitrary LaTeX, could the labels just be \includegraphics calls?
&lt;/p&gt;
— Jonathan Carroll (&lt;span class=&#34;citation&#34;&gt;@carroll_jono&lt;/span&gt;) &lt;a href=&#34;https://twitter.com/carroll_jono/status/1050535371241476096?ref_src=twsrc%5Etfw&#34;&gt;October 11, 2018&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
&lt;p&gt;Yes, as it turns out.&lt;/p&gt;
&lt;div style=&#34;width:100%;height:0;padding-bottom:75%;position:relative;&#34;&gt;
&lt;iframe src=&#34;https://giphy.com/embed/XreQmk7ETCak0&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;position:absolute&#34; frameBorder=&#34;0&#34; class=&#34;giphy-embed&#34; allowFullScreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;a href=&#34;https://giphy.com/gifs/retro-thumbs-up-XreQmk7ETCak0&#34;&gt;via GIPHY&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;A quick test showed that it was indeed possible, which only leaves re-implementing the previous posts’ images using this method.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://gist.github.com/jonocarroll/08a1ccff36be628430d768e5b9426e54&#34;&gt;I’ve done so&lt;/a&gt;, and the code isn’t particularly shorter than the other method.&lt;/p&gt;
&lt;p&gt;{{% gist jonocarroll 08a1ccff36be628430d768e5b9426e54 %}}&lt;/p&gt;
&lt;p&gt;Producing nearly the same end result.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://jcarroll.com.au/post/2018-10-16-even-more-images-as-x-axis-labels_files/annotation.png&#34; alt=&#34;tikzDevice result&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;tikzDevice result&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;There are a few differences compared to the previous version(s):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I had a request for rotating the additional text, which I actually [also updated recently[(&lt;a href=&#34;https://gist.github.com/jonocarroll/2f9490f1f5e7c82ef8b791a4b91fc9ca#file-images_as_xaxis_labels_updated-r&#34; class=&#34;uri&#34;&gt;https://gist.github.com/jonocarroll/2f9490f1f5e7c82ef8b791a4b91fc9ca#file-images_as_xaxis_labels_updated-r&lt;/a&gt;), and it seemed to fit better, so I rotated the labels within the &lt;span class=&#34;math inline&#34;&gt;\(\LaTeX\)&lt;/span&gt; command.&lt;/li&gt;
&lt;li&gt;Since all of the text has been rendered via &lt;span class=&#34;math inline&#34;&gt;\(\LaTeX\)&lt;/span&gt;, the fonts are a bit different.&lt;/li&gt;
&lt;li&gt;The rankings have since changed, so I’ve added an 11th to keep Australia in the list.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;span class=&#34;math inline&#34;&gt;\(\LaTeX\)&lt;/span&gt; component of this also meant that a few changes were necessary in the other labels, such as the dollar sign in the y-axis label, and the underscores throughout (these are considered special characters in &lt;span class=&#34;math inline&#34;&gt;\(\LaTeX\)&lt;/span&gt;). Lastly, the result of running the &lt;code&gt;tikz&lt;/code&gt; command is that a &lt;code&gt;.tex&lt;/code&gt; (&lt;span class=&#34;math inline&#34;&gt;\(\LaTeX\)&lt;/span&gt; source code) file is produced. This isn’t quite the plot image file we want. It &lt;em&gt;does&lt;/em&gt; however have the commands to generate one. The last steps in the above gist are to process this &lt;code&gt;.tex&lt;/code&gt; file with &lt;span class=&#34;math inline&#34;&gt;\(\LaTeX\)&lt;/span&gt;. Here I used the &lt;code&gt;tools::texi2dvi&lt;/code&gt; function, but one &lt;em&gt;could&lt;/em&gt; also use a &lt;code&gt;system&lt;/code&gt; command to their &lt;span class=&#34;math inline&#34;&gt;\(\LaTeX\)&lt;/span&gt; installation.&lt;/p&gt;
&lt;p&gt;That still only produced a PDF. The last step was to use the &lt;code&gt;magick&lt;/code&gt; package to convert this into an image.&lt;/p&gt;
&lt;p&gt;Overall, this is a nice proof of concept, but I don’t think it’s a particularly tidy way of achieving the goal of image axis labels. It does however lay the groundwork for anyone else who decides this might be a useful route to take. Plus I learned a bit more about how &lt;code&gt;tikzDevice&lt;/code&gt; works and got to revisit my &lt;span class=&#34;math inline&#34;&gt;\(\LaTeX\)&lt;/span&gt; knowledge.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  colorspace    1.4-1   2019-03-18 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.1.0   2019-07-06 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  dplyr         0.8.3   2019-07-04 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  filehash      2.4-2   2019-04-17 [1] CRAN (R 3.5.2)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  ggplot2     * 3.2.1   2019-08-10 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  gtable        0.3.0   2019-03-25 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  knitr         1.24    2019-08-08 [1] CRAN (R 3.5.2)                   
##  lazyeval      0.2.2   2019-03-15 [1] CRAN (R 3.5.2)                   
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  munsell       0.5.0   2018-06-12 [1] CRAN (R 3.5.1)                   
##  pillar        1.4.2   2019-06-29 [1] CRAN (R 3.5.2)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgconfig     2.0.2   2018-08-16 [1] CRAN (R 3.5.1)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  purrr         0.3.2   2019-03-15 [1] CRAN (R 3.5.2)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  scales        1.0.0   2018-08-09 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  tibble        2.1.3   2019-06-06 [1] CRAN (R 3.5.2)                   
##  tidyselect    0.2.5   2018-10-11 [1] CRAN (R 3.5.1)                   
##  tikzDevice  * 0.12.3  2019-08-07 [1] CRAN (R 3.5.2)                   
##  tinytex     * 0.15    2019-08-07 [1] CRAN (R 3.5.2)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Adding strings in R</title>
      <link>https://jcarroll.com.au/2018/10/06/adding-strings-in-r/</link>
      <pubDate>Sat, 06 Oct 2018 00:09:15 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2018/10/06/adding-strings-in-r/</guid>
      <description>&lt;p&gt;This started out as a &lt;em&gt;“hey, I wonder…”&lt;/em&gt; sort of thing, but as usual, they tend to end up as interesting voyages into the deepest depths of code, so I thought I’d write it up and share. Shoutout to &lt;span class=&#34;citation&#34;&gt;[@coolbutuseless]&lt;/span&gt;(&lt;a href=&#34;https://twitter.com/coolbutuseless&#34; class=&#34;uri&#34;&gt;https://twitter.com/coolbutuseless&lt;/a&gt;) for proving that a little curiosity can go a long way and inspiring me to keep digging into interesting topics.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://jcarroll.com.au/post/2018-10-06-adding-strings-in-r_files/stringeastereggs.jpg&#34; alt=&#34;This is what you get if you “glue” “strings”. Photo: https://craftwhack.com/cool-craft-string-easter-eggs/&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;This is what you get if you “glue” “strings”. Photo: &lt;a href=&#34;https://craftwhack.com/cool-craft-string-easter-eggs/&#34; class=&#34;uri&#34;&gt;https://craftwhack.com/cool-craft-string-easter-eggs/&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href=&#34;http://www.happylittlescripts.com/2018/09/make-your-r-code-nicer-with-roperators.html&#34;&gt;This post&lt;/a&gt; came across my feed last week, referring to the &lt;a href=&#34;https://cran.r-project.org/package=roperators&#34;&gt;roperators package on CRAN&lt;/a&gt;. In that post, the author introduces an infix operator from that package which ‘adds’ (concatenates/pastes) strings&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;using infix (%) operators &amp;quot; %+% &amp;quot;R can do simple string addition&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;using infix (%) operators R can do simple string addition&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This might be familiar if you use python&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;&amp;quot;python &amp;quot; + &amp;quot;adds &amp;quot; + &amp;quot;strings&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or javascript&lt;/p&gt;
&lt;pre class=&#34;js&#34;&gt;&lt;code&gt;&amp;quot;javascript &amp;quot; + &amp;quot;also adds &amp;quot; + &amp;quot;strings&amp;quot;
## javascript also adds strings&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or perhaps even go&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;package main

import &amp;quot;fmt&amp;quot;

func main() {
  fmt.Println(&amp;quot;go &amp;quot; + &amp;quot;even adds &amp;quot; + &amp;quot;strings&amp;quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or Julia&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;julia can &amp;quot; * &amp;quot;add strings&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but this is not something natively available in R&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;this doesn&amp;#39;t&amp;quot; + &amp;quot;work&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in &amp;quot;this doesn&amp;#39;t&amp;quot; + &amp;quot;work&amp;quot;: non-numeric argument to binary operator&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2018-10-06-adding-strings-in-r_files/nazi.jpg&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Could we make it work, though? That got me wondering. My first guess was to just create a new &lt;code&gt;+&lt;/code&gt; function which &lt;em&gt;does&lt;/em&gt; allow for this. The normal addition operator is&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;`+`&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## function (e1, e2)  .Primitive(&amp;quot;+&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so a first attempt might be&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;`+` &amp;lt;- function(e1, e2) {
  if (is.character(e1) | is.character(e2)) {
    paste0(e1, e2)
  } else {
    base::`+`(e1, e2)
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This checks to see if the left or right side of the operator is a character-classed object, and if either is, it pastes the two together. Otherwise it just uses the ‘regular’ addition operator between the two arguments. This works for simple cases, e.g.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;a&amp;quot; + &amp;quot;b&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;ab&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;a&amp;quot; + 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;a2&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;2 + 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;2 + &amp;quot;a&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;2a&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But we hit an important snag if we try to add to character-represented numbers&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;200&amp;quot; + &amp;quot;200&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;200200&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s probably going to be an issue if we read in unformatted data (e.g. from a CSV) as characters and try to treat it like numbers. Normally this would throw the above error about not being numeric, but now we get a silent weird number-character. That’s no good.&lt;/p&gt;
&lt;p&gt;An extension to this checks whether or not we have the number-as-a-character situation and falls back to the correct interpretation in that case&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;`+` &amp;lt;- function(e1, e2) {
  ## unary
  if (missing(e2)) return(e1)
  if (!is.na(suppressWarnings(as.numeric(e1))) &amp;amp; !is.na(suppressWarnings(as.numeric(e2)))) {
    ## both arguments numeric-like but characters
    return(base::`+`(as.numeric(e1), as.numeric(e2)))
  } else if ((is.character(e1) &amp;amp; is.na(suppressWarnings(as.numeric(e1)))) | 
             (is.character(e2) &amp;amp; is.na(suppressWarnings(as.numeric(e2))))) {
    ## at least one true character 
    return(paste0(e1, e2))
  } else {
    ## both numeric
    return(base::`+`(e1, e2))
  }
}

&amp;quot;a&amp;quot; + &amp;quot;b&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;ab&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;a&amp;quot; + 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;a2&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;2 + 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;2 + &amp;quot;a&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;2a&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;2&amp;quot; + &amp;quot;2&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;2 + &amp;quot;edgy&amp;quot; + 4 + &amp;quot;me&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;2edgy4me&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, that’s one option for string addition in R. Is it the right one? The idea of actually dispatching on a character class is inviting. Can we just add a &lt;code&gt;+.character&lt;/code&gt; method (since there doesn’t seem to already be one)? Normally when we have S3 dispatch we need a generic function, which calls &lt;code&gt;UseMethod(&amp;quot;class&amp;quot;)&lt;/code&gt;, but we don’t have that in this case. &lt;code&gt;+&lt;/code&gt; is an internal generic, which is probably the first sign that we’re going to have trouble. If we try to define the method&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;`+` &amp;lt;- base::`+`
`+.character` &amp;lt;- function(e1, e2) {
  paste0(e1, e2)
}
&amp;quot;a&amp;quot; + &amp;quot;b&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in &amp;quot;a&amp;quot; + &amp;quot;b&amp;quot;: non-numeric argument to binary operator&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It seems to fail. What went wrong? Is dispatch not working?&lt;/p&gt;
&lt;div style=&#34;width:100%;height:0;padding-bottom:54%;position:relative;&#34;&gt;
&lt;iframe src=&#34;https://giphy.com/embed/dbtDDSvWErdf2&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;position:absolute&#34; frameBorder=&#34;0&#34; class=&#34;giphy-embed&#34; allowFullScreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;a href=&#34;https://giphy.com/gifs/richard-ayoade-it-crowd-maurice-moss-dbtDDSvWErdf2&#34;&gt;via GIPHY&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;We want to dispatch on “character” – is that what we have?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;class(&amp;quot;a&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;character&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What if we explicitly create an object with that class?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;structure(&amp;quot;a&amp;quot;, class = &amp;quot;character&amp;quot;) + 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;a2&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;2 + structure(&amp;quot;a&amp;quot;, class = &amp;quot;character&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;2a&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What if we try to dispatch on some new class?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;`+.foo` &amp;lt;- function(e1, e2) {
  paste0(e1, e2)
}

structure(&amp;quot;a&amp;quot;, class = &amp;quot;foo&amp;quot;) + 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;a2&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but no dice for just a regular atomic character object. Time to revisit the help pages.&lt;/p&gt;
&lt;p&gt;In R, addition is limited to particular classes of objects, defined by the Ops group (there are also Math, Summary, and Complex groups). The methods for the Ops group members describe which classes can be involved in operations involving any of the Ops group members:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, &amp;quot;%%&amp;quot;, &amp;quot;%/%&amp;quot;
&amp;quot;&amp;amp;&amp;quot;, &amp;quot;|&amp;quot;, &amp;quot;!&amp;quot;
&amp;quot;==&amp;quot;, &amp;quot;!=&amp;quot;, &amp;quot;&amp;lt;&amp;quot;, &amp;quot;&amp;lt;=&amp;quot;, &amp;quot;&amp;gt;=&amp;quot;, &amp;quot;&amp;gt;&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These methods are:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;eval(.S3methods(&amp;quot;Ops&amp;quot;), envir = baseenv())&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] Ops.data.frame      Ops.Date            Ops.difftime       
##  [4] Ops.factor          Ops.numeric_version Ops.ordered        
##  [7] Ops.POSIXt          Ops.quosure*        Ops.raster*        
## [10] Ops.roman*          Ops.ts*             Ops.unit*          
## see &amp;#39;?methods&amp;#39; for accessing help and source code&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What’s missing from this list, in order for us to be able to just use “string” + “string” is a character method. What’s perhaps even more surprising is that there &lt;em&gt;is&lt;/em&gt; a &lt;code&gt;roman&lt;/code&gt; method! Whaaaat?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as.roman(&amp;quot;1&amp;quot;) + as.roman(&amp;quot;5&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] VI&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as.roman(&amp;quot;2000&amp;quot;) + as.roman(&amp;quot;18&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] MMXVIII&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2018-10-06-adding-strings-in-r_files/groove_small.gif&#34; width=&#34;400&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Since the operations need to be defined for all the members of the Ops group, we would also need to define what to do with, say, &lt;code&gt;*&lt;/code&gt; between strings. When one side is a string and the other is a number, a reasonable approach might be that which was taken in the original post (using a new infix &lt;code&gt;%s*%&lt;/code&gt;)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;a&amp;quot; %s*% 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##     a 
## &amp;quot;aaa&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is, of course, a function to do this already&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;strrep(&amp;quot;a&amp;quot;, 3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;aaa&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but I could see creating &lt;code&gt;&amp;quot;a&amp;quot; * 3&lt;/code&gt; as a shortcut to this. Note: this exists in python&lt;/p&gt;
&lt;pre class=&#34;python&#34;&gt;&lt;code&gt;&amp;quot;a&amp;quot; * 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;#39;aaa&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I don’t know what one would expect &lt;code&gt;&amp;quot;a&amp;quot; * &amp;quot;b&amp;quot;&lt;/code&gt; to produce.&lt;/p&gt;
&lt;p&gt;The problem with where this is heading is that we aren’t allowed to create the method for an atomic class, as &lt;a href=&#34;https://twitter.com/JorisMeys&#34;&gt;Joris Meys&lt;/a&gt; and &lt;a href=&#34;https://twitter.com/BrodieGaslam&#34;&gt;Brodie Gaslam&lt;/a&gt; point out on Twitter&lt;/p&gt;
&lt;blockquote class=&#34;twitter-tweet&#34; data-lang=&#34;en&#34;&gt;
&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;
Yes, you&#39;re right. Below is what I remembered, which suggested that if it were not sealed, it could be defined, but that isn&#39;t true b/c &lt;code&gt;do_arith&lt;/code&gt; only dispatches on objects (as you point out), although in theory it could dispatch on atomics, but probably doesn&#39;t for speed. &lt;a href=&#34;https://t.co/UXk6Tdm3lW&#34;&gt;pic.twitter.com/UXk6Tdm3lW&lt;/a&gt;
&lt;/p&gt;
— BrodieG (&lt;span class=&#34;citation&#34;&gt;@BrodieGaslam&lt;/span&gt;) &lt;a href=&#34;https://twitter.com/BrodieGaslam/status/1047838113052155904?ref_src=twsrc%5Etfw&#34;&gt;October 4, 2018&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;setMethod(&amp;quot;+&amp;quot;, c(&amp;quot;character&amp;quot;, &amp;quot;character&amp;quot;), function(e1, e2) paste0(e1, e2))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in setMethod(&amp;quot;+&amp;quot;, c(&amp;quot;character&amp;quot;, &amp;quot;character&amp;quot;), function(e1, e2) paste0(e1, : the method for function &amp;#39;+&amp;#39; and signature e1=&amp;quot;character&amp;quot;, e2=&amp;quot;character&amp;quot; is sealed and cannot be re-defined&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so no luck there. Brodie also links to &lt;a href=&#34;https://stackoverflow.com/questions/1319698/why-doesnt-operate-on-characters-in-r/1321491#1321491&#34;&gt;a Stack Overflow discussion&lt;/a&gt; on this very topic where it is pointed out by &lt;a href=&#34;https://twitter.com/MMaechler&#34;&gt;Martin Mächler&lt;/a&gt; that this has been discussed on &lt;a href=&#34;https://stat.ethz.ch/pipermail/r-devel/2006-August/038991.html&#34;&gt;r-devel&lt;/a&gt;q – that makes for some interesting historical weigh-ins on why this isn’t a thing in R. Incidentally, the small-world effect comes into play regarding that Stack Overflow post as one of the three answers happens to be a former work colleague of mine.&lt;/p&gt;
&lt;p&gt;So, in the end, it seems the best we can do is the rather long-winded overwrite of &lt;code&gt;+&lt;/code&gt; which checks if the arguments really are characters. I don’t mind this, and would probably use it if it was in base R or a package. The biggest issue that people seem to have with this is that it ‘looks like’ addition, but it’s not commutative. If that word is new to you, it just means that &lt;code&gt;x + y&lt;/code&gt; should give the same answer as &lt;code&gt;y + x&lt;/code&gt;. For numbers, the regular &lt;code&gt;+&lt;/code&gt; satisfies this:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;2 + 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 5&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;3 + 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but when we try to do this with strings… not so much&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;a&amp;quot; + &amp;quot;b&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;ab&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;b&amp;quot; + &amp;quot;a&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;ba&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This doesn’t particularly bother me, because I’m okay with this not actually being ‘mathematical addition’. The fun turn this then took was the suggestion from &lt;a href=&#34;https://twitter.com/JorisMeys&#34;&gt;Joris Meys&lt;/a&gt; that &lt;a href=&#34;https://docs.julialang.org/en/stable/manual/mathematical-operations/#Operator-Precedence-and-Associativity-1&#34;&gt;Julia’s non-associative operators&lt;/a&gt; is a strength of the language. There, the way that &lt;a href=&#34;https://docs.julialang.org/en/stable/manual/mathematical-operations/#footnote-2&#34;&gt;you group values matters&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
a + b + c is parsed as +(a, b, c) not +(+(a, b), c).
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2018-10-06-adding-strings-in-r_files/wack.gif&#34; width=&#34;250&#34; /&gt;&lt;/p&gt;
&lt;p&gt;I’ll eventually get around to learning more Julia, but this is already hurting my brain.&lt;/p&gt;
&lt;p&gt;That distinction may be of interest, however, to &lt;a href=&#34;https://twitter.com/MilesMcBain/&#34;&gt;Miles McBain&lt;/a&gt;, whose concern was more about repeated applications of &lt;code&gt;+&lt;/code&gt; being a bottleneck&lt;/p&gt;
&lt;blockquote class=&#34;twitter-tweet&#34; data-lang=&#34;en&#34;&gt;
&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;
I hate + for string concatenation. “a” + “b” + “c” is paste(“a”, paste(“b”,“c”)). So you end up copying the data in “b” and “c” twice due to the data being immutable. That can really add up fast with more +&#39;s if you are careless. Like I was in my first programming job.
&lt;/p&gt;
— Miles McBain (&lt;span class=&#34;citation&#34;&gt;@MilesMcBain&lt;/span&gt;) &lt;a href=&#34;https://twitter.com/MilesMcBain/status/1047743465562431489?ref_src=twsrc%5Etfw&#34;&gt;October 4, 2018&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
&lt;p&gt;In that case, parsing as &lt;code&gt;+(&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;)&lt;/code&gt; is exactly what would be desired.&lt;/p&gt;
&lt;p&gt;So, what’s the conclusion of all of this? I’ve learned (and re-learned) a heap more about how the Ops group works, I’ve played a lot with dispatch, and I’ve thought deeply about edge-cases for adding strings. I’ve also been exposed to a bit more Julia. All in all, a worthwhile dive into something potentially silly, but a lot of fun. If you have some thoughts on the matter, leave a comment here or reply on Twitter – I’d love to hear about another angle to this story.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.1.0   2019-07-06 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  dplyr       * 0.8.3   2019-07-04 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  forcats     * 0.4.0   2019-02-17 [1] CRAN (R 3.5.1)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  jsonlite      1.6     2018-12-07 [1] CRAN (R 3.5.1)                   
##  knitr         1.24    2019-08-08 [1] CRAN (R 3.5.2)                   
##  lattice       0.20-38 2018-11-04 [1] CRAN (R 3.5.1)                   
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  Matrix        1.2-17  2019-03-22 [1] CRAN (R 3.5.2)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  pillar        1.4.2   2019-06-29 [1] CRAN (R 3.5.2)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgconfig     2.0.2   2018-08-16 [1] CRAN (R 3.5.1)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  purrr         0.3.2   2019-03-15 [1] CRAN (R 3.5.2)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  reticulate    1.13    2019-07-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  roperators  * 1.1.0   2018-09-28 [1] CRAN (R 3.5.1)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  tibble        2.1.3   2019-06-06 [1] CRAN (R 3.5.2)                   
##  tidyselect    0.2.5   2018-10-11 [1] CRAN (R 3.5.1)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Constricted development with reticulate</title>
      <link>https://jcarroll.com.au/2018/04/04/reticulate/</link>
      <pubDate>Wed, 04 Apr 2018 23:38:05 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2018/04/04/reticulate/</guid>
      <description>&lt;p&gt;I’ve been using the &lt;a href=&#34;https://github.com/rstudio/reticulate&#34;&gt;reticulate&lt;/a&gt; package occasionally for a while now, so I was surprised to see that it had only just been officially released.&lt;/p&gt;
&lt;blockquote class=&#34;twitter-tweet&#34; data-lang=&#34;en&#34;&gt;
&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;
reticulate: R interface to Python &lt;a href=&#34;https://t.co/qVWmwoMQAP&#34;&gt;https://t.co/qVWmwoMQAP&lt;/a&gt;. Comprehensive set of interoperability tools including R Markdown Python engine &lt;a href=&#34;https://twitter.com/hashtag/rstats?src=hash&amp;amp;ref_src=twsrc%5Etfw&#34;&gt;#rstats&lt;/a&gt; &lt;a href=&#34;https://twitter.com/hashtag/pydata?src=hash&amp;amp;ref_src=twsrc%5Etfw&#34;&gt;#pydata&lt;/a&gt; &lt;a href=&#34;https://t.co/SuWM6Y3Pk0&#34;&gt;pic.twitter.com/SuWM6Y3Pk0&lt;/a&gt;
&lt;/p&gt;
— RStudio (&lt;span class=&#34;citation&#34;&gt;@rstudio&lt;/span&gt;) &lt;a href=&#34;https://twitter.com/rstudio/status/978293244390985728?ref_src=twsrc%5Etfw&#34;&gt;March 26, 2018&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
&lt;p&gt;It’s a brilliant piece of work, allowing python and R to coexist in the same workflow.&lt;/p&gt;
&lt;p&gt;Another opportunity came up today to use it so I thought it might be nice to do a very quick blog post to show just how easy it is to take external python code and have it callable directly from R. In this case, &lt;span class=&#34;citation&#34;&gt;[@coolbutuseless]&lt;/span&gt;(&lt;a href=&#34;https://twitter.com/coolbutuseless&#34; class=&#34;uri&#34;&gt;https://twitter.com/coolbutuseless&lt;/a&gt;) posed a challenge on Twitter to write a fast ‘needle in a haystack’ search of a small vector inside a larger one. I looked over the existing candidates and figured some sort of &lt;a href=&#34;https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes&#34;&gt;Sieve of Eratosthenes&lt;/a&gt;-esque algorithm might have a chance (though the name eluded me entirely at the time).&lt;/p&gt;
&lt;p&gt;My proposal was to search for the first digit using &lt;code&gt;which()&lt;/code&gt;, and use this
reduced vector of possible-matches in additional tests on the remaining parts of
the ‘needle’. &lt;span class=&#34;citation&#34;&gt;[@coolbutuseless]&lt;/span&gt;(&lt;a href=&#34;https://twitter.com/coolbutuseless&#34; class=&#34;uri&#34;&gt;https://twitter.com/coolbutuseless&lt;/a&gt;) refactored
my attempt allowing for arbitrary length needles and found it to &lt;a href=&#34;https://coolbutuseless.bitbucket.io/2018/04/03/finding-a-length-n-needle-in-a-haystack/&#34;&gt;do quite well
against the current
offerings&lt;/a&gt;.
What he still wanted though was a &lt;a href=&#34;https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm&#34;&gt;Boyer–Moore string search
algorithm&lt;/a&gt;
implementation. This is apparently what &lt;a href=&#34;https://lists.freebsd.org/pipermail/freebsd-current/2010-August/019310.html&#34;&gt;GNU &lt;code&gt;grep&lt;/code&gt;
uses&lt;/a&gt;,
so it’s probably pretty okay.&lt;/p&gt;
&lt;p&gt;That algorithm is pretty clever about how it goes about the search, starting in a similar way to what I did (the sieve approach was apparently the leading string match method prior to Boyer-Moore). It’s much more complicated though, so I wasn’t about to write one of those myself in R. Nowadays, people think of C/C++ when there’s functionality they want to grab from elsewhere. There’s a C implementation on the Wikipedia site, so that seems like a nice place to start. I &lt;a href=&#34;https://gist.github.com/jonocarroll/d658b5ccf33aaef150b6b36f055d2d6d#file-boyermoore-c&#34;&gt;saved the text&lt;/a&gt; to a new &lt;code&gt;boyermoore.c&lt;/code&gt; file and ran&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;R CMD SHLIB boyermoore.c&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;from a terminal to compile it into &lt;code&gt;boyermore.so&lt;/code&gt;. This could then be loaded into R with &lt;code&gt;dyn.load(&amp;quot;boyermore.so&amp;quot;)&lt;/code&gt; and in theory called with &lt;code&gt;.C(&amp;quot;boyer_moore&amp;quot;, &amp;lt;something&amp;gt;, &amp;lt;something&amp;gt;)&lt;/code&gt;. I tried a couple of &lt;code&gt;&amp;lt;something&amp;gt;&lt;/code&gt;s (which weren’t pointers) and promptly crashed RStudio.&lt;/p&gt;
&lt;p&gt;The python implementation is also listed on Wikipedia, so I figured that’s another route to try. I &lt;a href=&#34;https://gist.github.com/jonocarroll/d658b5ccf33aaef150b6b36f055d2d6d#file-boyermoor-py&#34;&gt;saved the text&lt;/a&gt; to a new &lt;code&gt;boyermoor.py&lt;/code&gt; file (also embedded below) and started about loading the functions from R. This is actually much simpler than for C:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(reticulate)
bm &amp;lt;- py_run_file(&amp;quot;boyermoor.py&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This executes the python file and creates a new named list with each exported python function as an element. How easy is that!?! Calling the function would be as easy as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;bm$string_search(needle, haystack)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not &lt;em&gt;quite&lt;/em&gt; that easy of course… The implementation assumes that both the ‘needle’ and the ‘haystack’ are text, not numbers. To solve this, I converted my numbers (in the range 0 to 12) to letters using the built-in &lt;code&gt;LETTERS&lt;/code&gt; vhat it worked as expected, a benchmark test showed that it was nowhere near as fast as my R approach. I can’t say this is due to the algorithm itself, which should be fairly fast, but probably has more to do with the fact that I’m using two different languages.&lt;/p&gt;
&lt;p&gt;The entire call from R looks pretty neat and tidy&lt;/p&gt;
&lt;p&gt;{{% gist jonocarroll d658b5ccf33aaef150b6b36f055d2d6d %}}&lt;/p&gt;
&lt;p&gt;despite a lot of python code in the background&lt;/p&gt;
&lt;p&gt;I’d certainly recommend having &lt;code&gt;reticulate&lt;/code&gt; in your arsenal next time you need to attack a problem using python from within R. There’s a whole heap of useful ways to interact between R and python with this including importing python modules and calling python scripts, etc…&lt;/p&gt;
&lt;p&gt;As a side-note: keep an eye on the &lt;a href=&#34;https://github.com/rstats-go&#34;&gt;ergo project&lt;/a&gt; to connect the go language in just as easily.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.1.0   2019-07-06 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  jsonlite      1.6     2018-12-07 [1] CRAN (R 3.5.1)                   
##  knitr         1.24    2019-08-08 [1] CRAN (R 3.5.2)                   
##  lattice       0.20-38 2018-11-04 [1] CRAN (R 3.5.1)                   
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  Matrix        1.2-17  2019-03-22 [1] CRAN (R 3.5.2)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  reticulate  * 1.13    2019-07-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>JC and the Vignettes</title>
      <link>https://jcarroll.com.au/2018/03/06/jc-and-the-vignettes/</link>
      <pubDate>Tue, 06 Mar 2018 15:55:31 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2018/03/06/jc-and-the-vignettes/</guid>
      <description>&lt;p&gt;If that’s not a great 1960’s band name then I don’t know what is (hint: I don’t know what is).&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.billboard.com/music/the-marvelettes&#34;&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2018-03-06-jc-and-the-vignettes_files/marvelettes.jpg&#34; width=&#34;400&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;At the start of the year I set out my ‘goals for 2018’ just like many of us do; an overly ambitious list of things we’d like to do to better ourselves. My list includes improving my French to better interact with a colleague I cohabitate and work with while onsite (my 48 day streak on Duolingo was interrupted by travel… &lt;em&gt;c’est un bon début&lt;/em&gt;); reading more books (two a month, so far so good); writing more blog posts (one a month, this one included); interacting more with the R community; and using a bullet journal (all of these are currently tracked in said bullet journal).&lt;/p&gt;
&lt;p&gt;My original plan for the increased interaction was to pick an R package a month. I’d pick a package which didn’t already have a vignette, learn the package, write a vignette, submit it as a PR, and blog about the experience. This seemed straightforward enough. There’s a long-standing feeling that too many R packages lack vignettes (note: &lt;a href=&#34;https://juliasilge.com/blog/mining-cran-description/&#34;&gt;https://juliasilge.com/blog/mining-cran-description/&lt;/a&gt; – an analysis I intend to reproduce/update). I looked through my backlog of interesting packages I meant to look at more closely and checked to see if they already had vignettes… all of them did (womp womp).&lt;/p&gt;
&lt;p&gt;For those not familiar, vignettes in R packages are long-form documentation. Not just a listing of each function, but a good solid walkthrough of background, a use-case, examples, motivations, pitfalls, comparisons, performance metrics, and so on. Function documentation rarely provides sufficient detail like this, so vignettes are a convenient way to include some longer discussions about your package. The problem is that people either neglect to, forget to, or aren’t aware that they can (and should!) write vignettes for their packages.&lt;/p&gt;
&lt;p&gt;Rather than admit defeat and throw another resolution on the ever-growing pile of failures (I’m looking your way, dusty calligraphy set) I decided to take a different approach. I sent out an offer on Twitter: &lt;em&gt;suggest a package which needs a vignette&lt;/em&gt;. It seemed to be popular enough&lt;/p&gt;
&lt;blockquote class=&#34;twitter-tweet&#34; data-lang=&#34;en&#34;&gt;
&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;
The old argument was that &lt;a href=&#34;https://twitter.com/hashtag/rstats?src=hash&amp;amp;ref_src=twsrc%5Etfw&#34;&gt;#rstats&lt;/a&gt; packages generally lack vignettes. Someone scraped CRAN and found ‘most’ (lots of?) packages don&#39;t have them.&lt;br&gt;&lt;br&gt;With my book now with the copyeditors, I finally have some time to get/give back to this awesome community…
&lt;/p&gt;
— Jonathan Carroll (&lt;span class=&#34;citation&#34;&gt;@carroll_jono&lt;/span&gt;) &lt;a href=&#34;https://twitter.com/carroll_jono/status/961139524901527552?ref_src=twsrc%5Etfw&#34;&gt;February 7, 2018&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
&lt;blockquote class=&#34;twitter-tweet&#34; data-lang=&#34;en&#34;&gt;
&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;
So, my offer: point me towards a new(ish) package on GitHub that (a) does something cool, and (b) doesn&#39;t have a vignette. I&#39;ll learn the package inside-out, write a vignette, submit it as a PR, and blog about it. Your package, someone else&#39;s which you use, I don&#39;t mind…
&lt;/p&gt;
— Jonathan Carroll (&lt;span class=&#34;citation&#34;&gt;@carroll_jono&lt;/span&gt;) &lt;a href=&#34;https://twitter.com/carroll_jono/status/961139533701054464?ref_src=twsrc%5Etfw&#34;&gt;February 7, 2018&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
&lt;p&gt;Thus began the ‘Volunteer Vignettes’ program. I got to work on the first one almost immediately, and doing so has already uncovered bugs, inconsistencies, and insights to the author (I do plan to start a conversation with original authors before beginning any actual work). I’ll be writing each one up once I’m ‘done’ with it, sharing the insights discovered along the way, plus some new ideas about how vignettes might evolve.&lt;/p&gt;
&lt;p&gt;If you’re new to vignettes, at this point you may be asking “How does one go about making one? What tools are required? How do I include one in my package?”, and I’m glad you asked. Over the next few months I’ll be blogging about vignettes; how they’re currently used, how they might be more useful, and how we might be able to get people to use them more. I’m also scheduled to present the eventual conclusion of this project at &lt;a href=&#34;https://user2018.r-project.org/&#34;&gt;userR 2018&lt;/a&gt;, so I’d better get it done!&lt;/p&gt;
&lt;p&gt;For now, stay tuned!&lt;/p&gt;
&lt;p&gt;P.S. for those interested in a very old-school jam:&lt;/p&gt;
&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube.com/embed/425GpjTSlS4?rel=0&#34; frameborder=&#34;0&#34; allow=&#34;autoplay; encrypted-media&#34; allowfullscreen&gt;
&lt;/iframe&gt;
</description>
    </item>
    
    <item>
      <title>Thou shalt not compare numeric values (except when it works)
</title>
      <link>https://jcarroll.com.au/2017/09/04/compare-numerics/</link>
      <pubDate>Mon, 04 Sep 2017 15:02:07 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2017/09/04/compare-numerics/</guid>
      <description>&lt;p&gt;This was just going to be a few Tweets but it ended up being a bit of a rollercoaster of learning for me, and I haven’t blogged in far too long, so I’m writing it up quickly as a ‘hey look at that’ example for newcomers.&lt;/p&gt;
&lt;p&gt;I’ve been working on the ‘merging data’ part of &lt;a href=&#34;https://www.manning.com/books/data-munging-with-r&#34;&gt;my book&lt;/a&gt; and, as I do when I’m writing this stuff, I had a play around with some examples to see if there was anything funky going on if a reader was to try something slightly different. I’ve been using &lt;code&gt;dplyr&lt;/code&gt; for the examples after being thoroughly convinced on Twitter to do so. It’s going well. Mostly.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## if you haven&amp;#39;t already done so, load dplyr
library(dplyr)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My example involved joining together two &lt;code&gt;tibble&lt;/code&gt;s containing text values. Nothing too surprising. I wondered though; do numbers behave the way I expect? Now, a big rule in programming is ‘thou shalt not compare numbers’, and it holds especially true &lt;a href=&#34;http://0.30000000000000004.com/&#34;&gt;when numbers aren’t exactly integers&lt;/a&gt;. This is because representing non-integers is hard, and what you see on the screen isn’t always what the computer sees internally.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://jcarroll.com.au/post/2017-09-04-thou-shalt-not-compare-numeric-values-except-when-it-works_files/AngryGod.jpg&#34; alt=&#34;Thou shalt not compare numbers&#34; width=&#34;600&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;Thou shalt not compare numbers&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;If I had a &lt;code&gt;tibble&lt;/code&gt; where the column I would use to &lt;code&gt;join&lt;/code&gt; had integers&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dataA &amp;lt;- tribble(
    ~X, ~Y,
    0L, 100L,
    1L, 101L,
    2L, 102L,
    3L, 103L
)
dataA&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 4 x 2
##       X     Y
##   &amp;lt;int&amp;gt; &amp;lt;int&amp;gt;
## 1     0   100
## 2     1   101
## 3     2   102
## 4     3   103&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and another &lt;code&gt;tibble&lt;/code&gt; with &lt;code&gt;numeric&lt;/code&gt; in that column&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dataB &amp;lt;- tribble(
    ~X, ~Z,
    0, 1000L,
    1, 1001L,
    2, 1002L,
    3, 1003L
)
dataB&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 4 x 2
##       X     Z
##   &amp;lt;dbl&amp;gt; &amp;lt;int&amp;gt;
## 1     0  1000
## 2     1  1001
## 3     2  1002
## 4     3  1003&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;would they still &lt;code&gt;join&lt;/code&gt;?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;full_join(dataA, dataB)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Joining, by = &amp;quot;X&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 4 x 3
##       X     Y     Z
##   &amp;lt;dbl&amp;gt; &amp;lt;int&amp;gt; &amp;lt;int&amp;gt;
## 1     0   100  1000
## 2     1   101  1001
## 3     2   102  1002
## 4     3   103  1003&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, sure. R treats these as close enough to join. I mean, maybe it shouldn’t, but we’ll work with what we have. R doesn’t always think these are equal&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;identical(0L, 0)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;identical(2L, 2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;though sometimes it does&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;0L == 0&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;2L == 2&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(&lt;code&gt;==&lt;/code&gt; coerces types before comparing). Well, what if one of these just ‘looks like’ the other value (can be coerced to the same?)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dataC &amp;lt;- tribble(
    ~X, ~Z,
    &amp;quot;0&amp;quot;, 100L,
    &amp;quot;1&amp;quot;, 101L,
    &amp;quot;2&amp;quot;, 102L,
    &amp;quot;3&amp;quot;, 103L
)
dataC&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 4 x 2
##   X         Z
##   &amp;lt;chr&amp;gt; &amp;lt;int&amp;gt;
## 1 0       100
## 2 1       101
## 3 2       102
## 4 3       103&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;full_join(dataA, dataC)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-info text-info&#34;&gt;&lt;code&gt;## Joining, by = &amp;quot;X&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error: Can&amp;#39;t join on &amp;#39;X&amp;#39; x &amp;#39;X&amp;#39; because of incompatible types (character / integer)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s probably wise. Of course, R is perfectly happy with things like&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;2&amp;quot;:&amp;quot;5&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2 3 4 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and &lt;code&gt;==&lt;/code&gt; thinks that’s fine&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;0&amp;quot; == 0L&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;quot;2&amp;quot; == 2L&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but who am I to argue?&lt;/p&gt;
&lt;p&gt;Anyway, how far apart can those integers and numerics be before they aren’t able to be joined? What if we shift the ‘numeric in name only’ values away from the integers just a teensy bit? &lt;code&gt;.Machine$double.eps&lt;/code&gt; is the built-in value for ‘the tiniest number you can produce’. On this system it’s 2.22044610^{-16}.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dataBeps &amp;lt;- tribble(
    ~X, ~Z,
    0 + .Machine$double.eps, 1000L,
    1 + .Machine$double.eps, 1001L,
    2 + .Machine$double.eps, 1002L,
    3 + .Machine$double.eps, 1003L
)
dataBeps&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 4 x 2
##          X     Z
##      &amp;lt;dbl&amp;gt; &amp;lt;int&amp;gt;
## 1 2.22e-16  1000
## 2 1.00e+ 0  1001
## 3 2.00e+ 0  1002
## 4 3.00e+ 0  1003&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, that’s… weirder. The values offset from &lt;code&gt;2&lt;/code&gt; and &lt;code&gt;3&lt;/code&gt; joined fine, but the &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; each got multiple copies since R thinks they’re different. What if we offset a little further?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dataB2eps &amp;lt;- tribble(
    ~X, ~Z,
    0 + 2*.Machine$double.eps, 1000L,
    1 + 2*.Machine$double.eps, 1001L,
    2 + 2*.Machine$double.eps, 1002L,
    3 + 2*.Machine$double.eps, 1003L
)
dataB2eps&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## # A tibble: 4 x 2
##          X     Z
##      &amp;lt;dbl&amp;gt; &amp;lt;int&amp;gt;
## 1 4.44e-16  1000
## 2 1.00e+ 0  1001
## 3 2.00e+ 0  1002
## 4 3.00e+ 0  1003&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s what I’d expect. So, what’s going on? Why does R think those numbers are the same? Let’s check with a minimal example: For each of the values &lt;code&gt;0:4&lt;/code&gt;, let’s compare that integer with the same offset by &lt;code&gt;.Machine$double.eps&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(purrr) ## for the &amp;#39;thou shalt not for-loop&amp;#39; crowd
map_lgl(0:4, ~ as.integer(.x) == as.integer(.x) + .Machine$double.eps)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE FALSE  TRUE  TRUE  TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And there we have it. Some sort of relative difference tolerance maybe? In any case, the general rule to live by is to &lt;em&gt;never&lt;/em&gt; compare floats. Add this to the list of reasons why.&lt;/p&gt;
&lt;p&gt;For what it’s worth, I’m sure this is hardly a surprising detail to the &lt;code&gt;dplyr&lt;/code&gt; team. They’ve dealt with &lt;a href=&#34;https://github.com/tidyverse/dplyr/issues/228&#34;&gt;things like this for a long time&lt;/a&gt; and I’m sure it was much worse before those changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update: &lt;/strong&gt; As noted in the comments, R does have a way to check if things are ‘nearly equal’ (within some specified tolerance) via &lt;code&gt;all.equal()&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;purrr::map_lgl(0:4, ~all.equal(.x, .x + .Machine$double.eps))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE TRUE TRUE TRUE TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, this does require the user to either specify the exact tolerance under which they consider two numbers ‘equal’, or to use the default (which, judging by the source of &lt;code&gt;all.equal.numeric()&lt;/code&gt; is &lt;code&gt;sqrt(.Machine$double.eps)&lt;/code&gt; or around 1.490116110^{-8} on this system). This means that numbers can be ‘quite’ different (depending on what’s an important difference) and still considered equal&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;purrr::map_lgl(0:4, ~ all.equal(.x, .x + 1e-8))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE TRUE TRUE TRUE TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.1.0   2019-07-06 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  dplyr       * 0.8.3   2019-07-04 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  fansi         0.4.0   2018-10-05 [1] CRAN (R 3.5.1)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  knitr         1.24    2019-08-08 [1] CRAN (R 3.5.2)                   
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  pillar        1.4.2   2019-06-29 [1] CRAN (R 3.5.2)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgconfig     2.0.2   2018-08-16 [1] CRAN (R 3.5.1)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  purrr       * 0.3.2   2019-03-15 [1] CRAN (R 3.5.2)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  tibble      * 2.1.3   2019-06-06 [1] CRAN (R 3.5.2)                   
##  tidyselect    0.2.5   2018-10-11 [1] CRAN (R 3.5.1)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  utf8          1.1.4   2018-05-24 [1] CRAN (R 3.5.1)                   
##  vctrs         0.2.0   2019-07-05 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
##  zeallot       0.1.0   2018-01-28 [1] CRAN (R 3.5.2)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Data Munging With R Preview - Storing Values (Assigning)</title>
      <link>https://jcarroll.com.au/2017/06/26/data-munging-with-r-preview-storing-values-assigning/</link>
      <pubDate>Mon, 26 Jun 2017 23:10:03 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2017/06/26/data-munging-with-r-preview-storing-values-assigning/</guid>
      <description>&lt;p&gt;[&lt;strong&gt;Update&lt;/strong&gt;] The title of this book has since been changed to &lt;em&gt;Beyond Spreadsheets with R&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Since about October last year, I’ve been writing an introduction to R book. It’s
been quite the experience. I’ve finally started making time to document some of
the interesting things I’ve learned (about R, about writing, about how to bring
those two together) along the way.&lt;/p&gt;
&lt;p&gt;The book is aimed at proper beginners; people with absolutely no formal coding
experience. This tends to mean people coming from Excel who need to do more than
a spreadsheet can/should.&lt;/p&gt;
&lt;blockquote class=&#34;twitter-tweet&#34;&gt;
&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;
I&#39;m writing an R book for real beginners (ppl with 0 code XP) via &lt;a href=&#34;https://twitter.com/ManningBooks?ref_src=twsrc%5Etfw&#34;&gt;&lt;span class=&#34;citation&#34;&gt;@ManningBooks&lt;/span&gt;&lt;/a&gt;! What tripped you up most when you first learned R? Pls RT!
&lt;/p&gt;
— Jonathan Carroll (&lt;span class=&#34;citation&#34;&gt;@carroll_jono&lt;/span&gt;) &lt;a href=&#34;https://twitter.com/carroll_jono/status/780746085727735808?ref_src=twsrc%5Etfw&#34;&gt;September 27, 2016&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
&lt;p&gt;Most of the books I’ve looked at which claim to teach programming begin with
some strong assumptions about the reader already knowing how to program, and
teach the specific syntax of some language. That’s no good if this is your first
language, so I’m working towards teaching the concepts, the language, and the
syntax (warts and all).&lt;/p&gt;
&lt;p&gt;The book is currently available under the Manning Early Access Program (MEAP)
which means if you buy it you get the draft of the first three chapters right
now. If you find something you still don’t understand, or you don’t like how
I’ve written some/all of it, then jump onto the forum and let me know. I make
more edits and write more chapters, and you get updated versions. Lather, rinse,
repeat until the final version and you get a polished book which (if I’m any
good) contains what you want it to.&lt;/p&gt;
&lt;p&gt;I’m genuinely interested in getting this right; I want to help people learn R. I
contribute a bit of time on Stack Overflow answering people’s questions, and
it’s very common to see questions that shouldn’t need asking. I don’t blame the
user for not knowing something (a different answer for not searching, perhaps),
but I can help make the resource they need.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.manning.com/books/data-munging-with-r?a_aid=datamungingwithr&amp;amp;a_bid=1dc44480&#34;&gt;To show that I really want people to contribute, here’s a discount code to
sweeten the deal: use &lt;code&gt;mlcarroll&lt;/code&gt; for 50% off here.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Chapter 1 is a free download, so please check that out too! At the moment the
MEAP covers the first three chapters, but the following four aren’t too far
behind.&lt;/p&gt;
&lt;p&gt;I’ll document some of the behind-the-scenes process shortly, but for now here’s
an excerpt from chapter 2:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.2. Storing Values (Assigning)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In order to do something with our data, we will need to tell &lt;code&gt;R&lt;/code&gt; what
to call it, so that we can refer to it in our code. In programming in general,
we typically have &lt;em&gt;variables&lt;/em&gt; (things that may vary) and &lt;em&gt;values&lt;/em&gt;
(our data). We’ve already seen that different data &lt;em&gt;values&lt;/em&gt; can have
different &lt;em&gt;types&lt;/em&gt;, but we haven’t told &lt;code&gt;R&lt;/code&gt; to store any of
them yet. Next, we’ll create some &lt;em&gt;variables&lt;/em&gt; to store our data
&lt;em&gt;values&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.2.1. Data (Variables)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If we have the values &lt;code&gt;4&lt;/code&gt; and &lt;code&gt;8&lt;/code&gt; and we want to do something with them, we can
use the values literally (say, add them together as &lt;code&gt;4 + 8&lt;/code&gt;). You may be
familiar with this if you frequently use Excel; data values are stored in cells
(groups of which you can opt to name) and you tell the program which values you
wish to combine in some calculation by selecting the cells with the mouse or
keyboard. Alternatively, you can opt to refer to cells by their grid reference
(e.g. &lt;code&gt;A1&lt;/code&gt;). Similarly to this second method, we can store values in &lt;em&gt;variables&lt;/em&gt;
(things that may vary) and &lt;em&gt;abstract&lt;/em&gt; away the values. In &lt;code&gt;R&lt;/code&gt;, assigning of
values to variables takes the following form&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;variable &amp;lt;- value&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;assignment operator&lt;/em&gt; &lt;code&gt;&amp;lt;-&lt;/code&gt; can be thought of as storing the value/thing on
the right hand side into the name/thing on the left hand side. For example, try
typing &lt;code&gt;x &amp;lt;- 4&lt;/code&gt; into the &lt;code&gt;R&lt;/code&gt; &lt;code&gt;**Console**&lt;/code&gt; then press &lt;kbd&gt;Enter&lt;/kbd&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2017-06-26-data-munging-with-r-preview-storing-values-assigning_files/variable_value.png&#34; width=&#34;150&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Figure 2. 1. The &lt;em&gt;variable&lt;/em&gt; &lt;code&gt;x&lt;/code&gt; has been assigned the &lt;em&gt;value&lt;/em&gt; &lt;code&gt;4&lt;/code&gt;.
You could just as easily use the equals sign to achieve this; &lt;code&gt;x = 4&lt;/code&gt; but I
recommend you use &lt;code&gt;&amp;lt;-&lt;/code&gt; for this for reasons that will become clear later.
You’ll notice that the &lt;code&gt;**Environment**&lt;/code&gt; tab of the &lt;code&gt;**Workspace**&lt;/code&gt; pane now lists
&lt;code&gt;x&lt;/code&gt; under &lt;code&gt;**Values**&lt;/code&gt; and shows the number 4 next to it, as shown in Fig 2. 2.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2017-06-26-data-munging-with-r-preview-storing-values-assigning_files/fig-x_eq_4.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Figure 2. 2. The &lt;em&gt;variable&lt;/em&gt; &lt;code&gt;x&lt;/code&gt; has been assigned the &lt;em&gt;value&lt;/em&gt; &lt;code&gt;4&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What happened behind the scenes was that when we pressed &lt;kbd&gt;Enter&lt;/kbd&gt;, &lt;code&gt;R&lt;/code&gt;
took the entire expression that we entered (&lt;code&gt;x &amp;lt;- 4&lt;/code&gt;) and evaluated it. Since we
told &lt;code&gt;R&lt;/code&gt; to &lt;em&gt;assign&lt;/em&gt; the value &lt;code&gt;4&lt;/code&gt; to the variable &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;R&lt;/code&gt; converted the value
&lt;code&gt;4&lt;/code&gt; to binary and placed that in the computer’s memory. &lt;code&gt;R&lt;/code&gt; then gives us a
reference to that place in the computer’s memory and labels it &lt;code&gt;x&lt;/code&gt;. A diagram of
this process is shown in Fig 2. 3. Nothing else appeared in the &lt;code&gt;**Console**&lt;/code&gt;
because the action of assigning a value doesn’t &lt;em&gt;return&lt;/em&gt; anything (we’ll cover
this more in our section on functions).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2017-06-26-data-munging-with-r-preview-storing-values-assigning_files/assign.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Figure 2. 3. Assigning a value to a variable. The value entered is converted to
binary, then stored in memory, the reference to which is labelled by the
variable.&lt;/p&gt;
&lt;p&gt;This is overly simplified, of course. Technically speaking, in &lt;code&gt;R&lt;/code&gt;, names have
objects rather than the other way around. This means that &lt;code&gt;R&lt;/code&gt; can be quite
memory efficient since it doesn’t create a copy of anything it doesn’t need to.&lt;/p&gt;
&lt;p&gt;Caution: On &lt;em&gt;“hidden”&lt;/em&gt; variables&lt;/p&gt;
&lt;p&gt;Variables which begin with a period (e.g. &lt;code&gt;.length&lt;/code&gt;) are considered &lt;em&gt;hidden&lt;/em&gt; and
do not appear in the &lt;code&gt;**Environment**&lt;/code&gt; tab of the &lt;code&gt;**Workspace**&lt;/code&gt;. They
otherwise behave exactly as any other variable; they can be printed and
manipulated. An example of one of these is the &lt;code&gt;.Last.value&lt;/code&gt; variable, which
exists from the moment you load up &lt;code&gt;R&lt;/code&gt; (with the value &lt;code&gt;TRUE&lt;/code&gt;) - this contains
the output value of the last statement executed (handy if you forgot to assign
it to something). There are very few reasons you’ll want to use this feature
(dot-prefixed hidden variables) on purpose at the moment, so for now, avoid
creating variable names with this pattern. The exception to the &lt;em&gt;hidden&lt;/em&gt; nature
of these is again the &lt;code&gt;.Last.value&lt;/code&gt; variable which you can request to be visible
in the &lt;code&gt;**Environment**&lt;/code&gt; tab via &lt;span class=&#34;menuseq&#34;&gt;&lt;span class=&#34;menu&#34;&gt;Tools&lt;/span&gt; ▸ &lt;span class=&#34;submenu&#34;&gt;Global Options…
&lt;/span&gt; ▸ &lt;span class=&#34;submenu&#34;&gt;General&lt;/span&gt; ▸ &lt;span class=&#34;menuitem&#34;&gt;Show .Last.value in environment listing&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;We can retrieve the value assigned to the variable &lt;code&gt;x&lt;/code&gt; by asking &lt;code&gt;R&lt;/code&gt; to print
the value of &lt;code&gt;x&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;print(x = x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;for which we have a useful shortcut - if your entire expression is just a
variable, &lt;code&gt;R&lt;/code&gt; will assume you mean to &lt;code&gt;print()&lt;/code&gt; it, so&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;works just the same.&lt;/p&gt;
&lt;p&gt;Now, about that &lt;code&gt;[1]&lt;/code&gt;: it’s important to know that in &lt;code&gt;R&lt;/code&gt;, there’s no such thing
as a single value; every value is actually a &lt;em&gt;vector&lt;/em&gt; of values (we’ll cover
these properly in the next chapter, but think of these as collections of values
of the same type).&lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_1&#34; class=&#34;footnote&#34; href=&#34;#_footnote_1&#34; title=&#34;View footnote.&#34;&gt;1&lt;/a&gt;]&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Whenever &lt;code&gt;R&lt;/code&gt; prints a value it allows for the case where the value contains more
than one number. To make this easier on the eye, it labels the first value
appearing on the line by it’s position in the collection. For collections
(vectors) with just a single value, this might appear strange, but this makes
more sense once our variables contain more values&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Print the column names of the mtcars dataset
names(x = mtcars)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  [1] &amp;quot;mpg&amp;quot;  &amp;quot;cyl&amp;quot;  &amp;quot;disp&amp;quot; &amp;quot;hp&amp;quot;   &amp;quot;drat&amp;quot; &amp;quot;wt&amp;quot;   &amp;quot;qsec&amp;quot; &amp;quot;vs&amp;quot;   &amp;quot;am&amp;quot;   &amp;quot;gear&amp;quot;
## [11] &amp;quot;carb&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can assign another variable to another value&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;y &amp;lt;- 8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are few restrictions for what we can name our data &lt;em&gt;values&lt;/em&gt;, but &lt;code&gt;R&lt;/code&gt; will
complain if you try to break them. Variables should start with a letter, not a
number. Trying to create the variable &lt;code&gt;2b&lt;/code&gt; will generate an error. Variables can
also start with a dot (&lt;code&gt;.&lt;/code&gt;) as long as it’s not immediately followed by a
number, although you may wish to avoid doing so. The rest of the variable name
can consist of letters (upper and lower case) and numbers, but not punctuation
(except &lt;code&gt;.&lt;/code&gt; or &lt;code&gt;_&lt;/code&gt;) or other symbols (except the dot, though again, preferably
not).&lt;/p&gt;
&lt;p&gt;There are also certain &lt;em&gt;reserved words&lt;/em&gt; that you can’t name variables as. Some
are &lt;em&gt;reserved&lt;/em&gt; for built-in functions or keywords&lt;/p&gt;
&lt;p&gt;&lt;code&gt;if&lt;/code&gt;, &lt;code&gt;else&lt;/code&gt;, &lt;code&gt;repeat&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;function&lt;/code&gt;, &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;in&lt;/code&gt;, &lt;code&gt;next&lt;/code&gt;, and &lt;code&gt;break&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Others are &lt;em&gt;reserved&lt;/em&gt; for particular values&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TRUE&lt;/code&gt;, &lt;code&gt;FALSE&lt;/code&gt;, &lt;code&gt;NULL&lt;/code&gt;, &lt;code&gt;Inf&lt;/code&gt;, &lt;code&gt;NaN&lt;/code&gt;, &lt;code&gt;NA&lt;/code&gt;, &lt;code&gt;NA_integer_&lt;/code&gt;, &lt;code&gt;NA_real_&lt;/code&gt;,
&lt;code&gt;NA_complex_&lt;/code&gt;, and &lt;code&gt;NA_character_&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We’ll come back to what each of these means, but for now you just need to know
that you can’t create a variable with one of those names.&lt;/p&gt;
&lt;p&gt;Caution: On overwriting names&lt;/p&gt;
&lt;p&gt;What you &lt;strong&gt;can&lt;/strong&gt; do however, which you may wish to take care with, is &lt;em&gt;overwrite&lt;/em&gt;
the in-built names of variables and functions. By default, the value &lt;code&gt;pi&lt;/code&gt; is
available (π = 3.141593).&lt;/p&gt;
&lt;p&gt;If you were translating an equation into code, and wanted to enter the value
&lt;em&gt;p&lt;sub&gt;i&lt;/sub&gt;&lt;/em&gt; you might accidentally call it &lt;code&gt;pi&lt;/code&gt; and in doing so change the
default value, causing all sorts of trouble when you next go to use it or call a
function you’ve written which expects it to still be the default.&lt;/p&gt;
&lt;p&gt;The default value can still be accessed by specifying the package in which it is
defined, separated by two colons (&lt;code&gt;::&lt;/code&gt;). In the case of &lt;code&gt;pi&lt;/code&gt;, this is the &lt;code&gt;base&lt;/code&gt;
package.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Re-defining `pi` to be equal to exactly `3`
pi &amp;lt;- 3L
# The default, correct value is still available.
base::pi&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 3.141593&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is also an issue for functions, with the same solution; specify the package
in which it is defined to use that definition. We’ll return to this in a section
on ‘scope’.&lt;/p&gt;
&lt;p&gt;We’ll cover how to do things to our variables in more detail in the next
section, but for now let’s see what happens if we add our variables &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;
in the same way as we did for our regular numbers&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x + y&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 12&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is what we got when we added these numbers explicitly. Note that since our
expression produces just a number (no assignment), the value is printed. We’ll
cover how to add and subtract values in more depth in our section on basic
mathematics.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;R&lt;/code&gt; has no problems with overwriting these values, and it doesn’t mind what data
you overwrite these with.&lt;sup class=&#34;footnote&#34;&gt;[&lt;a id=&#34;_footnoteref_2&#34; class=&#34;footnote&#34; href=&#34;#_footnote_2&#34; title=&#34;View footnote.&#34;&gt;2&lt;/a&gt;]&lt;/sup&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;y &amp;lt;- &amp;#39;banana&amp;#39;
y&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;banana&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;R&lt;/code&gt; is &lt;em&gt;case-sensitive&lt;/em&gt;, which means that it treats &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;A&lt;/code&gt; as distinct
names. You can have a variable named &lt;code&gt;myVariable&lt;/code&gt; and another named &lt;code&gt;MYvariable&lt;/code&gt;
and another named &lt;code&gt;myVARIABLE&lt;/code&gt; and &lt;code&gt;R&lt;/code&gt; will hold the value assigned to each
independently.&lt;/p&gt;
&lt;p&gt;On variable names:&lt;/p&gt;
&lt;blockquote&gt;
There are only two hard things in Computer Science: cache invalidation and naming things.
&lt;/blockquote&gt;
&lt;div class=&#34;attribution&#34;&gt;
&lt;p&gt;— Phil Karlton&lt;br&gt;
&lt;cite&gt;Principal Curmudgeon Netscape Communications Corporation&lt;/cite&gt;&lt;/p&gt;
&lt;p&gt;I said earlier that &lt;code&gt;R&lt;/code&gt; won’t keep track of your units so it’s a good idea to
name your variables in a way that makes logical sense, is meaningful, and will
help you remember what it represents. Variables &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; are fine for playing
around with values, but aren’t particularly meaningful if your data represents
speeds, where you may want to use something like &lt;code&gt;speed_kmph&lt;/code&gt; for speeds in
kilometers per hour. Underscores (&lt;code&gt;_&lt;/code&gt;) are allowed in variable names, but
whether or not you use them is up to you. Some programmers prefer to name
variables in this way (sometimes referred to as ‘snake_case’), others prefer
‘CamelCase’. The use of periods (dots, &lt;code&gt;.&lt;/code&gt;) to separate words is discouraged for
reasons beyond the scope of this book.&lt;sup class=&#34;footnote&#34;&gt;[&lt;a
id=&#34;_footnoteref_3&#34; class=&#34;footnote&#34; href=&#34;#_footnote_3&#34; title=&#34;View
footnote.&#34;&gt;3&lt;/a&gt;]&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Important: Naming things&lt;/p&gt;
&lt;p&gt;Be careful when naming your variables. Make them meaningful and concise. In six
months from now, will you remember what &lt;code&gt;data_17&lt;/code&gt; corresponds to? Tomorrow, will
you remember that &lt;code&gt;newdata&lt;/code&gt; was updated twice?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.2.2. Unchanging Data&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you’re familiar with working with data in a spreadsheet program (such as
Excel), you may expect your variables to behave in a way that they won’t.
Automatic recalculation is a very useful feature of spreadsheet programs, but
it’s not how &lt;code&gt;R&lt;/code&gt; behaves.&lt;/p&gt;
&lt;p&gt;If we assign our two variables, then add them, we can save that result to
another variable&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- 4
b &amp;lt;- 8
sum_of_a_and_b &amp;lt;- a + b&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This has the value we expect&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;print(x = sum_of_a_and_b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 12&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if we &lt;em&gt;change&lt;/em&gt; one of these values&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;b &amp;lt;- 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;this has &lt;strong&gt;no impact&lt;/strong&gt; on the value of the variable we created to hold the sum
earlier&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;print(x = sum_of_a_and_b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 12&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the sum was calculated, and that value stored in a variable, the connection
to the original values was lost. This makes things &lt;em&gt;reliable&lt;/em&gt; because you know
for sure what value a variable will have at any point in your calculation by
following the steps that lead to it, whereas a spreadsheet depends much more on
its current overall &lt;em&gt;state&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.2.3. Assigmnent Operators (&lt;code&gt;&amp;lt;-&lt;/code&gt; vs &lt;code&gt;=&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you’ve read some &lt;code&gt;R&lt;/code&gt; code already, you’ve possibly seen that both &lt;code&gt;&amp;lt;-&lt;/code&gt; and
&lt;code&gt;=&lt;/code&gt; are used to assign values to objects, and this tends to cause some
confusion. Technically, &lt;code&gt;R&lt;/code&gt; will accept either when assigning variables, so in
that respect it comes down to a matter of style (I still highly recommend
assigning with &lt;code&gt;&amp;lt;-&lt;/code&gt;). The big difference comes when using functions that take
&lt;em&gt;arguments&lt;/em&gt; - there you should only use &lt;code&gt;=&lt;/code&gt; to specify what the &lt;em&gt;value&lt;/em&gt; of the
&lt;em&gt;argument&lt;/em&gt;. For example, when we inspected the &lt;code&gt;mtcars&lt;/code&gt; data, we could specify a
string with which to indent the output&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;str(object = mtcars, indent.str = &amp;#39;&amp;gt;&amp;gt;  &amp;#39;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## &amp;#39;data.frame&amp;#39;:    32 obs. of  11 variables:
## &amp;gt;&amp;gt;  $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
## &amp;gt;&amp;gt;  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
## &amp;gt;&amp;gt;  $ disp: num  160 160 108 258 360 ...
## &amp;gt;&amp;gt;  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
## &amp;gt;&amp;gt;  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
## &amp;gt;&amp;gt;  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
## &amp;gt;&amp;gt;  $ qsec: num  16.5 17 18.6 19.4 17 ...
## &amp;gt;&amp;gt;  $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
## &amp;gt;&amp;gt;  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
## &amp;gt;&amp;gt;  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
## &amp;gt;&amp;gt;  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we had used &lt;code&gt;&amp;lt;-&lt;/code&gt; instead of &lt;code&gt;=&lt;/code&gt; for either argument, then &lt;code&gt;R&lt;/code&gt; would treat
that as creating a new variable &lt;code&gt;object&lt;/code&gt; or &lt;code&gt;indent.str&lt;/code&gt; with value &lt;code&gt;mtcars&lt;/code&gt; or
&lt;code&gt;&#39;&amp;gt;&amp;gt; &#39;&lt;/code&gt; respectively, which isn’t what we want.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;score &amp;lt;- 4.8
score&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4.8&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;str(object = score)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  num 4.8&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fruit &amp;lt;- &amp;#39;banana&amp;#39;
fruit&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;banana&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;str(object = fruit)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##  chr &amp;quot;banana&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that we didn’t need to tell &lt;code&gt;R&lt;/code&gt; that one of these was a number and one was
a string, it figured that out itself. It’s good practice (and easier to read) to
make your &lt;code&gt;&amp;lt;-&lt;/code&gt; line up vertically when defining several variables:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;first_name &amp;lt;- &amp;#39;John&amp;#39;
last_name  &amp;lt;- &amp;#39;Smith&amp;#39;
top_points &amp;lt;- 23&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but only if this can be achieved without adding too many spaces (exactly how
many is too many is up to you).&lt;/p&gt;
&lt;p&gt;Caution: Watch this space!&lt;/p&gt;
&lt;p&gt;An extra space can make a big difference to the syntax. Compare:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt;- 3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;a &amp;lt; - 3&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the first case we assigned the value &lt;code&gt;3&lt;/code&gt; to the variable &lt;code&gt;a&lt;/code&gt; (which returns
nothing). In the second case, with a wayward space, we &lt;em&gt;compared&lt;/em&gt; &lt;code&gt;a&lt;/code&gt; to the
value &lt;code&gt;-3&lt;/code&gt; which returns &lt;code&gt;FALSE&lt;/code&gt; (I’ll explain why that works at all, later).&lt;/p&gt;
&lt;p&gt;Now that we know how to provide some data to &lt;code&gt;R&lt;/code&gt;, what if we want to explicitly
tell &lt;code&gt;R&lt;/code&gt; that our data should be of a specific type, or we want to convert our
data to a different type? That’s an article for another day.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.manning.com/books/data-munging-with-r?a_aid=datamungingwithr&amp;amp;a_bid=1dc44480&#34;&gt;If you’re interested in seeing more, and hopefully providing feedback on what
you do/don’t like about it, then use the discount code &lt;code&gt;mlcarroll&lt;/code&gt;
here&lt;/a&gt;
for 50% off and get reading!&lt;/p&gt;
&lt;div id=&#34;footnotes&#34;&gt;
&lt;hr&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnote_1&#34;&gt;
&lt;p&gt;&lt;a href=&#34;#_footnoteref_1&#34;&gt;1&lt;/a&gt;. In technical terms, &lt;code&gt;R&lt;/code&gt; has no &lt;em&gt;scalar&lt;/em&gt; types.&lt;/p&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnote_2&#34;&gt;
&lt;p&gt;&lt;a href=&#34;#_footnoteref_2&#34;&gt;2&lt;/a&gt;. This is where the distinction of &lt;em&gt;weakly typed&lt;/em&gt; becomes important - in a &lt;em&gt;strongly typed&lt;/em&gt; language you would not be able to arbitrarily change the type of a variable.&lt;/p&gt;
&lt;div class=&#34;footnote&#34; id=&#34;_footnote_3&#34;&gt;
&lt;p&gt;&lt;a href=&#34;#_footnoteref_3&#34;&gt;3&lt;/a&gt;. This syntax is already used within &lt;code&gt;R&lt;/code&gt; to denote functions acting on a specific class, such as &lt;code&gt;print.Date()&lt;/code&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Images as x-axis labels (updated)</title>
      <link>https://jcarroll.com.au/2016/06/03/images-as-x-axis-labels-updated/</link>
      <pubDate>Fri, 03 Jun 2016 08:18:26 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2016/06/03/images-as-x-axis-labels-updated/</guid>
      <description>&lt;p&gt;They say “&lt;em&gt;if you want to find an answer on the internet, just present a wrong one as fact. Then wait.&lt;/em&gt;”&lt;/p&gt;
&lt;p&gt;It didn’t take long, actually. Despite my searches while trying to get &lt;a href=&#34;https://jcarroll.com.au/2016/06/02/images-as-x-axis-labels/&#34;&gt;images into x-axis labels&lt;/a&gt; it seems I overlooked a working, &lt;a href=&#34;http://stackoverflow.com/questions/14070953/photo-alignment-with-graph-in-r/14078391&#34;&gt;significantly less hacky implementation&lt;/a&gt;. My Google-fu had in fact let me down.&lt;/p&gt;
&lt;p&gt;Baptiste Auguié (&lt;span class=&#34;citation&#34;&gt;[@tpab]&lt;/span&gt;(&lt;a href=&#34;https://twitter.com/tpab&#34; class=&#34;uri&#34;&gt;https://twitter.com/tpab&lt;/a&gt;) / &lt;span class=&#34;citation&#34;&gt;[@baptiste]&lt;/span&gt;(&lt;a href=&#34;https://github.com/baptiste&#34; class=&#34;uri&#34;&gt;https://github.com/baptiste&lt;/a&gt;)) had this working a while ago (seemingly before the &lt;code&gt;ggplot2&lt;/code&gt; update that broke other methods), and in a definitively less hacky way. I’ve added a &lt;a href=&#34;https://gist.github.com/jonocarroll/2f9490f1f5e7c82ef8b791a4b91fc9ca&#34;&gt;new gist&lt;/a&gt; (if you’re reading this on R-bloggers, the gist isn’t embedded, so either follow the link or view on my site) which implements it on the same graph as earlier, and I like this significantly more.&lt;/p&gt;
&lt;p&gt;{{% gist jonocarroll 2f9490f1f5e7c82ef8b791a4b91fc9ca %}}&lt;/p&gt;
This method gets around the &lt;code&gt;element_text()&lt;/code&gt; validation and updates the grobs in a way that’s above my pay grade/understanding of &lt;code&gt;ggplot2&lt;/code&gt; internals, and is a much more consistent way to go about it. This also:
&lt;ul&gt;
&lt;li&gt;
places the factor labels on the graph along with the picture, covering some concerns about people not knowing which maps are for which country,
&lt;/li&gt;
&lt;li&gt;
leaves room for the &lt;code&gt;caption&lt;/code&gt; to go back in, which I wanted,
&lt;/li&gt;
&lt;li&gt;
automatically scales the grob better,
&lt;/li&gt;
&lt;li&gt;
doesn’t involve creating an external &lt;code&gt;grob&lt;/code&gt; and thus turning off clipping; using &lt;code&gt;axis.text.x&lt;/code&gt; is exactly what I was hoping for.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://jcarroll.com.au/post/2016-06-03-images-as-x-axis-labels-updated_files/GDP_updated.png&#34; alt=&#34;Updated version using @baptiste’s method; much better.&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;Updated version using &lt;span class=&#34;citation&#34;&gt;@baptiste&lt;/span&gt;’s method; much better.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;My version worked (sort of) but only because it used options that were bad practice (not doubting that for a moment). I’d like to see this method make it into &lt;code&gt;ggplot2&lt;/code&gt; properly; Baptiste had an &lt;a href=&#34;https://github.com/hadley/ggplot2/issues/1240&#34;&gt;open GitHub issue&lt;/a&gt; involving it a while ago but it has since been closed, presumably without the feature being incorporated.&lt;/p&gt;
&lt;p&gt;I started the previous post by saying how awesome open-source software is (e.g. &lt;code&gt;R&lt;/code&gt;). You know what else is awesome? The #rstats community. Thank you to every one of you.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Images as x-axis labels</title>
      <link>https://jcarroll.com.au/2016/06/02/images-as-x-axis-labels/</link>
      <pubDate>Thu, 02 Jun 2016 22:42:31 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2016/06/02/images-as-x-axis-labels/</guid>
      <description>&lt;p&gt;Open-source software is awesome. If I found that a piece of closed-source software was missing a feature that I wanted, well, bad luck. I probably couldn’t even tell if was actually missing or if I just didn’t know about it. When the source is available, maintained, and documented however, things get fun. We can identify, and perhaps fill gaps.&lt;/p&gt;
&lt;p&gt;I’ve thought for a couple of projects which had bar-graphs that it would be neat to have the categories labelled by an icon or a picture. Say, the logo for a company or an illustrative example. Sure, you could fire up GIMP/Inkscape and manually insert them over the top of the text labels (each and every time you re-produce the graph… no thanks) but that’s not how I operate.&lt;/p&gt;
&lt;p&gt;There are probably very few cases for which this is technically a good idea (trying to be a featured author on &lt;a href=&#34;http://junkcharts.typepad.com/&#34;&gt;JunkCharts&lt;/a&gt; might very well be one of those reasons). Nonetheless, there are at least a couple of requests for this floating around on stackoverflow; &lt;a href=&#34;http://stackoverflow.com/questions/29939447/icons-as-x-axis-labels-in-r-ggplot2&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;http://stackoverflow.com/questions/8905101/how-can-i-use-a-graphic-imported-with-grimport-as-axis-tick-labels-in-ggplot2-u&#34;&gt;here&lt;/a&gt; for example. I struggled to find any satisfactory solutions that were in current working order (though perhaps my Google-fu has failed me).&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;http://stackoverflow.com/questions/8905101/how-can-i-use-a-graphic-imported-with-grimport-as-axis-tick-labels-in-ggplot2-u&#34;&gt;second link there&lt;/a&gt; has a working example, but the big update to &lt;code&gt;ggplot2&lt;/code&gt; breaks that pretty strongly; &lt;code&gt;opts&lt;/code&gt; was deprecated and now &lt;code&gt;element_text()&lt;/code&gt; has a gatekeeper validation routine that prevents any such messing around. The &lt;a href=&#34;http://stackoverflow.com/questions/29939447/icons-as-x-axis-labels-in-r-ggplot2&#34;&gt;first link&lt;/a&gt; however takes a different route. I couldn’t get that one to work either, but in any case the answer is a year out of date (updates in &lt;code&gt;ggplot2&lt;/code&gt; can easily have broken the &lt;code&gt;gTree&lt;/code&gt; relations), not particularly flexible, and relies on saving intermittent image files for &lt;code&gt;PostScriptTrace&lt;/code&gt; to read back in which I’m not a fan of (and couldn’t get to work anyway).&lt;/p&gt;
&lt;p&gt;I decided that I perhaps had enough ammunition to hack something together myself (emphasis on hack), and sure enough it seems to have worked (for a limited definition of “worked” with no attached or implied guarantees whatsoever).&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://jcarroll.com.au/post/2016-06-02-images-as-x-axis-labels_files/GDP.png&#34; alt=&#34;GDP per capita with flags for x-axis labels. This was harder to make than it seemed, but I’ve since added a little more flexibility to it.&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;GDP per capita with flags for x-axis labels. This was harder to make than it seemed, but I’ve since added a little more flexibility to it.&lt;/p&gt;
&lt;/div&gt;
The way to go about making your own is as follows;
&lt;ol&gt;
&lt;li&gt;
Stop and carefully re-evaluate the choices that you’ve made to bring you to this decision. Are you sure? Okay…
&lt;/li&gt;
&lt;li&gt;
Save the images (in the correct factor order) into a list (e.g. &lt;code&gt;pics&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;
Build your bar graph with categorical x-axis as per normal, using &lt;code&gt;theme()&lt;/code&gt; to remove the labels. Save as an object (e.g. &lt;code&gt;g&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;
Source the function &lt;a href=&#34;https://gist.github.com/jonocarroll/1d1bdb00a7b3910d62bf3eec8a77b4a7&#34;&gt;from this gist&lt;/a&gt; (at your own risk… copy and paste if you prefer):
&lt;/li&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;devtools::source_gist(&amp;quot;1d1bdb00a7b3910d62bf3eec8a77b4a7&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;script src=&#34;https://gist.github.com/jonocarroll/1d1bdb00a7b3910d62bf3eec8a77b4a7.js&#34;&gt;&lt;/script&gt;
&lt;li&gt;
Call (or pipe your &lt;code&gt;ggplot&lt;/code&gt; object to) the function:
&lt;/li&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;g %&amp;gt;% add_images_as_xlabels(pics)

## or

add_images_as_xlabels(g, pics)&lt;/code&gt;&lt;/pre&gt;
&lt;li&gt;
Your image will be re-drawn with your pictures labelling the categories.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here’s an example of the code used to generate the GDP per capita image, featuring some fairly brief (for what it does) &lt;code&gt;rvest&lt;/code&gt; scraping (to reiterate; I don’t want to have to do any of this by hand, so let’s code it up!).&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/jonocarroll/96d1dd879b535c3c7ffe8f74065d4bc4.js&#34;&gt;&lt;/script&gt;
At least a few caveats surround what I did manage to get working, including but not limited to:
&lt;ul&gt;
&lt;li&gt;
I’m not sure how to put the x-axis title back in at the right position without padding it with a lot of linebreaks (&lt;code&gt;&amp;quot;\n\n\n\nX-AXIS TITLE&amp;quot;&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;
I’m not sure how to move the &lt;code&gt;caption&lt;/code&gt; line from &lt;code&gt;labs()&lt;/code&gt; (assuming you’re using the development version of &lt;code&gt;ggplot2&lt;/code&gt; on GitHub with &lt;span class=&#34;citation&#34;&gt;@hrbrmstr&lt;/span&gt;’s excellent annotation additions) so it potentially gets drawn over.
&lt;/li&gt;
&lt;li&gt;
The spacing below the graph is currently arbitrarily set to a few lines more than necessary, but it’s a compromise in having an arbitrary number of images loaded at their correct sizes.
&lt;/li&gt;
&lt;li&gt;
Similarly, I’ve just expanded the plot range of the original graph by a seemingly okay amount which has worked for the few examples I’ve tried.
&lt;/li&gt;
&lt;li&gt;
Using a graph like this places the onus of domain knowledge onto the reader; if you don’t know what those flags refer to then this graph is less useful than one with the countries labelled with words. Prettier though.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ve no doubt that there must be a better way to do this, but it’s beyond my understanding of how &lt;code&gt;ggproto&lt;/code&gt; works, and I can’t seem to bypass &lt;code&gt;element_text&lt;/code&gt;’s requirements with what I do know. If you would like to help develop this into something more robust then I’m most interested. Given that it’s a single function I wasn’t going to create a package just for this, but I’m willing to help incorporate it into someone’s existing package. Hit the comments or ping me on Twitter (&lt;span class=&#34;citation&#34;&gt;[@carroll_jono]&lt;/span&gt;(&lt;a href=&#34;https://twitter.com/carroll_jono&#34; class=&#34;uri&#34;&gt;https://twitter.com/carroll_jono&lt;/a&gt;))!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>From a (set.)seed grows a mighty dataset</title>
      <link>https://jcarroll.com.au/2016/05/30/seed/</link>
      <pubDate>Mon, 30 May 2016 21:35:26 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2016/05/30/seed/</guid>
      <description>&lt;p&gt;Can you predict the output from this code?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;printStr &amp;lt;- function(str) paste(str, collapse=&amp;quot;&amp;quot;)

set.seed(12173423); x &amp;lt;- sample(LETTERS, 5, replace=TRUE)
set.seed(7723132);y &amp;lt;- sample(LETTERS, 5, replace=TRUE)

paste(printStr(x), printStr(y))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, the first bit is straightforward; it’s a function that puts two string together into one. The next two lines appear to provide a random integer to the &lt;code&gt;set.seed&lt;/code&gt; function then sample the pool of &lt;code&gt;LETTERS&lt;/code&gt; 5 times with replacement. The last line uses the function from the first line to combine those samples of letters together into one string. Easy enough. Looks like it will produce a random string. Give it a try… go on, the seeds should make it reproducible.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;[1] &amp;quot;HELLO WORLD&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whoa! What are the odds of that!?! Of all the possible letters we could have sampled, we get that!&lt;/p&gt;
&lt;p&gt;Okay, yes, it’s rigged. Pretty neat choice of values for &lt;code&gt;set.seed&lt;/code&gt; there, right? I came across the &lt;a href=&#34;http://stackoverflow.com/questions/15182496/why-does-this-code-using-random-strings-print-hello-world&#34;&gt;Java variant of this&lt;/a&gt; via StackOverflow’s ‘Hot Network Questions’ sidebar (a rabbit-hole equal in depth to a Wikipedia &lt;a href=&#34;http://www.urbandictionary.com/define.php?term=wiki-hole&#34;&gt;wiki-hole&lt;/a&gt;). The seeds just happen to be ones that when sampled 5 times with replacement produce the right values to extract those letters in order. That seems simple enough until you want to find them.&lt;/p&gt;
&lt;div id=&#34;update-2019-with-r-3.6-the-random-number-generator-rng-has-been-updated-to-avoid-a-particular-bug-the-result-of-which-is-that-this-entire-process-will-be-invalid-for-that-r-version.-this-will-still-work-as-advertised-in-versions-prior-to-3.6-but-the-same-seed-will-produce-different-strings-in-3.6-and-above.&#34; class=&#34;section level4&#34;&gt;
&lt;h4&gt;Update (2019): &lt;strong&gt;With R 3.6 the random number generator (RNG) has been updated to avoid a particular bug, the result of which is that this entire process will be invalid for that R version. This will still work as advertised in versions prior to 3.6, but the same seed will produce different strings in 3.6 and above.&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;The possible combinations of 5 letters, chosen with replacement, from the pool of 26 is &lt;span class=&#34;math inline&#34;&gt;\(26^5\)&lt;/span&gt; which is a lot, but not insanely many. I work with multi-million row datasets frequently enough. So, we could just run a loop over all integers (&lt;code&gt;set.seed&lt;/code&gt; rounds to nearest integer anyway; refer to &lt;code&gt;?set.seed&lt;/code&gt;), set the seed to that value, and save the sampled letters. The first combination will be&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;set.seed(1L)
sample(LETTERS, 5, replace=TRUE)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;G&amp;quot; &amp;quot;J&amp;quot; &amp;quot;O&amp;quot; &amp;quot;X&amp;quot; &amp;quot;F&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, we write a loop and iterate over the seed, saving the outputs. But wait, you may wonder, what’s to guarantee that we don’t get the same sample twice? Nothing. It’s a random sample starting from a different seed every time; there’s no control over the results after the fact. A quick check confirms this; here’s a duplicate of the first record appearing at seed 3415066L&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;set.seed(1L);sample1 &amp;lt;- sample(LETTERS, 5, replace=TRUE)
set.seed(3415066L); sample2 &amp;lt;- sample(LETTERS, 5, replace=TRUE)
identical(sample1, sample2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, &lt;code&gt;set.seed(1L)&lt;/code&gt; produces the same 5 letter sample as &lt;code&gt;set.seed(3415066L)&lt;/code&gt;. There’s definitely duplicates of other combinations between those two too. Okay, so we’re not going to be limited to &lt;span class=&#34;math inline&#34;&gt;\(26^5\)&lt;/span&gt;. How many though? Who knows? What’s the distribution of duplication? Without knowing how many we need to try for, we can take the upper limit and go for that; on my machine I get&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;.Machine$integer.max&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 2147483647&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is certainly a bigger number, but not out of the realm of possibility.&lt;/p&gt;
&lt;p&gt;To make life easier, we can split the problem up. It’s “embarrassingly parallel” (each iteration is completely independent of the others) so it’s perfect for parallelisation. If you haven’t read &lt;a href=&#34;https://wrathematics.github.io/&#34;&gt;Drew Schmidt a.k.a wrathematics’&lt;/a&gt; &lt;a href=&#34;https://wrathematics.github.io/RparallelGuide/&#34;&gt;semi-NSFW guide to Parallelism, R, and OpenMP&lt;/a&gt; then stop reading this and go read that.&lt;/p&gt;
&lt;p&gt;You’re back, great. Let’s assume for now that you too have access to a big, fast computer and want to parallelise the loop over all positive integers. If you’re lucky, it’s as easy as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(parallel)
cl &amp;lt;-
  makeCluster(7) ## 8-core machine, leave one out to remain stable
clusterApply(cl, seq(1, (.Machine$integer.max - 1), 1e7), function(x) {
  wordvec &amp;lt;- data.frame(word = character(1e7L), seed = integer(1e7L))
  for (iloop in 1:(1e7)) {
    iseed &amp;lt;- x + iloop - 1
    if (abs(iseed) &amp;lt; .Machine$integer.max) {
      set.seed(iseed)
      wordvec[iloop, &amp;quot;word&amp;quot;] &amp;lt;-
        paste0(LETTERS[sample(26, 5, replace = TRUE)], collapse = &amp;quot;&amp;quot;)
      wordvec[iloop, &amp;quot;word&amp;quot;] &amp;lt;- iseed
    }
  }
  write.csv(wordvec, file = paste0(&amp;quot;seeded_words_&amp;quot;, as.character(x), &amp;quot;.csv&amp;quot;))
}
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but life’s not that easy. This is slow as a week of Mondays. For starters, updating the &lt;code&gt;data.frame&lt;/code&gt; this many times will probably exhaust your RAM. This was run on a machine with 32GB available, and it got full, fast. Writing out large &lt;code&gt;.csv&lt;/code&gt; files is slow, and given that each of them has ten million rows, the 215 files aren’t particularly small; there are a lot of duplicate entries.&lt;/p&gt;
&lt;p&gt;We can make this better with a few adjustments;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(parallel)
cl &amp;lt;-
  makeCluster(7) ## 8-core machine, leave one out to remain stable
clusterApply(cl, seq(1, (.Machine$integer.max - 1), 1e7), function(x) {
  library(data.table)
  wordvec &amp;lt;- data.table(word = character(1e7L), seed = integer(1e7L))
  for (iloop in 1:(1e7)) {
    iseed &amp;lt;- x + iloop - 1
    if (abs(iseed) &amp;lt; .Machine$integer.max) {
      set.seed(iseed)
      set(
        wordvec,
        i = iloop,
        j = &amp;quot;word&amp;quot;,
        value = paste0(LETTERS[sample(26, 5, replace = TRUE)], collapse = &amp;quot;&amp;quot;)
      )
      set(wordvec,
          i = iloop,
          j = &amp;quot;seed&amp;quot;,
          value = iseed)
    }
  }
  unique_wordvec &amp;lt;- unique(wordvec, by = &amp;quot;word&amp;quot;)
  save(unique_wordvec,
       file = paste0(&amp;quot;seeded_words_&amp;quot;, as.character(x), &amp;quot;.rds&amp;quot;))
}
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using &lt;code&gt;data.table&lt;/code&gt; means that the &lt;code&gt;set()&lt;/code&gt; operations &lt;a href=&#34;https://gist.github.com/jonocarroll/a738212afde6394b4f251c7cac7f3348&#34;&gt;are all in-memory&lt;/a&gt; and this alone speeds up the loops. Removing duplicates using &lt;code&gt;unique&lt;/code&gt; (now dispatched for &lt;code&gt;data.table&lt;/code&gt;) and saving as a compressed binary &lt;code&gt;.rds&lt;/code&gt; file makes this a little less bulky. All in all, this can be completed in a few hours on a decent enough machine. I did try using &lt;a href=&#34;https://cran.r-project.org/web/packages/feather/index.html&#34;&gt;feather&lt;/a&gt; for the saving of files and my early tests using smaller subsets showed it to be amazingly fast. Unfortunately there are still some bugs to be ironed out of that package for large files/lots of rows, and my 215 files ended up small, but unreadable.&lt;/p&gt;
&lt;p&gt;Given that there’s only &lt;span class=&#34;math inline&#34;&gt;\(26^5 = 11881376\)&lt;/span&gt; combinations that we’re looking for, depending on how often duplicates come up, we probably don’t need all the results. I’ll save you the trouble and let you know that the loop only needs to go up to at most, &lt;code&gt;113449118&lt;/code&gt;. Reading all of the files back in and merging them again requires some careful considerations. &lt;code&gt;R&lt;/code&gt; isn’t too keen on creating objects larger than 2GB, so we can’t really just merge 113449118 lines of data. Taking it step-wise, I managed to get it to work&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(data.table)
library(dplyr)
load(&amp;quot;seeded_words_1.rds&amp;quot;) ## load the first file
bigdf &amp;lt;-
  unique_wordvec## objects were saved as unique_wordvec so save ## to a new name to avoid overwriting
rm(unique_wordvec)## then drop the saved version

allfiles &amp;lt;- list.files(pattern = &amp;quot;01.rds&amp;quot;)

## files were saved as &amp;#39;seeded_words_X.rds&amp;#39; where x was steps of 1e7
## sorting alphabetically gives the wrong order
for (file in allfiles[order(as.numeric(sub(&amp;quot;\\.rds&amp;quot;, &amp;quot;&amp;quot;, sub(
  &amp;quot;[a-z_]*&amp;quot;, &amp;quot;&amp;quot;, allfiles
))))]) {
  cat(paste0(&amp;quot;** Processing file &amp;quot;, file, &amp;quot;\n&amp;quot;)) ## show notifications on the screen
  load(file)
  bigdf &amp;lt;-
    unique(data.table(bind_rows(bigdf, unique_wordvec)), by = &amp;quot;word&amp;quot;) ## drop duplicates as we go
  rm(unique_wordvec)
  if (nrow(bigdf) &amp;amp;
      amp
      gt
      = 26 ^ 5) {
    cat(paste0(&amp;quot;** Processing OUTPUT file.\n&amp;quot;))
    save(bigdf, file = &amp;quot;all_seeded_words.rds&amp;quot;)
    stop()
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This results in a 75MB &lt;code&gt;.rds&lt;/code&gt; of all unique combinations of 5 letters sampled with replacement, and the seed that generates them. Not particularly share-able or convenient. We’re mainly interested in actual words. We can filter this list down to English words if we can think of some way to do that (with the associated assumptions and limitations that may bring). Here’s one &lt;code&gt;R&lt;/code&gt; option:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ScrabbleScore)
words &amp;lt;- bigdf[is.twl06.word(bigdf$word), ]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This filters the generated 5-letter words against a &lt;a href=&#34;https://en.wikipedia.org/wiki/Official_Tournament_and_Club_Word_List&#34;&gt;Scrabble Official Tournament and Club Word List&lt;/a&gt; which is as close as I can be bothered getting to ‘English’ words. What’s left is a list of &lt;code&gt;8938&lt;/code&gt; 5-letter words with their associated generating seeds. Sure enough, filtering the &lt;code&gt;twl06&lt;/code&gt; wordlist down to the 5-letter words gives exactly that many; we’ve generated all the 5-letter words in that data set. Cool. What were we hoping to do with it? Oh, right.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;print(words[&amp;quot;HELLO&amp;quot;])
#&amp;gt; 1: HELLO 12173423
print(words[&amp;quot;WORLD&amp;quot;])
#&amp;gt; 1: WORLD 7723132&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There we go, the seeds used in the original question for this post. If we wanted, we could write other words or phrases in this way.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;set.seed(5360994); x &amp;lt;- sample(LETTERS, 5, replace=TRUE)
set.seed(21732771); y &amp;lt;- sample(LETTERS, 5, replace=TRUE)

paste(printStr(x), printStr(y))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;STATS RULES&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We might be interested in what the distribution of unique, English words looks like. Here you go;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)
gg &amp;lt;- ggplot(words, aes(x=seq_along(seed), y=seed)) gg &amp;lt;- gg + geom_point(alpha=0.6, col=&amp;quot;steelblue1&amp;quot;, pch=20, size=2) gg &amp;lt;- gg + theme_bw()
gg &amp;lt;- gg + labs(title=&amp;quot;Seed that generates unique, English words&amp;quot;, subtitle=&amp;quot;Filtered as valid Scrabble TW06 words&amp;quot;,
caption=&amp;quot;https://en.wikipedia.org/wiki/Official_Tournament_and_Club_Word_List&amp;quot;,
x=&amp;quot;Index&amp;quot;,
y=&amp;quot;Seed&amp;quot;)
gg&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ve converted that using the excellent &lt;a href=&#34;https://plot.ly/ggplot2/&#34;&gt;&lt;code&gt;plotly::ggplotly()&lt;/code&gt; function&lt;/a&gt; so you can mouseover each point to see the corresponding word.&lt;/p&gt;
&lt;iframe width=&#34;600&#34; height=&#34;800&#34; frameborder=&#34;0&#34; scrolling=&#34;no&#34; src=&#34;https://plot.ly/~jonocarroll/4.embed&#34;&gt;
&lt;/iframe&gt;
&lt;p&gt;Fairly uniform looking in that plot. How about the density?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)
gv &amp;lt;- ggplot(words, aes(x=factor(0), y=seed)) gv &amp;lt;- gv + geom_violin(fill=&amp;quot;steelblue1&amp;quot;) gv &amp;lt;- gv + theme_bw()
gv &amp;lt;- gv + theme(axis.title.x=element_blank(),
axis.text.x=element_blank(),
axis.ticks.x=element_blank())
gv &amp;lt;- gv + labs(title=&amp;quot;Violin plot of seed that generates unique, English words&amp;quot;, subtitle=&amp;quot;Filtered as valid Scrabble TW06 words&amp;quot;,
caption=&amp;quot;https://en.wikipedia.org/wiki/Official_Tournament_and_Club_Word_List&amp;quot;,
y=&amp;quot;Seed&amp;quot;)
gv&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2016-05-30-seed_files/violinplot-1.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;which looks pretty nicely vanishing as more duplicates are produced.&lt;/p&gt;
&lt;p&gt;Finally, what about the distribution by starting letter?&lt;/p&gt;
&lt;iframe width=&#34;600&#34; height=&#34;800&#34; frameborder=&#34;0&#34; scrolling=&#34;no&#34; src=&#34;https://plot.ly/~jonocarroll/2.embed&#34;&gt;
&lt;/iframe&gt;
&lt;p&gt;Unsurprisingly; not many words starting with “X” (13) and lots starting with “S” (1084). The last word produced (the one with the largest unique seed before we run out of unique words) is “HUTCH” at 113449118.&lt;/p&gt;
&lt;p&gt;Can we do anything else with this? The first thing that comes to mind is using this to encode a message. This method is reminiscent of a hash function; it takes some data and via a 1-way mechanism, produces an encoded message. Of course, the 1-way nature of this takes a word and encodes it to an integer that can’t be easily predicted, so hopefully your message is all integers. Many reasons make this a bad idea to actually use for this purpose. The first being that in the world of digital security, if you’re thinking of rolling your own, you’re setting yourself up for trouble. Much smarter people than you or I have spent a lot of time getting digital security right, and it still isn’t.&lt;/p&gt;
&lt;p&gt;As for actual technical issues, the obvious one is that it can be brute-forced (as we just showed) easily. I produced the list of all 5-letter combinations produced from all possible integers in a few hours. Modern GPU processing can perform many millions of these calculations per second. Another technical fault of this would be that collisions are all too easy, as demonstrated by our duplicates. A good encoding should only generate the hashed value from the input, not any other input. &lt;a href=&#34;http://www.mathstat.dal.ca/~selinger/md5collision/&#34;&gt;MD5 has this flaw&lt;/a&gt;. If you were to try and use this encoding to validate a message (say, the integer represents a checksum of the message contents, encoded as a difficult to predict word) then it would be far too easy for a malicious entity to produce the same word from their own message padded out with junk data.&lt;/p&gt;
&lt;p&gt;So, not very useful for encryption/hashing (not that it should be). I don’t really have a useful application for this apart from the riddle at the start of this post, but it’s been an interesting journey through optimisation, parallelisation, filtering, and file input/output. I’d say that has made it worthwhile enough.&lt;/p&gt;
&lt;p&gt;The data file of valid Scrabble words can be &lt;a href=&#34;https://github.com/jonocarroll/wp_content/raw/master/_data/scrabble_words.rds&#34;&gt;downloaded here&lt;/a&gt; if you’d like it. I’ll gladly provide the full 5-letter list on request.&lt;/p&gt;
&lt;p&gt;I’m not a data-security expert so any and all of my advice there is liable to be rubbish. Do you know a better way to generate this data, or an aspect I haven’t considered? Hit the comments and let me know.&lt;/p&gt;
&lt;p&gt;Title image: &lt;a href=&#34;https://www.flickr.com/photos/usdagov/16024807396/&#34;&gt;CC-BY U.S. Department of Agriculture&lt;/a&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  colorspace    1.4-1   2019-03-18 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.1.0   2019-07-06 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  dplyr         0.8.3   2019-07-04 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  ggplot2     * 3.2.1   2019-08-10 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  gtable        0.3.0   2019-03-25 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  knitr         1.24    2019-08-08 [1] CRAN (R 3.5.2)                   
##  lazyeval      0.2.2   2019-03-15 [1] CRAN (R 3.5.2)                   
##  magrittr    * 1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  munsell       0.5.0   2018-06-12 [1] CRAN (R 3.5.1)                   
##  pillar        1.4.2   2019-06-29 [1] CRAN (R 3.5.2)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgconfig     2.0.2   2018-08-16 [1] CRAN (R 3.5.1)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  purrr         0.3.2   2019-03-15 [1] CRAN (R 3.5.2)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  scales        1.0.0   2018-08-09 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  tibble        2.1.3   2019-06-06 [1] CRAN (R 3.5.2)                   
##  tidyselect    0.2.5   2018-10-11 [1] CRAN (R 3.5.1)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Bad Neighbours (no, not the movie)</title>
      <link>https://jcarroll.com.au/2016/04/30/bad-neighbours/</link>
      <pubDate>Sat, 30 Apr 2016 01:06:29 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2016/04/30/bad-neighbours/</guid>
      <description>&lt;p&gt;Another day, another compulsion to see if I can do any better than someone’s solution.&lt;/p&gt;
&lt;p&gt;This one also comes from the &lt;a href=&#34;http://fivethirtyeight.com/features/can-you-solve-the-puzzle-of-your-misanthropic-neighbors/&#34;&gt;FiveThiryEight Puzzler challenge&lt;/a&gt; courtesy of &lt;a href=&#34;https://xianblog.wordpress.com/2016/04/29/gap-frequencies/&#34;&gt;Xi’an&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The original challenge this time was&lt;/p&gt;
&lt;blockquote&gt;
The misanthropes are coming. Suppose there is a row of some number, N, of houses in a new, initially empty development. Misanthropes are moving into the development one at a time and selecting a house at random from those that have nobody in them and nobody living next door. They keep on coming until no acceptable houses remain. At most, one out of two houses will be occupied; at least one out of three houses will be. But what’s the expected fraction of occupied houses as the development gets larger, that is, as N goes to infinity?
&lt;/blockquote&gt;
&lt;p&gt;which seems straightforward enough. Xi’an has a nice writeup of the analytical solution (which looks pretty well thought out) but that’s not what caught my attention. The (probably not intentionally provocative) statements&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A riddle from The Riddler where brute-force simulation does not pay:&lt;/p&gt;
Hence this limits the realisation of simulation to, say, N=10&lt;sup&gt;4&lt;/sup&gt;
&lt;/blockquote&gt;
&lt;p&gt;however, are like a red flag to a bull for me. The code provided for Xi’an’s solution isn’t optimised, and doesn’t take advantage of some potential speed-ups. 10,000 iterations seems like it should be quick. There’s also a typo in the &lt;code&gt;microbenchmark&lt;/code&gt; code there; &lt;code&gt;time&lt;/code&gt; should be &lt;code&gt;times&lt;/code&gt; otherwise it’s passed as a lambda function evaluating &lt;code&gt;time=10&lt;/code&gt;. Anyway, improvements to the code can be made.&lt;/p&gt;
&lt;p&gt;I took a slightly different approach; I assigned a vector of ‘houses’ being either occupied or available, identified as such by a boolean (&lt;code&gt;TRUE&lt;/code&gt;/&lt;code&gt;FALSE&lt;/code&gt;). For the purposes of this question, available means that there is a) no occupant; b) no occupant on either side. The function I ended up with was&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;misanthropist &amp;lt;- function(N) {
  
  occupied   &amp;lt;- rep(FALSE, N)
  acceptable &amp;lt;- rep(TRUE, N)
  
  while(any(acceptable)) {
    possible &amp;lt;- .Internal(which(acceptable))
    occupied[movedin &amp;lt;- possible[.Internal(sample(length(possible), 1, FALSE, NULL))]] &amp;lt;- TRUE
    acceptable[c(movedin-1, movedin, movedin+1)] &amp;lt;- FALSE
  }
  
  return(mean(occupied))
}

library(compiler)
misanthropist_c &amp;lt;- cmpfun(misanthropist)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are a heap of tricks employed here to speed evaluation up, and a few that aren’t because it turns out they didn’t perform better.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
the &lt;code&gt;acceptable&lt;/code&gt; vector is populated independently of the &lt;code&gt;occupied&lt;/code&gt; vector; &lt;code&gt;acceptable = ! occupied&lt;/code&gt; seemed like it was a contender but ended up being slower.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;any(acceptable)&lt;/code&gt; works faster than &lt;code&gt;sum(acceptable)&amp;gt;0&lt;/code&gt; in the &lt;code&gt;while&lt;/code&gt; loop, presumably because of short-circuiting (we only need to know that one is &lt;code&gt;TRUE&lt;/code&gt;, at which point we don’t need to keep testing).
&lt;/li&gt;
&lt;li&gt;
I’ve used &lt;code&gt;.Internal&lt;/code&gt; calls where possible (&lt;code&gt;which&lt;/code&gt;, &lt;code&gt;sample&lt;/code&gt;); this removes a tiny bit of overhead.
&lt;/li&gt;
&lt;li&gt;
the switching of &lt;code&gt;acceptable&lt;/code&gt; to &lt;code&gt;FALSE&lt;/code&gt; for the newly occupied house and those on either side can be done in a single step via a &lt;code&gt;c()&lt;/code&gt; subsetting. Originally I had coded around the potential issues of trying to set &lt;code&gt;acceptable[0]&lt;/code&gt; or &lt;code&gt;acceptable[N+1]&lt;/code&gt; when their neighbours moved in, but as it turns out, R is happy to silently assign beyond the bounds of that vector and move on, so no more checks needed.
&lt;/li&gt;
&lt;li&gt;
the proportion of occupied houses is easily calculated at the end given that &lt;code&gt;as.integer(TRUE)==1&lt;/code&gt; and &lt;code&gt;as.integer(FALSE)==0&lt;/code&gt;, so the mean of the boolean vector is the proportion of &lt;code&gt;TRUE&lt;/code&gt; values.
&lt;/li&gt;
&lt;li&gt;
finally, I’ve byte-compiled the function with &lt;code&gt;compiler::cmpfun&lt;/code&gt;. Built-in functions in &lt;code&gt;base&lt;/code&gt; are already byte-compiled, and this helps just a little bit more.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Back to the original question; how many iterations can we do? First, let’s compare what we’ve got so far with a reasonable number of iterations&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;gt; microbenchmark(frqns(1000L), misanthropist_c(1000L), times=3, unit=&amp;quot;ms&amp;quot;)
Unit: milliseconds
                   expr         min          lq        mean      median          uq         max neval
           frqns(1000L) 3600.981381 3601.460353 3655.512618 3601.939325 3682.778237 3763.617149     3
 misanthropist_c(1000L)    3.447858    3.470277    3.512251    3.492697    3.544448    3.596199     3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Uh, yep. That’s, just a little bit faster. Smidgen. 3.5ms/1000 iterations. What about a few more iterations on my optimised function? How about that 10,000 limit?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;gt; microbenchmark(misanthropist_c(10000L), times=3, unit=&amp;quot;ms&amp;quot;)
Unit: milliseconds
                    expr      min       lq     mean   median       uq      max neval
 misanthropist_c(10000L) 194.0501 194.8379 198.7545 195.6258 201.1066 206.5875     3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Maybe we shouldn’t get too cocky. 10 times as many iterations takes 56 times longer.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;gt; microbenchmark(misanthropist_c(100000L), times=3, unit=&amp;quot;ms&amp;quot;)
Unit: milliseconds
                     expr      min       lq    mean  median       uq      max neval
 misanthropist_c(100000L) 18260.85 18355.87 18422.4 18450.9 18503.18 18555.47     3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That brings us up to 184ms/1000 iterations. 10 times as many iterations again takes 92 times longer. It’s definitely slowing down.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2016-04-30-bad-neighbours_files/log10log10.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;On a log-log plot of time against iterations with a slope of 2, it’s clearer that the problem scales as &lt;span class=&#34;math inline&#34;&gt;\(\mathcal{O}(n^2)\)&lt;/span&gt;. That suggests that we should be able to complete the 1,000,000 iteration evaluation in about 20 minutes. 2,000,000 iterations in around 1 hour 20 minutes. 3,000,000 in 3 hours. Where am I going with this you ask? Xi’an requested help from &lt;a href=&#34;http://math.stackexchange.com/questions/1758065/limit-of-recursive-sequence-n2q-n-1n-12q-n-12n-2q-n-2&#34;&gt;stackexchange&lt;/a&gt; (a great move which paid off well) to get the analytical solution to the problem. If you check the timestamps, you’ll notice&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# asked    Apr 25 at 14:04
# answered Apr 25 at 16:25&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, let’s say that stackexchange was offline when you were impatiently working on a solution, you coded perfectly and knew how to optimise your functions. How close to the right answer can you get in this amount of time (2.5 hours). We can probably do at most 2,000,000 iterations. Does that reach a close-enough solution? Rather than making my code run for that long, let’s see if Xi’an’s recursive equation gets the same answer (obviously faster).&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;xian &amp;lt;- function(N) {
  a=b=1
  for (n in 3:N){ C=(1+2*a+(n-1)*b)/n;a=b;b=C}
  return(C/N)
}

xian1e5 &amp;lt;- xian(1e5L)
mine1e5 &amp;lt;- misanthropist_c(1e5L)
format(2*100*(xian1e5 - mine1e5)/(xian1e5 + mine1e5), digits=3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;-0.0335&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so off by 0.07% at that stage, presumably getting closer with more iterations. Let’s use the recursive equation for this next bit then, knowing that in the above scenario we would be using the full iterative approach. The recursive expression itself can also be optimised. I did re-write it in C (&lt;code&gt;xian_c&lt;/code&gt;) to see if that helped, but &lt;code&gt;compiler:cmpfun&lt;/code&gt; (as &lt;code&gt;xian_c2&lt;/code&gt;) does just as good a job (as one might expect)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;&amp;gt; microbenchmark(xian(1e7), xian_c(1e7), xian_c2(1e7), times=5, unit=&amp;amp;quot;ms&amp;amp;quot;)
Unit: milliseconds
           expr        min         lq       mean     median         uq        max neval
 xian(1e+07)    16881.8007 16920.1492 16935.2306 16931.9014 16963.9973 16978.3044     5
 xian_c(1e+07)    114.8676   115.0287   115.0771   115.0948   115.1507   115.2438     5
 xian_c2(1e+07)   114.8645   114.9419   116.2547   114.9835   117.2379   119.2454     5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so clearly some improvements can be made. This one scales much better with iterations, to the point that I can just max it out&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;.Machine$integer.max
# 2147483647
format(xian_c(.Machine$integer.max), digits=20)
                  # 0.43233235833753796973
0.5*(1-exp(-2))   # 0.43233235838169364884&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So now we have an upper limit on precision. We’ll be able to get at best within 0.0000000102% of the exact answer.&lt;/p&gt;
&lt;p&gt;If I repeatedly use the &lt;code&gt;xian_c&lt;/code&gt; function with different numbers of iterations, we can see how well we should expect to do&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2016-04-30-bad-neighbours_files/pcerror-1.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Is 2e-5% close enough for a couple of hours work?&lt;/p&gt;
&lt;p&gt;And there we have it. If we’d been stuck with the non-recursive method and needed to get as close to the right answer as possible in a comparable time to obtaining the analytic solution and coding/running it, we could get pretty darn close. I’d say the brute-force method lives to see another day! … provided you do a bit of optimising and don’t mind worrying about the &lt;a href=&#34;https://en.wikipedia.org/wiki/Halting_problem&#34;&gt;Halting problem&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Did I miss an important optimisation? Know a better approach? Hit the comments and let me know!&lt;/p&gt;
&lt;p&gt;Title image © Copyright &lt;a title=&#34;View profile&#34; href=&#34;http://www.geograph.org.uk/profile/39302&#34; xmlns:cc=&#34;http://creativecommons.org/ns#&#34; property=&#34;cc:attributionName&#34; rel=&#34;cc:attributionURL dct:creator&#34;&gt;Jaggery&lt;/a&gt; and licensed for &lt;a href=&#34;http://www.geograph.org.uk/reuse.php?id=3025760&#34;&gt;reuse&lt;/a&gt; under this &lt;a rel=&#34;license&#34; href=&#34;http://creativecommons.org/licenses/by-sa/2.0/&#34; class=&#34;nowrap&#34; about=&#34;http://s0.geograph.org.uk/geophotos/03/02/57/3025760_8ad38adb.jpg&#34; title=&#34;Creative Commons Attribution-Share Alike 2.0 Licence&#34;&gt;Creative Commons Licence&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.1.0   2019-07-06 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  knitr         1.24    2019-08-08 [1] CRAN (R 3.5.2)                   
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Solving Inequality (the math kind)</title>
      <link>https://jcarroll.com.au/2016/04/27/solving-inequality-the-math-kind/</link>
      <pubDate>Wed, 27 Apr 2016 22:47:55 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2016/04/27/solving-inequality-the-math-kind/</guid>
      <description>


&lt;p&gt;&lt;a href=&#34;https://xianblog.wordpress.com/2016/04/21/an-integer-programming-riddle/&#34;&gt;This neat approach&lt;/a&gt; showed up recently as an answer to a &lt;a href=&#34;http://fivethirtyeight.com/features/you-have-1-billion-to-win-a-space-race-go/&#34;&gt;FiveThirtyEight puzzle&lt;/a&gt; and of course I couldn’t help but throw it at &lt;code&gt;dplyr&lt;/code&gt; as soon as I could. Turns out that’s not a terrible idea. The question posed is&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;optimise&lt;/p&gt;
&lt;p&gt;200a + 100b + 50c + 25d&lt;/p&gt;
&lt;p&gt;under the constraints&lt;/p&gt;
&lt;p&gt;400a + 400b + 150c + 50d ≤ 1000,
b ≤ a,
a ≤ 1,
c ≤ 8,
d ≤ 4,&lt;/p&gt;
and (a,b,c,d) all non-negative integers.
&lt;/blockquote&gt;
&lt;p&gt;Leaving aside any interpretations of wording of the original question (let’s just start with trying to solve &lt;em&gt;this&lt;/em&gt; system of inequalities) &lt;a href=&#34;https://xianblog.wordpress.com/2016/04/21/an-integer-programming-riddle/&#34;&gt;the solution provided used 4 nested loops&lt;/a&gt;, which can definitely be avoided.&lt;/p&gt;
&lt;p&gt;My approach was to create all possible combinations of the 4 variables (within the given constraints), filter out the ones that don’t meet the constraint criteria, then sort by the evaluating expression to find which one does best.&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/jonocarroll/65315f0dc1061bd2fafa7607abbc3145.js?file=inequality_1.R&#34;&gt;&lt;/script&gt;
&lt;p&gt;I’m not suggesting that this is by any means always the best approach, but when the phase-space of possible solutions is so low (especially combinations of small integers) then this is pretty tidy (technically a single &lt;code&gt;dplyr&lt;/code&gt; chain).&lt;/p&gt;
&lt;p&gt;Alternatively, one could set this up as an equation and use a linear solver. In that case, we want to optimise &lt;span class=&#34;math inline&#34;&gt;\(\max(\|A x\|)\)&lt;/span&gt; subject to the constraints &lt;span class=&#34;math inline&#34;&gt;\(G x \ge h\)&lt;/span&gt; where &lt;span class=&#34;math inline&#34;&gt;\(A\)&lt;/span&gt; and &lt;span class=&#34;math inline&#34;&gt;\(x\)&lt;/span&gt; represent the coefficients and variables to be optimised, &lt;span class=&#34;math inline&#34;&gt;\(h\)&lt;/span&gt; the constraint vector, and &lt;span class=&#34;math inline&#34;&gt;\(G\)&lt;/span&gt; a matrix of coefficients for the constraints. For the system we’re looking at, that matrix inequality looks like this&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[ \left[\begin{array}{cccc}400 &amp;amp; 400 &amp;amp; 150 &amp;amp; 50 \\1 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 \\0 &amp;amp; 1 &amp;amp; 0 &amp;amp; 0 \\0 &amp;amp; 0 &amp;amp; 1 &amp;amp; 0 \\0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1\end{array}\right] \left[\begin{array}{c}a \\ b \\ c \\ d\end{array}\right] \le \left[\begin{array}{c}1000 \\ 1 \\ 1 \\ 8 \\ 4\end{array}\right]\ . \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Of course, the constraint that &lt;span class=&#34;math inline&#34;&gt;\(b \le a\)&lt;/span&gt; needs to be checked after the fact.&lt;/p&gt;
&lt;p&gt;Programming this is fairly straightforward, even with the constraint that these are integer solutions. &lt;a href=&#34;http://www.inside-r.org/packages/cran/limSolve/docs/linp&#34;&gt;&lt;code&gt;limSolve::linp&lt;/code&gt;&lt;/a&gt; is made for exactly these types of problems.&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/jonocarroll/65315f0dc1061bd2fafa7607abbc3145.js?file=inequality_2.R&#34;&gt;&lt;/script&gt;
&lt;p&gt;which results in the same answer as our manual brute-force search.&lt;/p&gt;
&lt;p&gt;One last thing to try is to plot the solution space and see how it looks. Sounds like a good opportunity to try out &lt;a href=&#34;https://plot.ly/&#34;&gt;plotly&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since this is technically a 5D plot (4 variables and a value) it’s a little difficult to visualise. I’ve reduced the dimensionality by treating each unique combination of &lt;span class=&#34;math inline&#34;&gt;\(a \le 1\)&lt;/span&gt; and &lt;span class=&#34;math inline&#34;&gt;\(b \le a\)&lt;/span&gt; (i.e. &lt;span class=&#34;math inline&#34;&gt;\(00,~01,~10,~11\)&lt;/span&gt;) as a group and using colour to distinguish those. The plot below should show up as a 3D object, so click, drag, and scroll it to have a closer look. Clicking on a group will remove/add it so you can get a clearer view, and hovering over a point should bring up the values of the axes and evaluation.&lt;/p&gt;
&lt;iframe width=&#34;900&#34; height=&#34;800&#34; frameborder=&#34;0&#34; scrolling=&#34;no&#34; src=&#34;//plot.ly/~jonocarroll/0.embed&#34;&gt;
&lt;/iframe&gt;
&lt;p&gt;Going back to the expression that’s being optimised it’s pretty clear why it’s broken down into 4 planes when grouped this way (substitute different values of &lt;span class=&#34;math inline&#34;&gt;\(a\)&lt;/span&gt; and &lt;span class=&#34;math inline&#34;&gt;\(b\)&lt;/span&gt; to see).&lt;/p&gt;
&lt;p&gt;Do you have another way to solve this? Drop a line or a link in the comments.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>#auunconf slack users&#39; timezone locations</title>
      <link>https://jcarroll.com.au/2016/04/14/slack-timezones/</link>
      <pubDate>Thu, 14 Apr 2016 23:04:15 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2016/04/14/slack-timezones/</guid>
      <description>&lt;p&gt;I had never used &lt;a href=&#34;https://slack.com/&#34;&gt;slack&lt;/a&gt; before, but had read a heap of &lt;a href=&#34;http://www.gizmodo.com.au/2016/04/10-tips-to-make-you-a-slack-wizard/&#34;&gt;tech articles&lt;/a&gt; extolling its virtues. &lt;a href=&#34;http://www.gizmodo.com.au/2015/10/malcolm-turnbull-wants-cabinet-ministers-to-use-slack/&#34;&gt;Apparently this is what our current Prime Minister advocates within Cabinet&lt;/a&gt;. The upcoming #auunconf organising team set up a channel and invited the participants, so I checked it out. Slack is pretty awesome as far as a unified workspace/messaging protocol can go. What makes it even more awesome, is that someone (&lt;span class=&#34;citation&#34;&gt;@hrbrmstr&lt;/span&gt;, no surprise) has made an &lt;a href=&#34;https://github.com/hrbrmstr/slackr&#34;&gt;R package that talks to it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After installing/loading the &lt;code&gt;slackr&lt;/code&gt; package, &lt;a href=&#34;https://api.slack.com/&#34;&gt;obtaining an API key&lt;/a&gt; (the usual drill; create an app, request key, save it somewhere and pray you don’t lose it or share it) and saving it in &lt;code&gt;~/.slackr&lt;/code&gt; (so I don’t have to remember to delete it from shared code) it was as simple as calling &lt;code&gt;slackr_users()&lt;/code&gt; to get a &lt;code&gt;data.frame&lt;/code&gt; of the users and their relevant data. Neat!&lt;/p&gt;
&lt;p&gt;The only geographical information in there was the timezone, so I figured I would merge that with &lt;a href=&#34;http://efele.net/maps/tz/world/&#34;&gt;a shapefile of such&lt;/a&gt; and plot it. Here’s the code I ended up creating&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/jonocarroll/1ce3ba63171eca2de22731c2503a1f48.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;Once I had plotted the map I wished the projection was more Pacific-centered, and looked into making that happen. It appears to be trickier than I wanted to bother with for such a small project, so I ended up abandoning it. I did find a &lt;a href=&#34;http://stackoverflow.com/questions/32591368/pacific-centric-robinson-projection-with-ggplot-in-r&#34;&gt;stackoverflow answer that seemed to have all the right ingredients&lt;/a&gt; (again, &lt;span class=&#34;citation&#34;&gt;@hrbrmstr&lt;/span&gt; at work) but I couldn’t get it to plot in any sort of reasonable time.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://jcarroll.com.au/post/2016-04-14-slack-timezones_files/auunconf_slackr_users_map.png&#34; alt=&#34;Map of #auunconf slack users&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;Map of #auunconf slack users&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The unique users so far claim to come from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Australia/Brisbane
&lt;/li&gt;
&lt;li&gt;
Australia/Canberra
&lt;/li&gt;
&lt;li&gt;
Asia/Ulaanbaatar
&lt;/li&gt;
&lt;li&gt;
America/Indiana/Indianapolis
&lt;/li&gt;
&lt;li&gt;
Australia/Adelaide
&lt;/li&gt;
&lt;li&gt;
Europe/Amsterdam
&lt;/li&gt;
&lt;li&gt;
Pacific/Auckland
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;so quite the diverse crowd.&lt;/p&gt;
&lt;p&gt;Once all was done and plotted, uploading the image to the slack team was as easy as &lt;code&gt;dev_slackr(&amp;quot;#general&amp;quot;)&lt;/code&gt; which sends the current graphic to the #general channel of the slack team that &lt;code&gt;slackr&lt;/code&gt; was configured for. Sure enough, it worked!&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://jcarroll.com.au/post/2016-04-14-slack-timezones_files/Screenshot-from-2016-04-14-224623.png&#34; alt=&#34;It works!&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;It works!&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I’m not entirely sure what I’ll use this for, but it was certainly a fun exercise to get working. Perhaps I can generalise it enough to submit a pull-request to make it available in slackr?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Simpler isn&#39;t always faster</title>
      <link>https://jcarroll.com.au/2016/04/14/simpler-isnt-always-faster/</link>
      <pubDate>Thu, 14 Apr 2016 21:52:45 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2016/04/14/simpler-isnt-always-faster/</guid>
      <description>&lt;p&gt;My name is Jonathan, and I have a coding obsession.&lt;/p&gt;
&lt;p&gt;I’ll admit it, the &lt;a href=&#34;http://adolfoalvarez.cl/the-hitchhikers-guide-to-the-hadleyverse/&#34;&gt;Hadleyverse&lt;/a&gt; has ruined me. I can no longer read a blog post or &lt;a href=&#34;http://stackoverflow.com/users/4168169/jonathan-carroll&#34;&gt;stackoverflow question&lt;/a&gt; in base &lt;code&gt;R&lt;/code&gt; and leave it be. There are improvements to make, and I’m somewhat sure that I know what they are. Most of them involve &lt;code&gt;dplyr&lt;/code&gt;. Many involve &lt;code&gt;data.table&lt;/code&gt;. Some involve &lt;code&gt;purrr&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.r-bloggers.com/how-to-sort-a-list-of-dataframes/&#34;&gt;This one&lt;/a&gt; came up on R-bloggers today (which leads back to &lt;a href=&#34;http://www.milanor.net/blog/how-to-sort-a-list-of-dataframes-in-r/&#34;&gt;MilanoR&lt;/a&gt;) and seemed like a good opportunity. The problem raised was; given a list of &lt;code&gt;data.frame&lt;/code&gt;s, can you create a list of the variables sorted into those &lt;code&gt;data.frame&lt;/code&gt;s? i.e. can you turn this&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;df_list_in &amp;lt;- list (
        df_1 = data.frame(x = 1:5, y = 5:1),
        df_2 = data.frame(x = 6:10, y = 10:6),
        df_3 = data.frame(x = 11:15, y = 15:11)
    )&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;into this&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;df_list_out &amp;lt;- list (
        df_x = data.frame(x_1 = 1:5, x_2 = 6:10, x_3 = 11:15),
        df_y = data.frame(y_1 = 5:1, y_2 = 10:6, y_3 = 15:11)
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That looks like a problem I came across recently. Let’s see…&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/jonocarroll/119e9db260783d7b459fd8fe4636150d.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;I managed to replace that function – which, while fast, is a little obtuse and difficult to read – with essentially a one-liner&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;df_list_in %&amp;gt;% purrr::transpose() %&amp;gt;% lapply(as.data.frame)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## $x
##   df_1 df_2 df_3
## 1    1    6   11
## 2    2    7   12
## 3    3    8   13
## 4    4    9   14
## 5    5   10   15
## 
## $y
##   df_1 df_2 df_3
## 1    5   10   15
## 2    4    9   14
## 3    3    8   13
## 4    2    7   12
## 5    1    6   11&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You may now proceed to argue over which is easier/simpler/more accessible/requires less knowledge of additional packages/etc… If you ask me, it’s damn-near perfect as long as you can place a cursor on &lt;code&gt;transpose&lt;/code&gt; in &lt;code&gt;RStudio&lt;/code&gt; and hit &lt;code&gt;F1&lt;/code&gt; which will bring up the &lt;code&gt;purrr::transpose&lt;/code&gt; help menu and explain exactly what is going on. Anyway, how does it compare? Here’s Michy’s graph (formatting updated and my function added)&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2016-04-14-simpler-isnt-always-faster_files/violinplot.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;and then, just for fun (and because I wanted an excuse to try it out) here’s a &lt;code&gt;yarrr::pirateplot&lt;/code&gt; of the same data&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2016-04-14-simpler-isnt-always-faster_files/pirateplot.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;My one-line function (without the &lt;code&gt;magrittr&lt;/code&gt; syntactical sugar) does slightly better than the &lt;code&gt;arrange_col&lt;/code&gt; function (on average), but has a lot less up-front code and is more readable (to me at least). The performance of any of these three doesn’t seem like it would have trouble scaling for any practical use-case.&lt;/p&gt;
&lt;p&gt;Scaling up the problem to a list of 100 &lt;code&gt;data.frame&lt;/code&gt;s each with 1000 observations of 50 variables, the same result pans out as shown in the above &lt;code&gt;microbenchmark&lt;/code&gt; and &lt;code&gt;pirateplot&lt;/code&gt; below&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2016-04-14-simpler-isnt-always-faster_files/bigdf_pirateplot.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;On the giant example (100 &lt;code&gt;data.frame&lt;/code&gt;s of 1000 observations of 50 variables) the difference is 20ms vs 380ms. Honestly, I don’t know what I’d do with the additional 360ms, but chances are I’d just waste them. I’ll take the efficient code on this one.&lt;/p&gt;
&lt;p&gt;Can you do even better than the one-liner? Spot a potential issue? Have I made a mistake? Got comments? You know what to do.&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.1.0   2019-07-06 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  knitr         1.24    2019-08-08 [1] CRAN (R 3.5.2)                   
##  magrittr    * 1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  purrr         0.3.2   2019-03-15 [1] CRAN (R 3.5.2)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>52vis Week 2 Challenge -- Australian Version</title>
      <link>https://jcarroll.com.au/2016/04/12/australian-homeless/</link>
      <pubDate>Tue, 12 Apr 2016 21:18:19 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2016/04/12/australian-homeless/</guid>
      <description>&lt;p&gt;I &lt;a href=&#34;https://jcarroll.com.au/2016/04/10/challenge/&#34;&gt;mapped out the USA homelessness rate&lt;/a&gt; in my last post as a challenge and noted at the end that it would be interesting to do the same for Australia. That was the first comment I received in person, too. “Let’s do it!” I said. What I found may shock you (click-bait title; check).&lt;/p&gt;
&lt;p&gt;Most of the code carried over. Of course, lacking &lt;a href=&#34;https://github.com/hrbrmstr/albersusa&#34;&gt;hrbrmstr’s neat &lt;code&gt;albersusa&lt;/code&gt;&lt;/a&gt; equivalent I had to obtain and process the shapefile myself. Thankfully, the &lt;a href=&#34;http://www.abs.gov.au/ausstats/abs@.nsf/mf/1259.0.30.001?OpenDocument&#34;&gt;ABS have me covered&lt;/a&gt;. Here’s the whole script;&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/jonocarroll/3f5e6cb61d9fb6c6a8f6afa85b8c6cfb.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;For starters, I compared the Australian statistics on the same scale as the USA (median 1.63‰, capped at 3x that value) and was shocked&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://jcarroll.com.au/post/2016-04-12-australian-homeless_files/HomelessPopulation_AUSversion_USscale.gif&#34; alt=&#34;AUS homeless population, US scale&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;AUS homeless population, US scale&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Yep, it appears we’re worse than the USA for homelessness. That sucks. What if we put it back on our own scale, how do our states do relatively? Well, for starters, the median goes up to 3.5‰ (I’ve again capped at 3x that value) but a lot of that seems to be coming from NT. Looking at the data itself, our lowest value is indeed higher than the USA median, so we’ve nothing to be proud of. That said, some states are doing better than our own median. TAS looks to be nicely below, while SA seems to be sitting around the median.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;https://jcarroll.com.au/post/2016-04-12-australian-homeless_files/HomelessPopulation_AUSversion_AUSscale.gif&#34; alt=&#34;AUS homeless population, AUS scale&#34; /&gt;
&lt;p class=&#34;caption&#34;&gt;AUS homeless population, AUS scale&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;If we drill down to the data itself, we can see what the actual figures look like. I’ve had a go at &lt;a href=&#34;https://rud.is/b/2016/04/07/geom_lollipop-by-the-chartettes/&#34;&gt;hrbrmstr’s &lt;code&gt;geom_lollipop&lt;/code&gt;&lt;/a&gt; (from the &lt;a href=&#34;https://github.com/hrbrmstr/ggalt&#34;&gt;dev version of &lt;code&gt;ggalt&lt;/code&gt;&lt;/a&gt;) and it works nicely, as expected. I’ve left NT off this first graph so that the others stand a fighting chance at the scale.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://s3-ap-southeast-2.amazonaws.com/jcarroll1/2016-14/HomelessPopulation_AUSbyStateNONT_optim.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;And here’s what happens if you include the Northern Territory&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://s3-ap-southeast-2.amazonaws.com/jcarroll1/2016-14/HomelessPopulation_AUSbyState_optim.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Ouch. It looks odd, but it’s correct. &lt;a href=&#34;http://blog.id.com.au/2012/population/australian-population/australian-2011-census-based-population-estimates/&#34;&gt;The number of people in the NT in 2011 was around 231,331&lt;/a&gt; but the &lt;a href=&#34;http://abs.gov.au/AUSSTATS/abs@.nsf/DetailsPage/2049.02011?OpenDocument%22&#34;&gt;census-estimated homeless population was 15,479&lt;/a&gt;, which means that 6.7% of the population (&lt;em&gt;i.e.&lt;/em&gt; 67‰) were homeless. What? Have I made a mistake? &lt;a href=&#34;http://www.abc.net.au/news/2012-11-12/nt-homelessness-rate-highest-in-nation/4367228&#34;&gt;No, it’s just horrifyingly true&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Aw, man. I came here for data analysis, not feels. Clearly this is a national shame, and something needs to be done about it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>52vis Week 2 Challenge</title>
      <link>https://jcarroll.com.au/2016/04/10/challenge/</link>
      <pubDate>Sun, 10 Apr 2016 22:01:17 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2016/04/10/challenge/</guid>
      <description>&lt;p&gt;From &lt;a href=&#34;https://rud.is/b/2016/04/06/52vis-week-2-2016-week-14-honing-in-on-the-homeless/&#34;&gt;Bob Rudis’ blog&lt;/a&gt; comes a weekly data/coding challenge. I didn’t quite get the time to tackle last week’s but I thought this one offered up a pretty good opportunity.&lt;/p&gt;
&lt;p&gt;Half the challenge is of course data processing/tidying, which is a big part of data science anyway (“75% of data science is getting the data in the right format, the other 50% is doing something with it” in case you haven’t heard the old joke). Needless to say, I’m using R for this one.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In case folks are wondering why I’m doing this, it’s pretty simple. We need a society that has high data literacy and we need folks who are capable of making awesome, truthful data visualizations. The only way to do that is by working with data over, and over, and over, and over again.&lt;/p&gt;
Directed projects with some reward are one of the best Pavlovian ways to accomplish that :-)
&lt;/blockquote&gt;
&lt;p&gt;The data this week is from the U.S. Department of Housing and Urban Development and involves homeless statistics, which I guess is pretty confronting given that I’ve done all this work from the comfort of my warm bed. Back to the topic at hand though. Bob Rudis provided some sample code and a nice &lt;code&gt;facet_wrap&lt;/code&gt;ped lollipop graph. I’ve also gone the &lt;code&gt;ggplot2&lt;/code&gt; route but I’ve done mine as a choropleth with Bob Rudis’ neat extensions for USA projections. It’s an almost too-obvious choice, so I spruced it up with the &lt;a href=&#34;https://github.com/dgrtwo/gganimate&#34;&gt;&lt;code&gt;gganimate&lt;/code&gt; package&lt;/a&gt;. The script is here:&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/jonocarroll/6e158719d6d672027b267002a07735dd.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;The map shows states with the median homeless population per thousand state population as white, with more than that coloured red, less than the median coloured blue (no, it’s not a political map). Each frame shows a different year of data. I think it does an okay job of displaying the changes in this statistic over a few years.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/jonocarroll/2016-14/master/jonocarroll/HomelessPopulation.gif&#34; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/jonocarroll/2016-14/master/jonocarroll/HomelessPopulation.gif&#34; /&gt;&lt;/p&gt;
&lt;p&gt;USA Homeless population, scaled by state population, and capped at 3x the national median. White fill represents median values. Grey states didn’t have data for that year.&lt;/p&gt;
&lt;p&gt;I’m loving the annotations extensions to &lt;code&gt;ggplot2&lt;/code&gt;; they really make these graphs a lot more professional looking. As for interpreting this map, well, that’s perhaps a little trickier. It seems to look like things got a bit worse overall in the earlier years of this data set, but since then they’ve been getting better. The west coast still has a large homeless population, and the central states seem to be a lot better. What’s not obvious from this, and that’s a general failing of non-size-proportional maps, is that some of the smallest states have some of the biggest per mille homelessness rates; D.C. tops out the scale in every year at between 9.3‰ (2007) and 11.7‰ (2014), followed by Oregon and Hawaii who see more than 3x the national median for more than a couple of years.&lt;/p&gt;
&lt;p&gt;I’m now somewhat curious to see what the Australian version looks like. Perhaps that’s a topic for the &lt;a href=&#34;https://github.com/ropensci/auunconf&#34;&gt;upcoming ROpenSci #auunconf&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As always, comments and suggestions welcome. The full repo of files is &lt;a href=&#34;https://github.com/jonocarroll/2016-14/tree/master/jonocarroll&#34;&gt;available here&lt;/a&gt;, for which I’ll be adding a pull-request back into the original repo.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Bring on the ROpenSci #auunconf 2016!</title>
      <link>https://jcarroll.com.au/2016/04/01/bring-on-the-ropensci-auunconf-2016/</link>
      <pubDate>Fri, 01 Apr 2016 06:25:01 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2016/04/01/bring-on-the-ropensci-auunconf-2016/</guid>
      <description>&lt;p&gt;I’ll be heading to the &lt;a href=&#34;http://auunconf.ropensci.org&#34;&gt;2016 ROpenSci un-conference&lt;/a&gt; (hackathon) in Brisbane later this month to smash out a heap of open-science R code. Ideas are already flowing quite nicely, and I’m confident that any ideas we don’t end up officially working on will get their chance in the very near future.&lt;/p&gt;
&lt;p&gt;One thing I noticed from the organisers was that coffee won’t be provided in an official sense. As a physicist at heart, that’s strange (scary) yet understandable (physics conferences go through an astounding amount of coffee; we once had a full-time barista on deck). There are supposedly plenty of nearby places to get a good coffee, but where? Time for some R code!&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/jonocarroll/603be338bffc2c379ee54ae3e25698c3.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;This ended up being a little easier than I first thought thanks to &lt;a href=&#34;http://stackoverflow.com/a/34802126/4168169&#34;&gt;someone already identifying the right Google Places API endpoint and providing an example function&lt;/a&gt;. I re-wrote the function to be a bit more general and to suit my needs a little better. After that it’s just a matter of extracting and plotting locations, adding a 2d density, and prettifying the output.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://s3-ap-southeast-2.amazonaws.com/jcarroll1/coffee_near_auunconf_2016.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;I’m loving &lt;a href=&#34;http://rud.is/b/2016/03/16/supreme-annotations/&#34;&gt;hrbrmstr’s annotations additions&lt;/a&gt; to &lt;code&gt;ggplot2&lt;/code&gt;; I think they really bring R graphics into a professional appearance. I have a feeling that my locations when not at the hackathon itself will correlate well with this density map as I try to find the best local coffee.&lt;/p&gt;
&lt;p&gt;Stay tuned for updates on the projects we end up developing. I have a good feeling that they’re going to be somewhat awesome.&lt;/p&gt;
&lt;p&gt;Suggestions on the above code most welcome. Also, if you happen to know of a great coffee house near there that isn’t listed, hit the comments section!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Image marginal histograms</title>
      <link>https://jcarroll.com.au/2016/03/12/image-marginal-histograms/</link>
      <pubDate>Sat, 12 Mar 2016 00:37:37 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2016/03/12/image-marginal-histograms/</guid>
      <description>&lt;p&gt;Another day, another interesting challenge.&lt;/p&gt;
&lt;p&gt;I follow &lt;a href=&#34;https://rud.is/b/&#34;&gt;Bob Rudis’ (a.k.a. hrbrmstr’s) blog&lt;/a&gt;, typically via &lt;a href=&#34;https://www.r-bloggers.com/&#34;&gt;R-bloggers&lt;/a&gt;, and &lt;a href=&#34;https://rud.is/b/2016/03/10/some-light-image-processing-creation-with-r/&#34;&gt;this post&lt;/a&gt; caught my eye. Partly because I thought I knew of an existing way to do this. As usual, actually getting that to work took a little longer than I might have hoped, but I think the end result is pretty neat.&lt;/p&gt;
&lt;p&gt;His post describes the process of writing an R function to take an image file, for example this one&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2016-03-12-image-marginal-histograms_files/file10a566a2b4dc3.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;and producing a histogram along the sides of the number of pixels on a given row/column. This is what he created (a different image to the example, I believe)&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://i2.wp.com/rud.is/b/wp-content/uploads/2016/03/Rplot1.png?resize=940%2C512&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Something funny is going on with the right-hand histogram; it doesn’t line up with the image.&lt;/p&gt;
&lt;p&gt;Here’s my approach.&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/JonoCarroll/7960dff5bf42e47423db.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;It leverages the &lt;code&gt;png&lt;/code&gt; package to extract the channels into a matrix, converts those to &lt;code&gt;x,y,z data.frame&lt;/code&gt;s, takes the median value, plots that with &lt;code&gt;ggplot2&lt;/code&gt;, then leverages &lt;code&gt;ggExtra::ggMarginal&lt;/code&gt; to add the marginal histograms. Note that the &lt;code&gt;ggExtra&lt;/code&gt; package has some bugs (it hasn’t been maintained in a while) in relation to more recent (possibly the dev branch) of &lt;code&gt;ggplot2&lt;/code&gt;. I got it working on at least one of my machines. This is my result&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2016-03-12-image-marginal-histograms_files/marginal.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;I’ve had several uses for these types of marginal plots lately, so hopefully I can sort out the issues I’ve been getting in combination with &lt;code&gt;ggplot2&lt;/code&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Is it crowded in here?</title>
      <link>https://jcarroll.com.au/2016/03/09/is-it-crowded-in-here/</link>
      <pubDate>Wed, 09 Mar 2016 22:31:13 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2016/03/09/is-it-crowded-in-here/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://i.imgur.com/5sYruU9.jpg&#34;&gt;This was a neat graphic that someone made&lt;/a&gt;. It shows the population at a given latitude or longitude as a bar chart, overlayed on a map of the world itself. It shows where people live; the bigger the bar, the more people living at that latitude/longitude.&lt;/p&gt;
&lt;p&gt;“&lt;em&gt;I can do that.&lt;/em&gt;” I said. In R of course. So here it is;&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/JonoCarroll/d7e23d8e4460acbcddd8.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;I love that such a small amount of code can produce something so interesting. Click the images below to view them in all their full-size glory.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jcarroll.com.au/post/2016-03-09-is-it-crowded-in-here_files/popByLat.png&#34;&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2016-03-09-is-it-crowded-in-here_files/popByLat.png&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jcarroll.com.au/post/2016-03-09-is-it-crowded-in-here_files/popByLon.png&#34;&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2016-03-09-is-it-crowded-in-here_files/popByLon.png&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;How is this useful? Well… okay, it’s not. It’s pretty. That’s what it is. An a neat exercise in data manipulation and plotting.&lt;/p&gt;
&lt;p&gt;UPDATE: As per a comment on my reddit thread, I’ve updated this to include a logarithmic colour-scale for population. The populations follow a nice logit curve if you arrange them in order:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jcarroll.com.au/post/2016-03-09-is-it-crowded-in-here_files/logPopulation.png&#34;&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2016-03-09-is-it-crowded-in-here_files/logPopulation.png&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here’s the updated graphics:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jcarroll.com.au/post/2016-03-09-is-it-crowded-in-here_files/popByLat_popCol.png&#34;&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2016-03-09-is-it-crowded-in-here_files/popByLat_popCol.png&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jcarroll.com.au/post/2016-03-09-is-it-crowded-in-here_files/popByLon_popCol.png&#34;&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2016-03-09-is-it-crowded-in-here_files/popByLon_popCol.png&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Jackpot!</title>
      <link>https://jcarroll.com.au/2016/01/13/jackpot/</link>
      <pubDate>Wed, 13 Jan 2016 15:18:22 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2016/01/13/jackpot/</guid>
      <description>&lt;p&gt;The powerball lottery in the USA has jackpotted to a first prize of $1.3 billion, which is just a silly amount of money.&lt;/p&gt;
&lt;p&gt;The cost of an entry (if you happen to be in the USA) is just $2, which is very much a ‘take a gamble’ sort of amount. If you’re an Aussie (except from SA like me) you can still have a go, but it will cost you considerably more (&lt;a href=&#34;http://www.news.com.au/finance/money/wealth/record-us15-billion-powerball-draw-now-open-to-australian-punters/news-story/721f7559c04f39ccd61787fcc80dc303&#34;&gt;$10.50&lt;/a&gt;) and you’ll still have to pay the relevant US taxes if you win.&lt;/p&gt;
&lt;p&gt;The following scenario has been raised a few times around the intertubes; if it costs $2 per ticket, the chances of winning (1/number of combinations of the drawn numbers) is 1/292,201,338, and the prize is over a billion dollars – why not buy one of every ticket and guarantee a win?&lt;/p&gt;
&lt;p&gt;First, let’s look at the game. There are 69 white balls from which 5 will be drawn. There is also a pool of 26 powerballs from which 1 will be drawn. You need 5/5 + 1 to win the jackpot.&lt;/p&gt;
&lt;p&gt;The odds of getting that right, &lt;a href=&#34;http://jcarroll.com.au/2015/03/10/what-are-the-odds/&#34;&gt;if you recall your combinatorics&lt;/a&gt;, is one in&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[ \displaystyle{{69 \choose 5} \cdot {26 \choose 1} = 292,201,338}\ . \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Doubling that makes buying all the tickets a mere $600 million or so. I’ll get my wallet.&lt;/p&gt;
&lt;p&gt;This would be easy money if it weren’t for three important facts; first, the cash prize is actually $930 million if you take it right away, so we’re already out of pocket quite a bit. Second, you may need to split the jackpot with one or more people, meaning a significantly lower return, possibly less than you invested. Lastly, you also need to pay tax on the income, which is around 40% on that. Maybe it’s not such a good deal.&lt;/p&gt;
&lt;p&gt;If you have one of every ticket however, you win every prize. How much does that get you? Back to combinatorics. To figure out how many combinations there are of each division we need to calculate the number of ways to get the number of correct and incorrect balls comparing our ticket to the draw, and multiply by the value of that prize.&lt;/p&gt;
&lt;p&gt;So, for the next best prize (a mere $1 million) we need to have all 5 of the white balls but not the powerball on our ticket. There are 5 possibilities of white ball, and we need all 5 of them. We need to match one of the 25 non-winning powerballs too, so the number of matching combinations is&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[ \displaystyle{{5 \choose 5} \cdot {25 \choose 1} = 25}\ . \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;So, there are 25 ways in which we could do this (get all 5 of the white ball numbers on our ticket, but not the powerball). That means that if we have one of each ticket, 25 of them will be worth a million dollars each.&lt;/p&gt;
&lt;p&gt;Continuing this logic the total winnings would be&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[ \begin{array}{lcl} {\rm WINNINGS} &amp;amp;=&amp;amp; 930,000,000\times{5 \choose 5} \cdot {1 \choose 1} \\ &amp;amp;+&amp;amp; 1,000,000\times{5 \choose 5} \cdot {25 \choose 1} \\ &amp;amp;+&amp;amp; 50,000\times{5 \choose 4} \cdot {64 \choose 1} \cdot {1 \choose 1} \\ &amp;amp;+&amp;amp; 100\times{5 \choose 4} \cdot {64 \choose 1} \cdot {25 \choose 1} \\ &amp;amp;+&amp;amp; 100\times{5 \choose 3} \cdot {64 \choose 2} \cdot {1 \choose 1} \\ &amp;amp;+&amp;amp; 7\times{5 \choose 3} \cdot {64 \choose 2} \cdot {25 \choose 1} \\ &amp;amp;+&amp;amp; 7\times{5 \choose 2} \cdot {64 \choose 3} \cdot {1 \choose 1} \\ &amp;amp;+&amp;amp; 4\times{5 \choose 1} \cdot {64 \choose 4} \cdot {1 \choose 1} \\ &amp;amp;+&amp;amp;  4\times{5 \choose 0} \cdot {64 \choose 5} \cdot {1 \choose 1}\end{array}\ . \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;or programmed as&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;winnings &amp;lt;- 930e6*1 +                                     ## cash prize for jackpot, 1 winner
            1e6*choose(5,5)*choose(25,1)                + ## match 5 out of 5 white, don&amp;#39;t match powerball
            5e4*choose(5,4)*choose(69-5,1)*choose(1,1)  + ## match 4 out of 5 white, match powerball
            1e2*choose(5,4)*choose(69-5,1)*choose(25,1) + ## match 4 out of 5 white, don&amp;#39;t match powerball
            1e2*choose(5,3)*choose(69-5,2)*choose(1,1)  + ## match 3 out of 5 white, match powerball
            7*choose(5,3)*choose(69-5,2)*choose(25,1)   + ## match 3 out of 5 white, don&amp;#39;t match powerball
            7*choose(5,2)*choose(69-5,3)*choose(1,1)    + ## match 2 out of 5 white, match powerball
            4*choose(5,1)*choose(69-5,4)*choose(1,1)    + ## match 1 out of 5 white, match powerball
            4*choose(5,0)*choose(69-5,5)*choose(1,1)      ## match 0 out of 5 white, match powerball
prettyNum(winnings, big.mark=&amp;quot;,&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;1,023,466,048&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, winning all prizes all by yourself (everyone else who might have won the jackpot lost their tickets) nets you a little over a billion pre-tax dollars on its own. Not bad, but still pretty risky since you’re betting on not sharing.&lt;/p&gt;
&lt;p&gt;The big question will be how big does the lottery need to get before this starts to look like a plausible option? The cost of tickets and total number of combinations are constants, so there must be some jackpot prize for which it’s a good bet to buy all the tickets, given that the chances of sharing don’t go up considerably (if you trust the &lt;a href=&#34;http://fivethirtyeight.com/features/powerball-jackpot-800-million-odds/&#34;&gt;FiveThirtyEight analysis of historical entries&lt;/a&gt;);&lt;/p&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.1.0   2019-07-06 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  knitr         1.24    2019-08-08 [1] CRAN (R 3.5.2)                   
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>SimplyStats Thanksgiving Puzzle</title>
      <link>https://jcarroll.com.au/2015/11/26/simplystats-thanksgiving-puzzle/</link>
      <pubDate>Thu, 26 Nov 2015 09:39:33 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2015/11/26/simplystats-thanksgiving-puzzle/</guid>
      <description>&lt;p&gt;I owe a lot to Jeff Leek and Roger Peng for their great Coursera courses, in which I learned to program in R.&lt;/p&gt;
&lt;p&gt;They (along with Rafa Irizarry) run the &lt;a href=&#34;http://simplystatistics.org/&#34;&gt;Simply Statistics&lt;/a&gt; blog, which I highly reccomend. They posted a Thanksgiving puzzle in which a data.frame needs to be converted from one form to another, spelling out ‘thanksgiving’.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://simplystatistics.org/2015/11/25/a-thanksgiving-dplyr-rubiks-cube-puzzle-for-you/&#34;&gt;http://simplystatistics.org/2015/11/25/a-thanksgiving-dplyr-rubiks-cube-puzzle-for-you/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The puzzle: convert this&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/jtleek/aae1218a8f4d1220e07d.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;into this&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/jtleek/4d4b63a035973231e6d4.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;My solution, which uses Rubik’s Cube rotations of rows and columns (and dplyr of course):&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/JonoCarroll/f89e0aae8b6c83ac5818.js&#34;&gt;&lt;/script&gt;
&lt;p&gt;Suggestions on how I could have done this differently (or automated solutions) most welcome!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>What are the odds?</title>
      <link>https://jcarroll.com.au/2015/03/10/what-are-the-odds/</link>
      <pubDate>Tue, 10 Mar 2015 08:00:20 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2015/03/10/what-are-the-odds/</guid>
      <description>&lt;p&gt;After posting this photo of our lottery ticket to Facebook&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2015-03-10-what-are-the-odds_files/soclose.jpg&#34; width=&#34;300&#34; /&gt;&lt;/p&gt;
&lt;p&gt;I thought more and more about random-event probabilities.&lt;/p&gt;
&lt;p&gt;I know my way around numbers just fine, so I know that the odds of winning Division 1 in the South Australian Saturday Night X-Lotto is 1 in &lt;a href=&#34;https://tatts.com/salotteries/games/x-lotto&#34;&gt;8,145,060&lt;/a&gt; (yes, that’s one of the semi-useless numbers I have memorised).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2015-03-10-what-are-the-odds_files/solo_odds.gif&#34; /&gt;&lt;/p&gt;
&lt;p&gt;That’s fairly improbable at face value, sure, but it’s me, so I’m going deeper. Calculating odds of events with limited outcomes can be as easy as multiplying out individual probabilities. For example, the odds of 8 women in a mum’s group all having the opposite-sex for their second child is just the product of 1 option from 2 choices, 8 times (multiplied);&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[ \left(\frac{1}{2}\right)^8 = \frac{1}{256}\ . \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;With things like drawing multiple numbered balls from a pool there are complications; it doesn’t matter what order you take them out in, and you need to account for all the possible combinations. The odds are nonetheless fairly easy to calculate if you know/remember your combinatorics; If, from the initial pool of &lt;span class=&#34;math display&#34;&gt;\[n\]&lt;/span&gt; numbers, we need to choose &lt;span class=&#34;math display&#34;&gt;\[r\]&lt;/span&gt; without replacement, then the notation for this is “n choose r” and has the formula&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[ \displaystyle{{n \choose r} = \frac{n!}{r!(n-r)!}}\ , \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;where the exclamation mark denotes factorial (&lt;span class=&#34;math inline&#34;&gt;\(p! = p \times (p-1) \times (p-2) \times \ldots \times 1\)&lt;/span&gt;).&lt;/p&gt;
&lt;p&gt;We are choosing 6 numbers from a pool of 45 without replacement, so the odds of any one exact choice coming up is&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[ \displaystyle{{45 \choose 6} = \frac{45!}{6!\ 39!}}\ . \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We can make use of a little more math to simplify that;&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[ \frac{(a+b)!}{b!} = (a+b) \times (a+b-1) \times (a+b-2) \times \ldots \times (b+1)\ , \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;so we are left with&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[ \frac{45!}{6!\ 39!} = \frac{(6+39)!}{6!\ 39!} = \frac{45 \times 44 \times 43 \times 42 \times 41 \times 40}{6 \times 5 \times 4 \times 3 \times 2 \times 1} = \frac{5864443200}{720} = 8,145,060\ . \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;How about getting (any) 4 numbers? That’s choosing 4 from a pool of 45;&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[ \displaystyle{{45 \choose 4} = 148,995}\ . \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Games like Powerball have much worse odds; In that game Division 1 is won by selecting 6 numbers from a pool of 40 without replacement, but then also selecting the Powerball from a new pool of 20;&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[ \displaystyle{{40 \choose 6} \times {20 \choose 1} = 76,767,600}\ . \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The point I was making with the photo was that it seemed somewhat cruel that the two missing numbers from our otherwise winning combination were both off by exactly 10, and thus only two little 1’s stood between us and a decent $2 million. I know perfectly well that &lt;em&gt;any&lt;/em&gt; two numbers qualified for those positions, but having the actual digits right there was just frustrating.&lt;/p&gt;
&lt;p&gt;I know there are plenty of people who don’t play the lottery because the odds are so bad. The problem I find with that thinking is two-fold; firstly, “&lt;em&gt;you gotta be in it to win it.&lt;/em&gt;” A cliché, sure, but valid. If you don’t have a ticket, your chances of winning are precisely zero. Secondly, while the odds of predicting the next random drawing of 6 numbers from a pool of 45 is 1 in 8,145,060, and thus the individual chances of winning are ‘low’, sure enough someone wins more or less every week. A scientific hero of mine, Richard Feynman puts it perfectly;&lt;/p&gt;
&lt;blockquote&gt;
You know, the most amazing thing happened to me tonight. I was coming here, on the way to the lecture, and I came in through the parking lot. And you won’t believe what happened. I saw a car with the license plate ARW 357. Can you imagine? Of all the millions of license plates in the state, what was the chance I would see that particular one tonight? Amazing!
&lt;/blockquote&gt;
&lt;p&gt;The point is that every game (line on a ticket) has exactly the same chances of winning as any other. Sure, individually that’s ‘low’ odds, but it’s no lower for me than it is for you. Someone is quite likely going to be life-changingly wealthier each week, just as someone’s car with some licence plate was going to be in the parking lot. It’s easy to make the quote as above after the fact and state the odds of seeing that one, but that’s applying an ex-post analysis to that particular event, confusing the matter somewhat.&lt;/p&gt;
&lt;p&gt;There is of course some advantage in having more games available (buying more tickets), though it’s no guarantee. You could buy 1,845,060 tickets and still not win; those calculated odds correspond to an infinite sample (you want an infinite sample simulator? &lt;a href=&#34;http://gravy.azurewebsites.net/LotterySimulator/&#34;&gt;Here you go&lt;/a&gt;). If I buy a 20-game ticket then my chances of winning drop by a factor of 20 to 20/8,145,060, or 1 in 407,253. That’s getting pretty reasonable; we’re under the ‘1 in a million’ line now.&lt;/p&gt;
&lt;p&gt;Another way to think about this is that even 1 in 8 million isn’t a terribly low probability in the grand scheme of things. Sure, things with that sort of probability aren’t going to be showing up in your day-to-day life a lot, but there are interesting examples. There’s apparently a &lt;a href=&#34;http://theweek.com/articles/462449/odds-are-11-million-1-that-youll-die-plane-crash&#34;&gt;1 in 11 million chance that you’ll die in an plane accident&lt;/a&gt;, which is hopefully reassuring. There’s &lt;a href=&#34;http://www.reddit.com/r/AskReddit/comments/2loor3/what_is_the_most_statistically_unlikely_thing/clxkdba&#34;&gt;this family&lt;/a&gt; who rented a car and travelled around the U.S.A., eventually parking next to another car with a consecutive number plate. The fact that it’s the same model of car isn’t terribly surprising; the plates were probably given in sequence to a dealer. The fact that the identifiable vehicles have been brought back together is the surprising part.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2015-03-10-what-are-the-odds_files/consecutive.jpg&#34; /&gt;&lt;/p&gt;
&lt;p&gt;They claim the other was rented from a completely different state to where theirs was. I’ve seen a licence plate consecutive to ours on the road, but here in Adelaide that’s probably not nearly so unlikely. I actually have a similar story; one Easter we went up the coast to Port Broughton, which was, to be honest, quite boring, so we got in the car and drove around to various towns, eventually stopping in for a snorkel at Moonta Bay. We pulled into the car park and I recognised the person getting out of their car in the bay across the road from ours. It was a visiting German post-doc from my research group who had decided to drive up from Adelaide on a whim, and who just happened to arrive at the same place as us at the same time and park a few meters from us. I digress.&lt;/p&gt;
&lt;p&gt;What then, were the odds of getting those two ‘off by 10’ numbers on my game line? With 4 of the 6 numbers already correct, the pool was reduced by 4 numbers, and I needed to choose another 2, so the individual chances of any two remaining numbers being drawn were&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[ \displaystyle{{41 \choose 2} = 820}\ . \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;That applies whether we want the chances of specifically 13 and 16 being chosen or any other pair of numbers.&lt;/p&gt;
&lt;p&gt;In large physics experiments such as the &lt;a href=&#34;http://home.web.cern.ch/topics/large-hadron-collider&#34;&gt;LHC&lt;/a&gt;, statistics play a large role in determining when an event (e.g. observing a Nobel-prize winning particle) is ‘likely’ and when it isn’t. Part of that includes taking into consideration the fact that &lt;strong&gt;lots&lt;/strong&gt; of observations are made, making the distinction between rare events and random fluctuations a fine line, and so a ‘look elsewhere effect’ is included in the calculations. The analogy here is that I would have been just as upset with 23 and 26, or 33 and 36, so we should include those in our calculations of ‘how likely’. This changes our calculations from the above, to choosing any of 6 numbers from the remaining 41, then any of 5 from the remaining 40;&lt;/p&gt;
&lt;p&gt;&lt;span class=&#34;math display&#34;&gt;\[ \frac{6}{41} \times \frac{5}{40} = \frac{30}{1640} = \frac{3}{164} \sim 1\ {\rm in}\ 55\ , \]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;so I’d say not all that unlikely to happen.&lt;/p&gt;
&lt;p&gt;This is why patterns show up so frequently from apparently random events; we focus on specific odds of unlikely events but fail to take in to account the other equally unlikely combinations. Bumping into a friend from a decade ago might seem unlikely, but you need to multiply those odds by the number of people who would have elicited the same response from you, had you bumped into them. In my earlier anecdote about bumping into a fellow researcher, I would have been just as surprised to see pretty much anyone I knew, so the probability of this ‘event’ is suddenly significantly higher, though possibly still ‘low’. With the car example, this probably happens a lot and you don’t notice it. I certainly don’t read the licence plate of every vehicle I park near. Also, how close would the plates need to be to surprise you? Off by a digit? Just the last digit? A letter? The ‘look elsewhere’ effect really raises this one significantly.&lt;/p&gt;
&lt;p&gt;Anyway, after all that, am I still going to buy a ticket sometime this month? Probably.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Project Euler Q5 :: Smallest multiple</title>
      <link>https://jcarroll.com.au/2015/01/08/project-euler-q5/</link>
      <pubDate>Thu, 08 Jan 2015 23:25:58 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2015/01/08/project-euler-q5/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://jcarroll.com.au/2015/01/02/project-euler/&#34;&gt;Explanation&lt;/a&gt;. Standard caveat: don’t look here if you are trying to do these yourself.&lt;/p&gt;
&lt;blockquote&gt;
2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder. What is the smallest positive number that is &lt;em&gt;evenly divisible&lt;/em&gt; by all of the numbers from 1 to 20?
&lt;/blockquote&gt;
&lt;p&gt;I’m getting the feeling that brute-force is going to be quite the useful tool for these questions. Thankfully &lt;code&gt;R&lt;/code&gt; can churn through numbers really fast.&lt;/p&gt;
&lt;p&gt;So, we’re after a number divisible by &lt;code&gt;1, 2, 3, ..., 10&lt;/code&gt;. Let’s vectorise that and check the stated answer&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;all(2520 %% 1:10 == 0)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Easy enough. The solution value must be divisible by 20, so we can just test multiples of 20 for the above property&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;i &amp;lt;- 20
y &amp;lt;- FALSE
while(!y) {
  i &amp;lt;- i + 20
  y &amp;lt;- all(i %% 1:20 == 0)
}
i&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 232792560&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;### CORRECT&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wrapping a &lt;code&gt;system.time()&lt;/code&gt; call around that assures us that this is still done in under a minute, as per the guidelines&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;   user  system elapsed 
 26.150   0.000  26.192 &lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.1.0   2019-07-06 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  knitr         1.24    2019-08-08 [1] CRAN (R 3.5.2)                   
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Project Euler Q4 :: Largest palindrome product</title>
      <link>https://jcarroll.com.au/2015/01/08/project-euler-q4/</link>
      <pubDate>Thu, 08 Jan 2015 22:24:09 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2015/01/08/project-euler-q4/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://jcarroll.com.au/2015/01/02/project-euler/&#34;&gt;Explanation&lt;/a&gt;. Standard caveat: don’t look here if you are trying to do these yourself.&lt;/p&gt;
&lt;blockquote&gt;
A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99. Find the largest palindrome made from the product of two 3-digit numbers.
&lt;/blockquote&gt;
&lt;p&gt;This seems like another brute-force question. There’s not that many numbers to test.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## check the worked solution
91*99 &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 9009&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m not aware of an &lt;code&gt;is.palindrome&lt;/code&gt; function, but it’s easy enough to code.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.palindrome &amp;lt;- function(x) {
   ## convert to character and explode
   x &amp;lt;- unlist(strsplit(as.character(x), &amp;quot;&amp;quot;))
   ## check if the vector is palindromic
   return(identical(x, rev(x)))
}
is.palindrome(9009)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.palindrome(9001)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] FALSE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s try it out for the two digit example and make sure we’re on the right track. Multiply all two digit numbers together and test them for palindrome-ness, then find the largest of those.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;twodigits &amp;lt;- 10:99
prods &amp;lt;- expand.grid(twodigits, twodigits)
prods$prod &amp;lt;- prods[ ,1]*prods[ ,2]
prods.palindromes &amp;lt;- prods$prod[sapply(prods$prod, is.palindrome)]
max(prods.palindromes)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 9009&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great! What about three digits?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;threedigits &amp;lt;- 100:999
prods &amp;lt;- expand.grid(threedigits, threedigits)
prods$prod &amp;lt;- prods[ ,1]*prods[ ,2]
prods.palindromes &amp;lt;- prods$prod[sapply(prods$prod, is.palindrome)]
largest &amp;lt;- max(prods.palindromes)
largest&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 906609&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;### CORRECT&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Takes a little longer, and generates a nice little 10MB, 810,000 element vector along the way.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;format(object.size(prods), units=&amp;quot;Mb&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] &amp;quot;9.4 Mb&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The two three digit numbers?&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;prods[prods$prod==largest, ]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##        Var1 Var2   prod
## 732594  993  913 906609
## 804514  913  993 906609&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.1.0   2019-07-06 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  knitr         1.24    2019-08-08 [1] CRAN (R 3.5.2)                   
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Project Euler Q3 :: Largest prime factor</title>
      <link>https://jcarroll.com.au/2015/01/03/project-euler-q3/</link>
      <pubDate>Sat, 03 Jan 2015 00:52:07 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2015/01/03/project-euler-q3/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://jcarroll.com.au/2015/01/02/project-euler/&#34;&gt;Explanation&lt;/a&gt;. Standard caveat: don’t look here if you are trying to do these yourself.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The prime factors of 13195 are 5, 7, 13 and 29.&lt;/p&gt;
What is the largest prime factor of the number 600851475143?
&lt;/blockquote&gt;
&lt;p&gt;It seems so simple at first glance, until of course you look at how big that last number is. I started off by making sure I understood the issue.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## check the worked solution
5*7*13*29&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 13195&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so far so good. At this point I realised that there isn’t an inbuilt &lt;code&gt;is.prime&lt;/code&gt; so I stole one from &lt;a href=&#34;http://cran.r-project.org/web/packages/rlist/vignettes/Examples.html&#34;&gt;this site.&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;is.prime &amp;lt;- function(num) {
 if (num == 2L) {
 TRUE
 } else if (any(num %% 2L:(num-1L) == 0L)) {
 FALSE
 } else {
 TRUE
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Testing the example works pretty well…&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## let&amp;#39;s loop up to n and list the prime factors
prime.factors &amp;lt;- function(n) {
 primes &amp;lt;- c()
 for(i in 1:n) {
 ## take advantage of lazy logical evaluation
 ## and short-cut to only the factors
 if(n %% i == 0 &amp;amp; is.prime(i)) primes &amp;lt;- c(primes, i)
 }
 return(primes)
}
prime.factors(13195)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]  5  7 13 29&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but I hit a snag when I tried to do the same for the problem value.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;w &amp;lt;- as.integer(600851475143)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-warning text-warning&#34;&gt;&lt;code&gt;## Warning: NAs introduced by coercion to integer range&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;prime.factors(600851475143) ## Error: cannot allocate vector of size 4476.7 Gb&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-danger text-danger&#34;&gt;&lt;code&gt;## Error in prime.factors(600851475143): long vectors not supported yet: eval.c:6387&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sure enough, that’s bigger than the machine precision integer allows&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;as.numeric(&amp;quot;600851475143&amp;quot;) &amp;gt; .Machine$integer.max&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;so, I abandoned the pre-filled list of values and went again with the brute force. For the sake of speeding it up, I delayed testing for primes until later, as I can do that over the generated list with an &lt;code&gt;apply&lt;/code&gt; and only bothered testing the values below &lt;code&gt;sqrt(n)&lt;/code&gt; and &lt;code&gt;n/f&lt;/code&gt; where &lt;code&gt;f&lt;/code&gt; is the largest found prime so far.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## lists are too big. Find the primes by brute force
## using floating point representations
z &amp;lt;- as.numeric(&amp;quot;600851475143&amp;quot;)
i &amp;lt;- 2
factors &amp;lt;- 1
## loop through values of i that are
## less than sqrt(z) and
## less than z/the largest found factor
while(i &amp;lt; sqrt(z) &amp;amp; i &amp;lt; z/max(factors)) {
 ## skip the prime test for now
 if(z %% i == 0) factors &amp;lt;- c(factors, i)
 i &amp;lt;- i + 1
}
factors&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1]      1     71    839   1471   6857  59569 104441 486847&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;factors.prime &amp;lt;- sapply(factors, is.prime)
primes &amp;lt;- factors[factors.prime] 
z == prod(primes)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] TRUE&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;max(primes)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 6857&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;### CORRECT&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.1.0   2019-07-06 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  knitr         1.24    2019-08-08 [1] CRAN (R 3.5.2)                   
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Project Euler Q2 :: Even Fibonacci numbers</title>
      <link>https://jcarroll.com.au/2015/01/02/project-euler-q2/</link>
      <pubDate>Fri, 02 Jan 2015 22:56:50 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2015/01/02/project-euler-q2/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://jcarroll.com.au/2015/01/02/project-euler/&#34;&gt;Explanation&lt;/a&gt;. Standard caveat: don’t look here if you are trying to do these yourself.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:&lt;/p&gt;
&lt;p&gt;1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …&lt;/p&gt;
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
&lt;/blockquote&gt;
&lt;p&gt;Getting a little trickier already. I initially attempted this one by a recursive brute-force search of each step in the sequence;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## recursively define the Fibonacci sequence
fibonacci &amp;lt;- function(x) {
   y &amp;lt;- ifelse(x &amp;gt; 1, fibonacci(x-1)+fibonacci(x-2), x)
   return(y)
}

## values in fibonacci &amp;lt; 4e6
z &amp;lt;- 4e6L
## check i=20,30,40
fibonacci(20)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 6765&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;fibonacci(30) # takes over 8 seconds&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 832040&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# fibonacci(40) # takes too long&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But of course these solutions are supposed to be calculable in &lt;a href=&#34;https://projecteuler.net/about&#34;&gt;about a minute&lt;/a&gt; so I’ve taken a wrong turn.&lt;/p&gt;
&lt;p&gt;It quickly became obvious that I was needlessly re-calculating each step to add another, which is silly, as this explicitly needs all of them each time. I decided to store the sequence as a &lt;code&gt;data.frame&lt;/code&gt; to keep the iteration number alongside it. Note that I use the more correct definition of the sequence which starts with 1, 1, 2. That’s not going to be an issue here, as we’re summing the even values anyway.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## this is silly, why recompute every time?
fibonacci.seq &amp;lt;- data.frame(n=integer(), f=integer())
fibonacci.seq[1,] &amp;lt;- c(1,1)
fibonacci.seq[2,] &amp;lt;- c(1,1)
w &amp;lt;- 2
f &amp;lt;- fibonacci.seq$f[w]
while(f &amp;lt; z) {
 w &amp;lt;- w + 1
 fibonacci.seq[w,] &amp;lt;- data.frame(n=w, f=fibonacci.seq$f[w-1]+fibonacci.seq$f[w-2])
 f &amp;lt;- fibonacci.seq$f[w]
}
head(fibonacci.seq)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##   n f
## 1 1 1
## 2 1 1
## 3 3 2
## 4 4 3
## 5 5 5
## 6 6 8&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;tail(fibonacci.seq)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;##     n       f
## 29 29  514229
## 30 30  832040
## 31 31 1346269
## 32 32 2178309
## 33 33 3524578
## 34 34 5702887&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## sum of even values
sum(fibonacci.seq[fibonacci.seq$f %% 2 == 0, &amp;quot;f&amp;quot;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 4613732&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;### CORRECT&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.1.0   2019-07-06 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  knitr         1.24    2019-08-08 [1] CRAN (R 3.5.2)                   
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Project Euler Q1 :: Multiples of 3 and 5</title>
      <link>https://jcarroll.com.au/2015/01/02/project-euler-q1/</link>
      <pubDate>Fri, 02 Jan 2015 22:45:10 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2015/01/02/project-euler-q1/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://jcarroll.com.au/2015/01/02/project-euler/&#34;&gt;Explanation&lt;/a&gt;. Standard caveat: don’t look here if you are trying to do these yourself.&lt;/p&gt;
&lt;blockquote&gt;
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find the sum of all the multiples of 3 or 5 below 1000.
&lt;/blockquote&gt;
&lt;p&gt;This one’s pretty straight forward, really, as one might hope being the first question. R’s built-in subsetting mechanism handles the extraction fairly nicely. I perhaps would have liked a way to do this without first defining &lt;code&gt;x&lt;/code&gt;; though I suppose it could just be repeated in the last line.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## check the worked solution
sum(c(3,5,6,9))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 23&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;## values &amp;lt; 1000
x &amp;lt;- 1:999

## sum of x % 3 or x % 5
sum(x[x %% 3 == 0 | x %% 5 == 0])&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## [1] 233168&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;### CORRECT&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;details&gt;
&lt;p&gt;&lt;summary&gt;
&lt;tt&gt;devtools::session_info()&lt;/tt&gt;
&lt;/summary&gt;&lt;/p&gt;
&lt;pre class=&#34;bg-success&#34;&gt;&lt;code&gt;## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.5.2 (2018-12-20)
##  os       Pop!_OS 19.04               
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language en_AU:en                    
##  collate  en_AU.UTF-8                 
##  ctype    en_AU.UTF-8                 
##  tz       Australia/Adelaide          
##  date     2019-08-13                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package     * version date       lib source                           
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)                   
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.5.2)                   
##  blogdown      0.14.1  2019-08-11 [1] Github (rstudio/blogdown@be4e91c)
##  bookdown      0.12    2019-07-11 [1] CRAN (R 3.5.2)                   
##  callr         3.3.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.2)                   
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)                   
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)                   
##  devtools      2.1.0   2019-07-06 [1] CRAN (R 3.5.2)                   
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.5.2)                   
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.5.2)                   
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.5.2)                   
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)                   
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)                   
##  knitr         1.24    2019-08-08 [1] CRAN (R 3.5.2)                   
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.5.1)                   
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)                   
##  pkgbuild      1.0.4   2019-08-05 [1] CRAN (R 3.5.2)                   
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)                   
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)                   
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.5.2)                   
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.1)                   
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.1)                   
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.5.2)                   
##  remotes       2.1.0   2019-06-24 [1] CRAN (R 3.5.2)                   
##  rlang         0.4.0   2019-06-25 [1] CRAN (R 3.5.2)                   
##  rmarkdown     1.14    2019-07-12 [1] CRAN (R 3.5.2)                   
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)                   
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)                   
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)                   
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)                   
##  testthat      2.2.1   2019-07-25 [1] CRAN (R 3.5.2)                   
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.5.2)                   
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)                   
##  xfun          0.8     2019-06-25 [1] CRAN (R 3.5.2)                   
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)                   
## 
## [1] /home/jono/R/x86_64-pc-linux-gnu-library/3.5
## [2] /usr/local/lib/R/site-library
## [3] /usr/lib/R/site-library
## [4] /usr/lib/R/library&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Project Euler</title>
      <link>https://jcarroll.com.au/2015/01/02/project-euler/</link>
      <pubDate>Fri, 02 Jan 2015 22:27:10 +0000</pubDate>
      <author>website@jcarroll.com.au (Jonathan Carroll)</author>
      <guid>https://jcarroll.com.au/2015/01/02/project-euler/</guid>
      <description>&lt;p&gt;As a means of honing my &lt;a href=&#34;http://www.r-project.org/&#34;&gt;R&lt;/a&gt; programming skills, I’ve decided to tackle the &lt;a href=&#34;https://projecteuler.net/about&#34;&gt;Project Euler&lt;/a&gt; questions exclusively using my new favourite programming language. Besides, it seems that R can do just about everything; surely it can handle some programming games. If I get the time, I’ll add updates in other languages as I build my knowledge of them.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://jcarroll.com.au/post/2015-01-02-project-euler_files/euler_portrait.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;R is not going to be the best language for some of the questions (I see some very Python-suitable questions) but they should all be do-able in R, and I’d bet R beats some of the others in at least a few questions.&lt;/p&gt;
&lt;p&gt;I’ll try to post a solution or two a week at least, along side my other projects. There’s about 500 questions available, presumably increasing in difficulty, so that’s quite a depth of material to cover.&lt;/p&gt;
&lt;p&gt;If you know of a good improvement that can be made, by all means drop a line in the comments.&lt;/p&gt;
&lt;p&gt;It should be noted however, as per the Project Euler site;&lt;/p&gt;
&lt;blockquote&gt;
&lt;h3&gt;
I learned so much solving problem XXX so is it okay to publish my solution elsewhere?
&lt;/h3&gt;
It appears that you have answered your own question. There is nothing quite like that “Aha!” moment when you finally beat a problem which you have been working on for some time. It is often through the best of intentions in wishing to share our insights so that others can enjoy that moment too. Sadly, however, that will not be the case for your readers. Real learning is an active process and seeing how it is done is a long way from experiencing that epiphany of discovery. Please do not deny others what you have so richly valued yourself.
&lt;/blockquote&gt;
&lt;p&gt;so if you’re planning on tackling these yourself, you’re better off steering clear of these posts for now and comparing solutions later. That’s what I’m doing at least.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
