<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://ninioartillero.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://ninioartillero.github.io/" rel="alternate" type="text/html" /><updated>2026-04-27T03:11:44+00:00</updated><id>https://ninioartillero.github.io/feed.xml</id><title type="html">ninioArtillero</title><subtitle>Hocus Pocus y KameHameHas. Encuentros con chilacayotas cósmicas y piratas truchas.
</subtitle><author><name>Xavier Góngora</name></author><entry><title type="html">A Liquid Haskell Kick-Start</title><link href="https://ninioartillero.github.io/2025/04/15/lh-kickstart.html" rel="alternate" type="text/html" title="A Liquid Haskell Kick-Start" /><published>2025-04-15T00:00:00+00:00</published><updated>2025-04-15T00:00:00+00:00</updated><id>https://ninioartillero.github.io/2025/04/15/lh-kickstart</id><content type="html" xml:base="https://ninioartillero.github.io/2025/04/15/lh-kickstart.html"><![CDATA[<p>In this tutorial post, I introduce Liquid Haskell (LH), present a step-by-step
installation procedure, and work through a simple example of its use.
As a bonus, we will see how to use a local LH build in our projects.</p>

<p>This is basically a rehash of some setup notes I made while preparing a proposal for the
<a href="https://summerofcode.withgoogle.com/">Google Summer of Code 2025</a>, based on the
<a href="https://github.com/haskell-org/summer-of-haskell/blob/3c9efd21fc0022f7b9c21ac2001ca1049d888dc9/content/ideas/lh-aliases.md">project idea</a>
proposed by Facundo Domínguez.
More detailed information can be found at the LH
<a href="https://ucsd-progsys.github.io/liquidhaskell/">documentation site</a> and
<a href="https://github.com/ucsd-progsys/liquidhaskell">source repository</a>.</p>

<p>LH is under active development, with a focus on quality-of-life features that make
it a breeze to use (or maybe not quite yet, but its getting there). I believe that
using <em>refinement types</em> to specify programs unlocks expressive possibilities,
enabling stronger guarantees and clearer intent, that are worth exploring.</p>

<h2 id="about-liquid-haskell">About Liquid Haskell</h2>

<p>LH is a tool that allows programmers to enforce contracts on their functions
inputs (<em>pre-conditions</em>) and outputs (<em>post-conditions</em>).
This is done through special comment annotations that extend a function type
signature with <em>refinement types</em>: types that include constraints defined by
logical predicates.</p>

<p>A typical example is that of a “successor” function, which we can specify to
<em>take only</em> positive integers and <em>guarantee to produce only</em> positive integers.</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">{-@ succ :: {v : Int | v &gt; 0} -&gt; {v : Int | v &gt; 0 } @-}</span>
<span class="n">succ</span> <span class="o">::</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">Int</span>
<span class="n">succ</span> <span class="n">n</span> <span class="o">=</span> <span class="n">n</span> <span class="o">+</span> <span class="mi">1</span>
</code></pre></div></div>

<p>We can be more succinct by declaring a refinement type alias.</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">{-@ type Pos = {v : Int | v &gt; 0} @-}</span>

<span class="cm">{-@ succ :: Pos -&gt; Pos @-}</span>
<span class="n">succ</span> <span class="o">::</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">Int</span>
<span class="n">succ</span> <span class="n">n</span> <span class="o">=</span> <span class="n">n</span> <span class="o">+</span> <span class="mi">1</span>
</code></pre></div></div>

<p>Other arithmetic properties like “multiplication by a positive
integer preserves order” can be specified as well.<sup id="fnref:real-world" role="doc-noteref"><a href="#fn:real-world" class="footnote" rel="footnote">1</a></sup></p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">{-@ type OrderedPair = { pair : (Int,Int) | fst pair &lt; snd pair } @-}</span>

<span class="cm">{-@ escalarMultiplication :: Pos -&gt; OrderedPair -&gt; OrderedPair @-}</span>
<span class="n">escalarMultiplication</span> <span class="o">::</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="kt">Int</span><span class="p">,</span><span class="kt">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="kt">Int</span><span class="p">,</span><span class="kt">Int</span><span class="p">)</span>
<span class="n">escalarMultiplication</span> <span class="n">n</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="n">n</span> <span class="o">*</span> <span class="n">x</span><span class="p">,</span> <span class="n">n</span> <span class="o">*</span> <span class="n">y</span><span class="p">)</span>
</code></pre></div></div>

<p>Note that we can use regular Haskell functions in the predicates, here <code class="language-plaintext highlighter-rouge">fst</code> and
<code class="language-plaintext highlighter-rouge">snd</code> to access the components of the pair. These are available, along with other
functions from the Haskell standard library (the “prelude”), because LH comes bundled
with their specifications (defined using <em>assumptions</em>).
In general, Haskell functions need to be lifted into the logic using <code class="language-plaintext highlighter-rouge">reflect</code>
and other constructs (which I don’t cover here) to be used in specifications.
LH verifies that given an ordered pair, we get back an ordered pair, so that our
specification is <em>correct</em>. But also that this function is only called with
ordered pairs, so that the specification is <em>enforced</em> at every call site.
To accomplish this LH renders the specifications into a collection of <em>constraints</em>
(think of a system of equations) that are passed to an external SMT solver that
verifies the specification.</p>

<p>I think of this as an alternative (or perhaps, complimentary) approach to
property based testing, in which properties are logically proven instead of being
checked against (cleverly) random generated input. In practice, what this means
is that we can express properties of our code and document its behaviour <em>in place</em>.</p>

<h2 id="installation">Installation</h2>

<p>First, we’ll need the Haskell toolchain: <code class="language-plaintext highlighter-rouge">cabal</code> to manage the project
and the <code class="language-plaintext highlighter-rouge">ghc</code> Haskell compiler. The (current) recommended way to install and
manage both is  through <a href="https://www.haskell.org/ghcup/">GHCup</a>.<sup id="fnref:nix" role="doc-noteref"><a href="#fn:nix" class="footnote" rel="footnote">2</a></sup>
After installing it with the default options, install a <code class="language-plaintext highlighter-rouge">ghc</code> version that corresponds
to a LH release (check the <a href="https://ucsd-progsys.github.io/liquidhaskell/install/">docs</a>).
In this tutorial we’ll use  <code class="language-plaintext highlighter-rouge">ghc-9.10.1</code> and <code class="language-plaintext highlighter-rouge">liquidhaskell-0.9.10.1.2</code>.<sup id="fnref:ghc-policy" role="doc-noteref"><a href="#fn:ghc-policy" class="footnote" rel="footnote">3</a></sup></p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ghcup <span class="nb">install </span>ghc 9.10.1
</code></pre></div></div>

<p>The following command bootstraps the creation of our project.
It creates a new cabal project for our tutorial, with the corresponding <code class="language-plaintext highlighter-rouge">base</code>
and <code class="language-plaintext highlighter-rouge">liquidhaskell</code> versions as dependencies,
and configures it to use the corresponding version of <code class="language-plaintext highlighter-rouge">ghc</code>.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir </span>lh-tutorial <span class="o">&amp;&amp;</span> <span class="nb">cd </span>lh-tutorial <span class="o">&amp;&amp;</span> <span class="se">\</span>
cabal init <span class="nt">--lib</span> <span class="nt">--dependency</span><span class="o">=</span><span class="s2">"base==4.20.0.0,liquidhaskell==0.9.10.1.2"</span>  <span class="o">&amp;&amp;</span> <span class="se">\</span>
cabal configure <span class="nt">--with-compiler</span> ghc-9.10.1
</code></pre></div></div>

<p>LH is implemented as a GHC plugin, which modifies the compiler pipeline to deliver
the extracted constrains to an SMT solver for verification.
For it to work, you must have any of the following installed in your system and
accessible from your <code class="language-plaintext highlighter-rouge">$PATH</code> environment variable:
<a href="https://github.com/Z3Prover/z3">Z3</a>, <a href="https://cvc4.github.io/">CVC4</a> or <a href="https://mathsat.fbk.eu/">MathSat</a>
The LH docs recommend Z3, which should be available from your Linux distribution package
manager. On MacOs, it can be installed using <a href="https://brew.sh/">Homebrew</a>: <code class="language-plaintext highlighter-rouge">brew install z3</code>.</p>

<p>To use LH, we need to indicate GHC to use the plugin. We can do so by modifying
the library stanza of the <code class="language-plaintext highlighter-rouge">lh-tutorial.cabal</code>.</p>

<pre><code class="language-cabal">library
    import:           warnings
    exposed-modules:  MyLib
    -- other-modules:
    -- other-extensions:
    build-depends:
        base ==4.20.0.0,
        liquidhaskell ==0.9.10.1.2
    hs-source-dirs:   src
    default-language: Haskell2010
    ghc-options: -fplugin=LiquidHaskell -- ADD THIS LINE!
</code></pre>

<p>This enables LH verification across all modules in the project.
Finally, build the project with <code class="language-plaintext highlighter-rouge">cabal build</code>. If the build succeeds, now LH has
been properly installed within the project. For the time being, you should be
notified that no constraints where checked.</p>

<h2 id="dummy-library">Dummy Library</h2>

<p>Modify the contents of <code class="language-plaintext highlighter-rouge">src/MyLib.hs</code> to include the examples from before.</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">module</span> <span class="nn">MyLib</span> <span class="kr">where</span>

<span class="cm">{-@ type Pos = {v : Int | v &gt; 0} @-}</span>

<span class="cm">{-@ succ :: Pos -&gt; Pos @-}</span>
<span class="n">succ</span> <span class="o">::</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">Int</span>
<span class="n">succ</span> <span class="n">n</span> <span class="o">=</span> <span class="n">n</span> <span class="o">+</span> <span class="mi">1</span>

<span class="cm">{-@ type OrderedPair = { pair : (Int,Int) | fst pair &lt;= snd pair } @-}</span>

<span class="cm">{-@ escalarMultiplication :: Pos -&gt; OrderedPair -&gt; OrderedPair @-}</span>
<span class="n">escalarMultiplication</span> <span class="o">::</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="kt">Int</span><span class="p">,</span><span class="kt">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="kt">Int</span><span class="p">,</span><span class="kt">Int</span><span class="p">)</span>
<span class="n">escalarMultiplication</span> <span class="n">n</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="n">n</span> <span class="o">*</span> <span class="n">x</span><span class="p">,</span> <span class="n">n</span> <span class="o">*</span> <span class="n">y</span><span class="p">)</span>
</code></pre></div></div>

<p>If you <code class="language-plaintext highlighter-rouge">cabal build</code> now, you’ll see that some constraints have actually been
checked. Now you’re ready to work on your own project, using these
steps as a template.</p>

<h2 id="using-a-local-build-of-liquid-haskell">Using a local build of Liquid Haskell</h2>

<p>Since I plan to work on the LH codebase and test my changes across various projects,
I need a way to use my local build. We now examine a couple of approaches, broadly
described
<a href="https://stackoverflow.com/questions/69773999/how-do-i-get-cabal-to-use-a-local-version-of-a-package-as-a-dependency-for-a-hac">here</a>,
to accomplish this.</p>

<p>We start by cloning LH source with the <code class="language-plaintext highlighter-rouge">--recurse-submodules</code> flag so that
the <code class="language-plaintext highlighter-rouge">liquid-fixpoint</code> package is also cloned (needed for the build).</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone <span class="nt">--recurse-submodules</span> https://github.com/ucsd-progsys/liquidhaskell.git
</code></pre></div></div>

<p>The upstream source is developed against the <code class="language-plaintext highlighter-rouge">ghc</code> version corresponding to its
latest realease, so make sure to install it (at the time of writing its <code class="language-plaintext highlighter-rouge">9.12.2</code>).
The build instructions can be found at the source repository
<a href="https://github.com/ucsd-progsys/liquidhaskell/blob/192b8766a521c6bef8be2b61c6fda3a1b53783fb/README.md">README</a>,
suggest using the following command:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cabal build liquidhaskell
</code></pre></div></div>

<p>This <em>should</em> build, but cabal is known to have its quirks. If it does, proceed
to the next section. If it doesn’t, carefully check the installation
documentation at the source repository and the documentation site.
It is possible that your current cabal library version does not
support the needed <code class="language-plaintext highlighter-rouge">ghc</code> version (check the error message), so you might need to
change (<em>set</em>) it. Installation and <em>set</em> of different versions of Haskell tools
can be done within <code class="language-plaintext highlighter-rouge">ghcup tui</code>. If the problem persists, consider rising an
<a href="https://github.com/ucsd-progsys/liquidhaskell/issues">issue</a>.</p>

<h3 id="symlink">Symlink</h3>

<p>The simplest way to use our build in a project is
to create a symlink to our <code class="language-plaintext highlighter-rouge">liquidhaskell</code> local repository in our project.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ln</span> <span class="nt">-s</span> /path/to/liquidhaskell/ /path/to/lh-tutorial/
</code></pre></div></div>

<p>For <code class="language-plaintext highlighter-rouge">cabal build</code> to pick it, we point to it in a
<code class="language-plaintext highlighter-rouge">cabal.project</code> file within the <code class="language-plaintext highlighter-rouge">lh-tutorial</code> project.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s2">"package: . liquidhaskell"</span> <span class="o">&gt;</span> cabal.project
</code></pre></div></div>

<h3 id="local-repository">Local Repository</h3>

<p>As an alternative, we can create a local package repository for cabal to
fetch the dependency from instead of <a href="https://hackage.haskell.org/">Hackage</a>.
The advantage of this approach is that we can easily use our build across projects.</p>

<p>First, build the <code class="language-plaintext highlighter-rouge">liquidhaskell</code> package tarball and place it in the directory
intended for the local repository. You can do this by running this command at the
source repository root.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cabal sdist <span class="nt">-o</span> /absolute/path/to/local/repository
</code></pre></div></div>

<p>Now declare a
<a href="https://cabal.readthedocs.io/en/3.14/config.html#local-no-index-repositories">local no-index repository</a>
in the cabal configuration file (typically found at <code class="language-plaintext highlighter-rouge">$HOME/.cabal/config</code> or
<code class="language-plaintext highlighter-rouge">$HOME/.config/cabal/config</code>) by adding this line:</p>

<pre><code class="language-cabal">repository local-repo
  url: file+noindex:///absolute/path/to/local/repository
</code></pre>

<p>We also need to set our local repository to have a
higher priority than Hackage. This is done by editing the
<code class="language-plaintext highlighter-rouge">active-repositories</code> <a href="https://cabal.readthedocs.io/en/3.14/cabal-project-description-file.html#cfg-field-active-repositories">field</a>
in the cabal config file, putting the local repository at the end of the list.</p>

<pre><code class="language-cabal">active-repositories: hackage.haskell.org, local-repo
</code></pre>

<p>Running <code class="language-plaintext highlighter-rouge">cabal update</code> makes cabal discover and merge our repository into its index.
In this way, every local project having <code class="language-plaintext highlighter-rouge">liquidhakell == 0.9.10.1.2</code> as a dependency
will fetch our tarball build instead of Hackage’s.
A downside of this approach is that we will need to erase the <code class="language-plaintext highlighter-rouge">.cache</code> file
(that cabal puts in our local repository directory) whenever we update our build
tarball.</p>

<h2 id="wrap-up">Wrap Up</h2>

<p>In this tutorial, we covered how to enable and use Liquid Haskell in a project,
as well as how to apply your local build across multiple projects. This should
give you everything needed to start building with LH or contribute to its source
code. Now go break some (verified) code!</p>
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:real-world" role="doc-endnote">
      <p>Liquid Haskell has been used to specify and verify complex properties in significant portions of major Haskell libraries. See <em>LiquidHaskell: Experience with Refinement Types in the Real World</em> @ <a href="https://dl.acm.org/doi/10.1145/2633357.2633366">https://dl.acm.org/doi/10.1145/2633357.2633366</a>. <a href="#fnref:real-world" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:nix" role="doc-endnote">
      <p>Other common alternatives are using the <a href="https://www.haskellstack.org/">Stack build tool</a> or the <a href="https://nixos.org/">Nix package manager</a>. Nix is a comprehensive tool (and language!) for reproducible package deployment, which can also be use to create declarative development environments. <a href="#fnref:nix" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:ghc-policy" role="doc-endnote">
      <p>As mentioned in the <a href="https://github.com/ucsd-progsys/liquidhaskell/">LH source repository README</a>, LH is developed against a specific version of <code class="language-plaintext highlighter-rouge">ghc</code> given its tight dependence on the <code class="language-plaintext highlighter-rouge">ghc</code> library which tends to break existing code without notice (in particular, because a distinction does not yet exists between public and internal API’s). At the moment of writing, previous versions of <code class="language-plaintext highlighter-rouge">liquidhaskell</code> are not maintained, so that new features and bug fixes reach only the next major and minor releases monotonically. <a href="#fnref:ghc-policy" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Xavier Góngora</name></author><category term="programming languages" /><category term="type systems" /><category term="formal methods" /><category term="software verification" /><category term="tutorial" /><category term="haskell" /><summary type="html"><![CDATA[In this tutorial post, I introduce Liquid Haskell (LH), present a step-by-step installation procedure, and work through a simple example of its use. As a bonus, we will see how to use a local LH build in our projects.]]></summary></entry><entry><title type="html">Live coding with Tidal Cycles Workshop in Tepoztlán</title><link href="https://ninioartillero.github.io/2024/06/08/tidal-init.html" rel="alternate" type="text/html" title="Live coding with Tidal Cycles Workshop in Tepoztlán" /><published>2024-06-08T00:00:00+00:00</published><updated>2024-06-08T00:00:00+00:00</updated><id>https://ninioartillero.github.io/2024/06/08/tidal-init</id><content type="html" xml:base="https://ninioartillero.github.io/2024/06/08/tidal-init.html"><![CDATA[<p>Last year I got a Tidal Cycles micro-grant in October to organize a live coding introductory workshop in Tepoztlán.<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>
My first son was born the month after and it has been an awesome ride!
This little person is quite demanding, but also incredibly inspiring.
I was finally able to give the workshop on March this year.</p>

<p><img src="/imgs/2024-tidal-init/cartel.png" alt="Workshop flyer." /></p>

<h2 id="tepoztlán">Tepoztlán</h2>

<p>Tepoztlán is located about 70 kilometers south of Mexico City,
in a valley of steep mountains (that seem to have been pushed out from the underground) and lush glens during rainy season.
It is a town proud of its traditions with a remarkable cultural and religious syncretism.
I’ve been living here for 7 years, and will continue for the foreseeable future.</p>

<p><img src="/imgs/2024-tidal-init/5.jpg" alt="View from the &quot;Fernando Martín Juez&quot; Cultural Center dinning room." /></p>

<p>We are currently facing environmental and social imbalance caused by a complex
real state black market, that neglects the National Park status and regulations,
and annual fires that threaten the ecosystem.
In this context, nurturing community is critical to counteract the dismantling of the social fabric.
This is no easy task, as the social spheres seem to orbit different stars at times.
Before this workshop, I gave a talk at the central church about algorithms and live coding practice.
So this is a second effort towards sharing both my artistic and research interests with my local community,
as most of my activities are usually online or in Mexico City.</p>

<h2 id="assistants-and-venue">Assistants and venue</h2>

<p><img src="/imgs/2024-tidal-init/7.jpg" alt="The four workshop participants." /></p>

<p>Four people came to the workshop. Alejandro is an economist, but works as a carpenter for a living.
Roberto is a front-end developer and environmental activist that links the preservation of the mountains and forests with
the rights of the indigenous people of Tepoztlán.
A second Alejandro is a high school senior involved with his neighborhood committee, he wants to study to become a mechatronics engineer.
Finally, Oscar is a systems engineer and part of the Forest Ranger Association of Tepoztlán.
All of them are native to Tepoztlán and value art as an expression of freedom.
They are pretty aware of the contradictions and tensions that their hometown hosts.</p>

<p><img src="/imgs/2024-tidal-init/8.jpg" alt="Goodbye photo." /></p>

<p>The venue was Fernando Martín Juez’s house in the Santa Cruz neighborhood near the west mountain side.
Fernando was an architect and designer that appointed his house to become a Cultural Center after his passing.
He made the necessary arrangements for an association of friends and neighbors to manage the place and make it a contribution to the people of Tepoztlán.
Unfortunately, the funds he left to kickstart activities are being held hostage by a bank (legal action has moved slowly),
and the doors have stayed shut except for some isolated events (of which ours is an example).
The house has an exotic architecture, a rich color palette, and is full of little artifacts that Fernando collected.
It was really a nice place to held the workshop and could become a spot for regular live coding sessions.</p>

<h2 id="the-workshop">The workshop</h2>

<p>For the first half of the workshop I gave an introductory talk.
First we discussed free and open source software as a
strategy to harness community efforts and build people centered technology.
Then I introduced the broader live coding practice, sharing some online references, and
explained what it meant in the context of computer music.
This set the stage to introduce Tidal’s architecture.
Before the break, we watched a video performance of Alex McLean (Tidal’s creator) doing a from-scratch session.
The slide presentation is available <a href="https://docs.google.com/presentation/d/e/2PACX-1vQ8h38f0t9CYkyP1UftIe1l-mmtrQjxeYh7i5sU4nfKoINEiV3xXKlgnFXlWsV3QWcKoNI94d-5RFfU/pub?start=false&amp;loop=false&amp;delayms=0">here</a>.</p>

<p><img src="/imgs/2024-tidal-init/3.jpg" alt="Me showing some Tidal type stuff in relation to function signatures." /></p>

<p>After cookies and coffee, the second part of the workshop was about getting hands-on.
I briefly introduced Tidal’s installation procedure with reference to the official documentation for them to attempt an installation at home.
Then I made a live demonstration showing the basics of sound reproduction, the mini-notation and some pattern
transformations (like <code class="language-plaintext highlighter-rouge">fast</code>, <code class="language-plaintext highlighter-rouge">slow</code>, <code class="language-plaintext highlighter-rouge">(&lt;~)</code>, <code class="language-plaintext highlighter-rouge">jux</code> and <code class="language-plaintext highlighter-rouge">rev</code>).
I also talked about function’s inputs and outputs, to provide a better understanding of Tidal’s syntax.
Finally we ran an <a href="https://estuary.mcmaster.ca">estuary</a> session for collective improvisation.
It was fun seeing them go wild with the few functions I showed them.</p>

<h2 id="aftermath">Aftermath</h2>

<p>In this first workshop I might have overwhelmed the participants by showing too much notation too soon.
Next time we could do short solo test rounds when introducing syntax elements.
This might improve the understanding of all and help build confidence.
Furthermore, those rounds could be structured by following an introductory tutorial.</p>

<p>This was fun and I hope more people join, but I know developing a practice community takes time.
It’s not easy for people to commit, specially with everyone being so busy.
I’ll keep making the call so anyone near looking for something like live coding can find us.</p>

<p><a href="/actividades/2024-tidal-init.html">Workshop pictures and details (in spanish).</a></p>
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Thanks to the Tidal Cycles contributors of the <a href="https://opencollective.com/tidalcycles">Open Collective</a> for making it possible through a micro-grant. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Xavier Góngora</name></author><category term="report" /><category term="live coding" /><category term="workshop" /><category term="tidal cycles" /><summary type="html"><![CDATA[Last year I got a Tidal Cycles micro-grant in October to organize a live coding introductory workshop in Tepoztlán.1 My first son was born the month after and it has been an awesome ride! This little person is quite demanding, but also incredibly inspiring. I was finally able to give the workshop on March this year. Thanks to the Tidal Cycles contributors of the Open Collective for making it possible through a micro-grant. &#8617;]]></summary></entry><entry><title type="html">Btrfs y respaldo de sistemas</title><link href="https://ninioartillero.github.io/2023/09/06/btrfs-doom.html" rel="alternate" type="text/html" title="Btrfs y respaldo de sistemas" /><published>2023-09-06T00:00:00+00:00</published><updated>2023-09-06T00:00:00+00:00</updated><id>https://ninioartillero.github.io/2023/09/06/btrfs-doom</id><content type="html" xml:base="https://ninioartillero.github.io/2023/09/06/btrfs-doom.html"><![CDATA[<p>Nunca había dedicado mucho tiempo a pensar sobre el <a href="https://www.freecodecamp.org/news/file-systems-architecture-explained/">sistema de archivos</a> de mi computadora.
Desde el punto de vista de un usuario, los detalles de este tipo de tecnología son irrelevantes hasta que algo falla;
se encuentra en un muy bajo nivel y es manejado por el sistema operativo. Su función es definir el uso de la memoria en disco.
Hasta hace poco, lo único que había investigado sobre sistemas de archivos era en relación a temas de compatibilidad.<sup id="fnref:exfat" role="doc-noteref"><a href="#fn:exfat" class="footnote" rel="footnote">1</a></sup></p>

<h2 id="btrfs-en-garuda-linux">Btrfs en Garuda Linux</h2>

<p>Fue al instalar <a href="https://garudalinux.org">Garuda Linux</a> en mi <em>desktop</em> que empecé a indagar en el tema. Una de sus características emblemáticas es el uso de <em>snapshots</em> de <a href="https://btrfs.readthedocs.io/en/latest/index.html">Btrfs</a> como estrategia de recuperación del sistema:<sup id="fnref:btrfs" role="doc-noteref"><a href="#fn:btrfs" class="footnote" rel="footnote">2</a></sup> En caso de que el sistema se rompa, lo cual sucede en ocasiones al actualizarlo, se puede acceder a una lista imágenes previas del sistema desde el menú arranque (<a href="https://en.wikipedia.org/wiki/GNU_GRUB">GRUB</a>). Estas imágenes (las <em>snapshots</em>) se toman de manera automática antes y después de cada actualización del sistema.
Esta característica específica permite utilizar <a href="https://wiki.archlinux.org/title/Arch_Linux">Arch Linux</a>, en la que se basa Garuda,<sup id="fnref:garuda" role="doc-noteref"><a href="#fn:garuda" class="footnote" rel="footnote">3</a></sup> de manera <em>confiable</em>. Arch es una distribución
que (valga la redundancia) distribuye el software directo desde los repositorios de sus desarrolladores (<em>upstream</em>) de manera continua.<sup id="fnref:rolling" role="doc-noteref"><a href="#fn:rolling" class="footnote" rel="footnote">4</a></sup> La ventaja: siempre se tienen los ultimos
arreglos, parches de seguridad y características. La desventaja: las cosas pueden salir mal y un programa o todo el sistema puede dejar de funcionar.
Ambas son razones por las que Arch Linux es una distribución considerada exclusiva para usuarios de Linux expertos o entusiastas.<sup id="fnref:arch" role="doc-noteref"><a href="#fn:arch" class="footnote" rel="footnote">5</a></sup> Btrfs tiene la capacidad de crear <em>snapshots</em> con un costo computacional prácticamente nulo.<sup id="fnref:bemoles" role="doc-noteref"><a href="#fn:bemoles" class="footnote" rel="footnote">6</a></sup> Explicar que es exactamente una <em>snapshot</em> en Btrfs excede la intención de este <em>post</em>;<sup id="fnref:snap" role="doc-noteref"><a href="#fn:snap" class="footnote" rel="footnote">7</a></sup> baste decir que se trata de una imagen (de alguna parte) del sistema que permite revertir los cambios en caso necesario. Así, en caso de que algo se rompa al actualizar el sistema, podemos revertir los cambios sin mayor problema.</p>

<p>Es importante mencionar que estas <em>snapshots</em> <strong>no son una una solución de respaldo</strong> para la integridad de los archivos (aunque se puede implementar con ellas). Dada la naturaleza de Btrfs, y los sistemas de archivos CoW, si un archivo está corrupto entonces lo está para todas las <em>snapshots</em> que lo comparten.</p>

<p>Tuve que investigar estas cosas debido a que cuando instalé Garuda cometí un error inocente. Decidí hacerle caso a un <a href="https://youtu.be/iBDIj-J3U28?si=NQ3gv1MOjY_fqmPj">video tutorial</a> de instalación en que se creaba una partición Btrfs separada para guardar los archivos personales (<code class="language-plaintext highlighter-rouge">/home</code>). Experiencias previas con otras distribuciones de Linux me habián enseñado la ventaja de tener particiones separadas para los archivos del sistema (<code class="language-plaintext highlighter-rouge">/</code>) y los archivos personales.
Sin embargo esto no aplicaba de la misma manera en Garuda.
Al hacer la partición, evité que el instalador de Garuda ubicara <code class="language-plaintext highlighter-rouge">/home</code> en su propio <em>subvolumen</em>. Los subvolúmenes de Btrfs son similares a una partición, pues
permiten administrarla de manera independiente gracias a que establecen un tipo de división lógica, con la capacidad extra de acceder al almacenamiento disponible de forma dinámica.<sup id="fnref:subvol" role="doc-noteref"><a href="#fn:subvol" class="footnote" rel="footnote">8</a></sup>
En Garuda se crean por defecto snapshots de <code class="language-plaintext highlighter-rouge">/</code>, cada vez que se hace una actualización del sistema. Para ilustrar como funciona esto hay que considerar el arreglo de subvolúmenes que hace Garuda al instalar el sistema:<sup id="fnref:suse" role="doc-noteref"><a href="#fn:suse" class="footnote" rel="footnote">9</a></sup></p>

<table>
  <thead>
    <tr>
      <th>Nombre del subvolumen</th>
      <th>Punto de montaje</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>@</td>
      <td>/</td>
    </tr>
    <tr>
      <td>@root</td>
      <td>/root</td>
    </tr>
    <tr>
      <td>@srv</td>
      <td>/srv</td>
    </tr>
    <tr>
      <td>@cache</td>
      <td>/var/cache</td>
    </tr>
    <tr>
      <td>@log</td>
      <td>/var/log</td>
    </tr>
    <tr>
      <td>@tmp</td>
      <td>/var/tmp</td>
    </tr>
    <tr>
      <td>@home</td>
      <td>/home</td>
    </tr>
  </tbody>
</table>

<p>La función de este arreglo de subvolúmenes es omitir los directorios correspondientes de las snapshots de <code class="language-plaintext highlighter-rouge">/</code>. Estos contienen archivos que no conviene revertir al volver a un estado anterior del sistema. <code class="language-plaintext highlighter-rouge">/home</code> contiene los archivos y configuraciones personales de los usuarios. <code class="language-plaintext highlighter-rouge">/root</code> es análogo a <code class="language-plaintext highlighter-rouge">/home</code> para el usuario <em>root</em>. <code class="language-plaintext highlighter-rouge">/var/cache</code> contiene archivos transitorios de las aplicaciones. <code class="language-plaintext highlighter-rouge">/var/log</code> es para los registros del sistema. <code class="language-plaintext highlighter-rouge">/var/tmp</code> contiene archivos temporales que las aplicaciones preservan entre reinicios. <code class="language-plaintext highlighter-rouge">/srv</code> contiene archivos relacionados con servicios de red proporcionados por el sistema.<sup id="fnref:fhs" role="doc-noteref"><a href="#fn:fhs" class="footnote" rel="footnote">10</a></sup></p>

<p>Tener <code class="language-plaintext highlighter-rouge">/home</code> en una partición separada me impidía administrarla con las herramientas de Garuda que dependen de este arreglo, aunque la partición fuera también Btrfs. Además me empecé a quedar con espacio limitado en el disco para mis archivos. La solución que encontré a esto, evitando reinstalar todo el sistema, está documentada en el <a href="https://forum.garudalinux.org/t/moving-home-partition-to-a-btrfs-subvolume/26336/10">foro de Garuda</a>.</p>

<h2 id="respaldar-doom-emacs">Respaldar Doom Emacs</h2>

<p>Lograr utilizar lo aprendido sobre Btrfs para idear una simple estrategia para respaldar mi editor de texto me inspiró a escribir este <em>post</em>. Utilizó <a href="https://github.com/doomemacs/doomemacs">Doom Emacs</a>: una esquema de configuración para el clásico editor de texto hacker <a href="https://www.gnu.org/software/emacs/download.html">Emacs</a>. El problema con Doom es similar a Arch: muchos de los paquetes se actualizan regularmente siguiendo al <em>upstream</em>, además de que la configuración de Emacs puede ser temperamental <em>per se</em>. Esto me ha llevado en muchas ocasiones (significativamente más de las que me han sucedido con Arch), a que Doom deje de funcionar después de una actualización. La siguiente estrategia sólo aplica a <a href="https://en.wikipedia.org/wiki/Operating_system#Unix_and_Unix-like_operating_systems">sistemas operativos tipo-unix</a> donde <code class="language-plaintext highlighter-rouge">/home/user</code> (denotado <code class="language-plaintext highlighter-rouge">~</code>) es (parte de) un sistema de archivos Btrfs.</p>

<h3 id="la-estrategia">La estrategia</h3>

<p>Lo primero es mudar Doom Emacs a un subvolumen, para ello hay que:</p>

<p>Cambiar el nombre del directorio donde se guardan los componentes de Doom,</p>

<p><code class="language-plaintext highlighter-rouge">mv ~/.emacs.d ~/.emacs.d.bak</code></p>

<p>crear un subvolumen para la nueva ubicación con el nombre que liberamos</p>

<p><code class="language-plaintext highlighter-rouge">sudo btrfs subvolume create ~/.emacs.d</code></p>

<p>y copiar todos los archivos (con sus propiedades) a la nueva ubicación:</p>

<p><code class="language-plaintext highlighter-rouge">cp -a ~/.emacs.d.bak/* ~/.emacs.d</code></p>

<p>Este último paso es relativamente innecesario, pues Doom es declarativo y su especificación se encuentra en <code class="language-plaintext highlighter-rouge">~/.doom.d</code>:<sup id="fnref:doom" role="doc-noteref"><a href="#fn:doom" class="footnote" rel="footnote">11</a></sup> bastaría correr <code class="language-plaintext highlighter-rouge">doom sync -u</code> para volver a poblar esta ubicación. Sin embargo es una descarga grande, que toma algo de tiempo y que podemos omitir.</p>

<p>Si Doom está funcionando correctamente, podemos borrar el respaldo con <code class="language-plaintext highlighter-rouge">rm -rf ~/.emacs.d.bak</code>.</p>

<p><strong>La estrategia consiste en crear una snaphot de solo escritura, o <em>read-only</em>,<sup id="fnref:snap:1" role="doc-noteref"><a href="#fn:snap" class="footnote" rel="footnote">7</a></sup> antes una actualización</strong>.</p>

<p><code class="language-plaintext highlighter-rouge">sudo btrfs subvolume snapshot -r ~/.emacs.d/ ~/.emacs.d.bak.ro</code></p>

<p>En caso de que la actualización deje a Doom fuera de combate, los siguientes pasos lo reviertiran a su estado anterior:</p>

<ol>
  <li>Borrar la configuración defectuosa: <code class="language-plaintext highlighter-rouge">sudo btrfs subvolume delete ~/emacs.d/</code></li>
  <li>Restaurar la vieja configuración: <code class="language-plaintext highlighter-rouge">sudo btrfs subvolume snapshot ~/.emacs.d.bak.ro ~/.emacs.d</code></li>
</ol>

<p>Doom Emacs es un editor fantástico, y ahora no tengo reservas en actualizarlo más cotidianamente. Por su parte Btrfs me ha demostrado las posbilididades de los sistemas de archivos.</p>

<hr />
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:exfat" role="doc-endnote">
      <p>Cuando tuve que formatear un disco externo para respaldo de video de alta definición descubrí que exFAT es LA opción de sistema de archivos para soporte multiplataforma. FAT32 es mejor en cuanto a compatibilidad, pero limita los archivos a un tamaño máximo de 4 GB. <a href="#fnref:exfat" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:btrfs" role="doc-endnote">
      <p>Garuda es una de las primeras distribuciones que ofreció Btrfs como sistema de archivos por defecto. Este es un sistema de archivos <em>copy-on-write</em>(CoW), lo que permite la creación ágil de <em>snapshots</em>. Otro sistema de archivos CoW muy querido por los administradores de sistemas es <a href="https://en.wikipedia.org/wiki/ZFS">ZFS</a>, creado originalmente por Sun Microsystems. <a href="#fnref:btrfs" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:garuda" role="doc-endnote">
      <p>Quizás sería más claro pensar Garuda Linux como una configuración empaquetada de Arch Linux. Sin embargo hay características que le hacen merecer el título de distribución derivada:</p>

      <ul>
        <li>Incluye dos repositorios adicionales: garuda (desde donde distribuyen sus propias configuraciones y <em>scripts</em>) y <a href="https://aur.chaotic.cx/">chaotic-aur</a>.</li>
        <li>Utilizan <a href="https://calamares.io/">Calamares</a> para instalación con interfaz gráfica.</li>
        <li>Además de la curaduría de paquetes pre-instalados, mantienen varios programas propios para la administración del sistema.</li>
        <li>Su script de instalación, <code class="language-plaintext highlighter-rouge">garuda-update</code>, envuelve al comando regular de actualización de Arch (<code class="language-plaintext highlighter-rouge">sudo pacman -Syu</code>). Esto les permite incluir arreglos desde la actualización.</li>
        <li>Mientras no se utilizen las herramientas de Garuda, la experiencia de uso y administración es identica a la de Arch.</li>
      </ul>
      <p><a href="#fnref:garuda" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:rolling" role="doc-endnote">
      <p>A esto se le conoce como modelo <a href="https://itsfoss.com/rolling-release/"><em>rolling release</em></a>. <a href="#fnref:rolling" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:arch" role="doc-endnote">
      <p>Otra razón es que su instalación, sin la mediación de una distribución preconfigurada como Garuda Linux o EndeavorOS, involucra la elección e instalación de todos los componentes del sistema desde una terminal. <a href="#fnref:arch" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:bemoles" role="doc-endnote">
      <p>Las ventajas de Btrfs tienen sus costos: este sistema de archivos requiere de más acciones de mantenimiento por parte del usuario, en comparación a ext4 (el estándar en Linux). Por ejemplo, es necesario borrar las <em>snapshots</em> viejas, ya que con el paso del tiempo sus diferencias con el sistema en operación crecen y llegan a ocupar mucho espacio en disto. En Garuda el mantenimiento está automatizado utilizando herramientas como <a href="https://github.com/kdave/btrfsmaintenance">btrfsmaintenance</a> y <a href="http://snapper.io/">snapper</a>. <a href="#fnref:bemoles" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:snap" role="doc-endnote">
      <p>En Btrfs, una <em>snapshot</em> es esencialmente un <em>subvolumen</em>. Ver <a href="https://fedoramagazine.org/working-with-btrfs-snapshots/">Fedora Magazine: Workging with Btrfs - Snapshots</a> <a href="#fnref:snap" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:snap:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:subvol" role="doc-endnote">
      <p>Por ejemplo, resulta trivial añadir un nuevo dispositivo de almacenamiento al sistema y redistribuir los archivos entre todos los dispositivos disponibles: simplemente se lo conecta, se añade al pozo de dispositivos y luego se da la instrucción de balancear el sistema de archivos. Para detalles ver este <a href="https://www.techrepublic.com/article/how-to-add-a-device-on-btrfs-system/">tutorial</a>. <a href="#fnref:subvol" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:suse" role="doc-endnote">
      <p>En Garuda el arreglo de subvolúmenes, utilizado por snapper, es <a href="https://archive.kernel.org/oldwiki/btrfs.wiki.kernel.org/index.php/SysadminGuide.html#Flat">plano</a> y está probablemente inspirado en el <a href="https://en.opensuse.org/SDB:BTRFS">arreglo de openSUSE</a>. <a href="#fnref:suse" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:fhs" role="doc-endnote">
      <p>Estos roles están especificados en la <a href="https://refspecs.linuxfoundation.org/FHS_3.0/fhs-3.0.html">Filesystem Hierarchy Standard (FHS)</a> a la que se apega Arch Linux. <a href="#fnref:fhs" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:doom" role="doc-endnote">
      <p>En este directorio se ubican tres archivos: uno para la especificación de componentes (<code class="language-plaintext highlighter-rouge">init.el</code>), otro para las opciones de configuración (<code class="language-plaintext highlighter-rouge">config.el</code>) y uno para paquetes adicionales (<code class="language-plaintext highlighter-rouge">packages.el</code>). <a href="#fnref:doom" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Xavier Góngora</name></author><category term="technology" /><category term="linux" /><category term="filesystem" /><category term="btrfs" /><summary type="html"><![CDATA[Nunca había dedicado mucho tiempo a pensar sobre el sistema de archivos de mi computadora. Desde el punto de vista de un usuario, los detalles de este tipo de tecnología son irrelevantes hasta que algo falla; se encuentra en un muy bajo nivel y es manejado por el sistema operativo. Su función es definir el uso de la memoria en disco. Hasta hace poco, lo único que había investigado sobre sistemas de archivos era en relación a temas de compatibilidad.1 Cuando tuve que formatear un disco externo para respaldo de video de alta definición descubrí que exFAT es LA opción de sistema de archivos para soporte multiplataforma. FAT32 es mejor en cuanto a compatibilidad, pero limita los archivos a un tamaño máximo de 4 GB. &#8617;]]></summary></entry><entry><title type="html">Bloggear pa’ que no se apeste</title><link href="https://ninioartillero.github.io/general/2023/08/04/bloggear.html" rel="alternate" type="text/html" title="Bloggear pa’ que no se apeste" /><published>2023-08-04T00:00:00+00:00</published><updated>2023-08-04T00:00:00+00:00</updated><id>https://ninioartillero.github.io/general/2023/08/04/bloggear</id><content type="html" xml:base="https://ninioartillero.github.io/general/2023/08/04/bloggear.html"><![CDATA[<p>Este <em>blog</em> tendrá la función de ventilar ideas en proceso, divulgar mis resultados de investigación y, en general, ser mi canal principal de comunicación con la internet.
Su temática se irá definiendo sobre la marcha, pero anticipo abordar temas relacionados con música, tecnología, programación y matemáticas; así como prácticas como la composición algorítmica, el <em>live coding</em> y la producción musical.</p>]]></content><author><name>Xavier Góngora</name></author><category term="general" /><summary type="html"><![CDATA[Este blog tendrá la función de ventilar ideas en proceso, divulgar mis resultados de investigación y, en general, ser mi canal principal de comunicación con la internet. Su temática se irá definiendo sobre la marcha, pero anticipo abordar temas relacionados con música, tecnología, programación y matemáticas; así como prácticas como la composición algorítmica, el live coding y la producción musical.]]></summary></entry><entry><title type="html">Que pedo Mundo</title><link href="https://ninioartillero.github.io/2023/03/27/hola-mundo.html" rel="alternate" type="text/html" title="Que pedo Mundo" /><published>2023-03-27T00:00:00+00:00</published><updated>2023-03-27T00:00:00+00:00</updated><id>https://ninioartillero.github.io/2023/03/27/hola-mundo</id><content type="html" xml:base="https://ninioartillero.github.io/2023/03/27/hola-mundo.html"><![CDATA[<p>Dios dijo</p>

<blockquote>
  <p>Qué pedo Mundo</p>
</blockquote>

<p>y el mundo surgió del caos primigenio.</p>]]></content><author><name>ninioArtillero</name></author><category term="poetry" /><summary type="html"><![CDATA[Dios dijo]]></summary></entry></feed>