<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Brian J. Cardiff</title>
    <description>The latest articles on DEV Community by Brian J. Cardiff (@bcardiff).</description>
    <link>https://dev.to/bcardiff</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F299%2F459923.png</url>
      <title>DEV Community: Brian J. Cardiff</title>
      <link>https://dev.to/bcardiff</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bcardiff"/>
    <language>en</language>
    <item>
      <title>¿Cómo instalar Haskell?</title>
      <dc:creator>Brian J. Cardiff</dc:creator>
      <pubDate>Mon, 24 Mar 2025 18:49:12 +0000</pubDate>
      <link>https://dev.to/bcardiff/como-instalar-haskell-40ml</link>
      <guid>https://dev.to/bcardiff/como-instalar-haskell-40ml</guid>
      <description>&lt;p&gt;Hay varias opciones para instalar las herramientas necesarias para programar en Haskell y también varias opciones sobre cómo usarlas. A continuación se presenta una serie de pasos y algunas opciones para que elijamos según nuestra preferencia. No es una guía exhaustiva. El objetivo es disponer de un entorno moderno que nos permita experimentar y aprender el lenguaje.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/jgWWg_o5lf0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  GHCup
&lt;/h2&gt;

&lt;p&gt;Primero vamos a instalar el instalador GHCup. En &lt;a href="https://www.haskell.org/ghcup/" rel="noopener noreferrer"&gt;https://www.haskell.org/ghcup/&lt;/a&gt; vamos a encontrar el siguiente comando que funciona para Linux, macOS, FreeBSD o &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/" rel="noopener noreferrer"&gt;WSL2&lt;/a&gt; y lo podemos ejecutar desde una terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nos va a hacer algunas preguntas, podemos usar las opciones por defecto que son buenas.&lt;/p&gt;

&lt;p&gt;Después de ejecutar el comando de arriba vamos a tener un ejecutable de &lt;code&gt;ghcup&lt;/code&gt; en &lt;code&gt;~/.ghcup/bin&lt;/code&gt; (ese &lt;code&gt;~&lt;/code&gt; representa la ruta de su usuario: seguramente &lt;code&gt;/home/nombreusuario&lt;/code&gt;,  &lt;code&gt;/Users/nombreusuario&lt;/code&gt; o &lt;code&gt;/mnt/c/Users/nombreusuario&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;Tenemos que verificar si el directorio &lt;code&gt;~/.ghcup/bin&lt;/code&gt; está en el &lt;code&gt;PATH&lt;/code&gt; o no. Ejecutando &lt;code&gt;ghcup --version&lt;/code&gt; deberíamos ver algo como lo siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% ghcup --version
The GHCup Haskell installer, version 0.1.40.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si en cambio ven algo como &lt;code&gt;command not found&lt;/code&gt; significa que  &lt;code&gt;~/.ghcup/bin&lt;/code&gt; no está en el &lt;code&gt;PATH&lt;/code&gt; y debemos agregarlo. Cómo, depende de qué sistema operativo y &lt;em&gt;shell&lt;/em&gt; usemos, pero tenemos que agregar &lt;code&gt;~/.ghcup/bin&lt;/code&gt; al &lt;code&gt;PATH&lt;/code&gt;. Seguramente necesitemos poner la ruta completa de &lt;code&gt;~&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Por ejemplo si usan macOS y zsh agregando lo siguiente a &lt;code&gt;~/.zprofile&lt;/code&gt; vamos a lograr tener &lt;code&gt;ghcup&lt;/code&gt; en el path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export PATH="/Users/nombreusuario/.ghcup/bin:$PATH"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si hacemos algún cambio para modificar el &lt;code&gt;PATH&lt;/code&gt; cerremos y vuelvamos a abrir la terminal. Probemos si &lt;code&gt;ghcup --version&lt;/code&gt; anda esta vez.&lt;/p&gt;

&lt;p&gt;Si anduvo ya está la parte más engorrosa.&lt;/p&gt;

&lt;h2&gt;
  
  
  GHC
&lt;/h2&gt;

&lt;p&gt;GHC es un compilador del lenguaje Haskell. Hay muchas versiones. GHCup permite elegir entre ellas, instalar una o varias versiones y definir cuál es la versión por defecto que se va a usar cuando se ejecute el comando &lt;code&gt;ghc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Entre todas las versiones hay una que se llama &lt;em&gt;recommended&lt;/em&gt;. Actualmente es la 9.4.8.&lt;/p&gt;

&lt;p&gt;Si ejecutamos &lt;code&gt;ghcup tui&lt;/code&gt; vamos a ver un menu para elegir instalar (presionando &lt;code&gt;i&lt;/code&gt;) y establecer como default (presionando &lt;code&gt;s&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% ghcup tui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seguramente ya tengamos instalada y establecida la versión recomendada de GHC. GHCup hace eso por defecto. Deberíamos ver un doble tilde verde en la primer columna de GHC. Un tilde para instalado y otro tilde para establecido.&lt;/p&gt;

&lt;p&gt;Para verificar si tienen GHC instalado podemos hacer lo siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% ghc --version
The Glorious Glasgow Haskell Compilation System, version 9.4.8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si no funcionó podemos usar los siguientes comandos para instalar y establecer la versión recomendada de GHC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% ghcup install ghc recommended
% ghcup set ghc recommended
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  GHCi
&lt;/h2&gt;

&lt;p&gt;Junto con GHC viene GHCi, el intérprete. Con GHCi podemos experimentar en forma interactiva, sin necesidad de crear archivos incluso.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% ghci
GHCi, version 9.4.8: https://www.haskell.org/ghc/  :? for help
ghci&amp;gt; 1+1
2
ghci&amp;gt; mayor a b = if a &amp;gt; b then a else b
ghci&amp;gt; mayor 3 4
4
ghci&amp;gt; :q
Leaving GHCi.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Trabajando con archivos en GHCi
&lt;/h2&gt;

&lt;p&gt;También se pueden cargar archivos. Si creamos un archivo &lt;code&gt;Ejemplo.hs&lt;/code&gt; (la convención es que empiecen con mayúscula) con el siguiente contenido:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;mayor&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="kr"&gt;else&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos cargarlo en &lt;code&gt;ghci&lt;/code&gt; usando &lt;code&gt;:l Ejemplo.hs&lt;/code&gt; y usar la función definida en él.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% ghci
GHCi, version 9.4.8: https://www.haskell.org/ghc/  :? for help
ghci&amp;gt; :l Ejemplo.hs 
[1 of 2] Compiling Main             ( Ejemplo.hs, interpreted )
Ok, one module loaded.
ghci&amp;gt; mayor 2 4
4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si cambiamos el contenido del archivo con &lt;code&gt;:r&lt;/code&gt; vamos a recargarlo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ghci&amp;gt; :r
[1 of 2] Compiling Main             ( Ejemplo.hs, interpreted ) [Source file changed]
Ok, one module loaded.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Trabajando con VSCode
&lt;/h2&gt;

&lt;p&gt;Si elegimos &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;VSCode&lt;/a&gt; como editor, lo recomendable es instalar extensión &lt;a href="https://marketplace.visualstudio.com/items?itemName=haskell.haskell" rel="noopener noreferrer"&gt;&lt;code&gt;haskell.haskell&lt;/code&gt;&lt;/a&gt;. Se integra con GHCup y cuenta con algunas herramientas adicional.&lt;/p&gt;

&lt;p&gt;La configuración sugerida ( Ctrl + Shift + P o Cmd + Shift + P , &lt;code&gt;&amp;gt; Open User Settings (JSON)&lt;/code&gt;) es la siguiente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"haskell.manageHLS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GHCup"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"haskell.upgradeGHCup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"haskell.toolchain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ghc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"recommended"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"recommended"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"cabal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"recommended"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"stack"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.formatOnSave"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta configuración sólo necesita que GHCup esté en el &lt;code&gt;PATH&lt;/code&gt; y va a bajar otras herramientas cuando las necesite. Si ya tenemos ghc en &lt;code&gt;PATH&lt;/code&gt; podemos omitir ésta configuración.&lt;/p&gt;

&lt;p&gt;Si abrimos el archivo &lt;code&gt;Ejemplo.hs&lt;/code&gt; con el editor vamos a tener coloreo de sintaxis. 🎨&lt;/p&gt;

&lt;p&gt;Seguramente nos aparezca la pregunta "Need to download hls-recommended, continue?". Digamos que sí. Alternativamente podemos instalar la versión recomendada de HLS usando &lt;code&gt;ghcup&lt;/code&gt; como hicimos antes.&lt;/p&gt;

&lt;p&gt;Es posible que necesitemos reiniciar el editor (Ctrl + Shift + P o Cmd + Shift + P , &lt;code&gt;&amp;gt; Developer: Reload Window&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Ahora disponemos de HLS (Haskell Language Server) que nos dará acceso a documentación y otras herramientas integradas para&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dar formato al código usando &lt;code&gt;ormolu&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Sugerencias sintácticas usando &lt;code&gt;hlint&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Anotaciones de tipo usando el algoritmo de inferencia&lt;/li&gt;
&lt;li&gt;Ir a la definición de la función&lt;/li&gt;
&lt;li&gt;Ver documentación&lt;/li&gt;
&lt;li&gt;Evaluar código en líneas que empiezan con &lt;code&gt;-- &amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por ejemplo, si el archivo contiene&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;mayor&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="kr"&gt;else&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;

&lt;span class="c1"&gt;-- &amp;gt;&amp;gt;&amp;gt; mayor 2 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nos va a aparecer un &lt;code&gt;Evaluate...&lt;/code&gt; arriba del &lt;code&gt;-- &amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; que al hacer &lt;em&gt;click&lt;/em&gt; nos dará el resultado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;mayor&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="kr"&gt;else&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;

&lt;span class="c1"&gt;-- &amp;gt;&amp;gt;&amp;gt; mayor 2 3&lt;/span&gt;
&lt;span class="c1"&gt;-- 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Trabajando con múltiples archivos
&lt;/h2&gt;

&lt;p&gt;Tanto GHCi como VSCode pueden operar con múltiples archivos al mismo tiempo. Hay veces que queremos separar el código en distintos módulos, ya sea para restringir interface o por mera organización.&lt;/p&gt;

&lt;p&gt;Supongamos que en una carpeta tenemos &lt;code&gt;Foo.hs&lt;/code&gt; y &lt;code&gt;Bar.hs&lt;/code&gt; con el siguiente contenido&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Foo&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Bar&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Foo&lt;/span&gt;

&lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;

&lt;span class="c1"&gt;-- &amp;gt;&amp;gt;&amp;gt; bar&lt;/span&gt;
&lt;span class="c1"&gt;-- 4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En GHCi podemos cargar cualquiera de los dos módulos con &lt;code&gt;:l&lt;/code&gt; y evaluar sus funciones.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% ghci
GHCi, version 9.4.8: https://www.haskell.org/ghc/  :? for help
ghci&amp;gt; :l Bar.hs 
[1 of 2] Compiling Foo              ( Foo.hs, interpreted )
[2 of 2] Compiling Bar              ( Bar.hs, interpreted )
Ok, two modules loaded.
ghci&amp;gt; bar
4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En VSCode basta con abrir la carpeta que los contiene para que todo funcione y podamos evaluar &lt;code&gt;-- &amp;gt;&amp;gt;&amp;gt; bar&lt;/code&gt; como antes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cabal
&lt;/h2&gt;

&lt;p&gt;Es usual aprovechar paquetes y aplicaciones definidos por otras personas. En Haskell se registran y distribuyen en &lt;a href="https://hackage.haskell.org/" rel="noopener noreferrer"&gt;Hackage&lt;/a&gt;. Para descargar los paquetes o aplicaciones de Hackage se usa &lt;a href="https://www.haskell.org/cabal/" rel="noopener noreferrer"&gt;Cabal&lt;/a&gt;. Si hemos seguido las instrucciones ya tenemos Cabal instalado, sino podemos usar GHCup para obtener la versión recomendada.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% cabal --version
cabal-install version 3.12.1.0
compiled using version 3.12.1.0 of the Cabal library 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A continuación usaremos aplicaciones y paquetes de Hackage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Re-evaluando expresiones
&lt;/h2&gt;

&lt;p&gt;Cada vez que cambiamos un archivo y queremos ver el resultado de nuestro nuevo programa tenemos que alejarnos de donde estamos editando el código para ir a evaluar una expresión.&lt;/p&gt;

&lt;p&gt;Si usamos GHCi tenemos que hacer &lt;code&gt;:r&lt;/code&gt; y escribir la expresión a evaluar.&lt;/p&gt;

&lt;p&gt;Si usamos VSCode podemos llegar a tener ya escrita cerca de la función que estamos editando la expresión a evaluar a continuación de un &lt;code&gt;-- &amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; . Con un &lt;em&gt;click&lt;/em&gt; en &lt;code&gt;Evaluate...&lt;/code&gt;  o &lt;code&gt;Refresh...&lt;/code&gt; obtenemos el resultado.&lt;/p&gt;

&lt;p&gt;Hay otra opción que no require alejarnos del código que estamos editando. La herramienta &lt;a href="https://github.com/ndmitchell/ghcid" rel="noopener noreferrer"&gt;ghcid&lt;/a&gt; permite ejecutar un expresión ni bien se hacen cambios en un archivo.&lt;/p&gt;

&lt;p&gt;Para instalarla primero debemos tener una versión actualizada del índice de paquetes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% cabal update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luego podemos proceder a instalar la aplicación &lt;code&gt;ghcid&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% cabal install ghcid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con el comando anterior la aplicación va a quedar instalada en &lt;code&gt;~/.cabal/bin&lt;/code&gt;. Vamos a necesitar agregar este directorio al &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Como alternativa podemos indicar en qué directorio instalar la aplicación. Por ejemplo en un directorio &lt;code&gt;bin&lt;/code&gt; junto a los archivos que estamos editando.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% cabal install ghcid --installdir=bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Volviendo al ejemplo de &lt;code&gt;Bar.hs&lt;/code&gt;, podemos querer evaluar la función &lt;code&gt;bar&lt;/code&gt; cada vez que hagamos cambios en el archivo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% bin/ghcid Bar.hs --test bar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En la pantalla veremos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4

...done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Probemos cambiar el contenido de &lt;code&gt;Bar.hs&lt;/code&gt; o &lt;code&gt;Foo.hs&lt;/code&gt; y el valor se actualizará.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trabajando con paquetes externos
&lt;/h2&gt;

&lt;p&gt;Para trabajar con paquetes hay dos alternativas&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instalar el paquete que queremos en forma manual y que esté disponible universalmente en la computadora, o bien&lt;/li&gt;
&lt;li&gt;Definir un proyecto cabal y declarar ahí cuales son los paquetes externos que queremos usar.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Forma manual
&lt;/h3&gt;

&lt;p&gt;Por ejemplo si queremos escribir casos de prueba podemos optar por usar el paquete &lt;a href="https://hackage.haskell.org/package/HUnit" rel="noopener noreferrer"&gt;HUnit&lt;/a&gt; e instalarlo de forma manual y que esté disponible universalmente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% cabal install --lib HUnit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luego podemos usarlo directamente al importarlo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Bar&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Foo&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Test.HUnit&lt;/span&gt;

&lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;runTestTTAndExit&lt;/span&gt; &lt;span class="n"&gt;allTests&lt;/span&gt;

&lt;span class="n"&gt;allTests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;test&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;~?=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En GHCi podemos evaluar la función &lt;code&gt;main&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% ghci Bar.hs 
ghci&amp;gt; main
Cases: 1  Tried: 1  Errors: 0  Failures: 0
*** Exception: ExitSuccess
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En VSCode podemos evaluar &lt;code&gt;-- &amp;gt;&amp;gt;&amp;gt; main&lt;/code&gt; pero la salida vamos a verla en la pestaña de OUTPUT si seleccionamos Haskell en la lista de la derecha.&lt;/p&gt;

&lt;p&gt;Con ghcid podemos ejecutar el siguiente comando para correr los test automáticamente con cada cambio.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% bin/ghcid Bar.hs --test main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ Si bien &lt;code&gt;cabal install --lib paquete&lt;/code&gt; anda y parece simple, no es la forma más adecuada de instalar paquetes. Dentro de la comunidad de Haskell se desaconseja usar esta forma. Está disponible por motivos históricos.&lt;/p&gt;

&lt;p&gt;‼️ En VSCode es posible que necesitemos ejecutar el comando &lt;code&gt;Haskell: Restart Haskell LSP Server&lt;/code&gt; (Ctrl + Shift + P o Cmd + Shift + P) para que tome los cambios del entorno.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Definir un proyecto
&lt;/h3&gt;

&lt;p&gt;Cabal nos permite también inicializar un proyecto Haskell. Esto nos sirve para organizar mejor el código en distintas partes pero sobre todo para un mejor manejo de dependencias.&lt;/p&gt;

&lt;p&gt;Para inicializar un proyecto podemos usar &lt;code&gt;cabal init nombreproyecto&lt;/code&gt; y aceptar todas las opciones por defecto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% cabal init nombreproyecto
What does the package build:
   1) Library
 * 2) Executable
   3) Library and Executable
   4) Test suite
Your choice? [default: Executable] 
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos a obtener la siguiente estructura en la carpeta &lt;code&gt;nombreproyecto&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── CHANGELOG.md
├── LICENSE
├── app
│   └── Main.hs
└── nombreproyecto.cabal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos borrar &lt;code&gt;CHANGELOG.md&lt;/code&gt; y &lt;code&gt;LICENSE&lt;/code&gt; para código de prueba.&lt;/p&gt;

&lt;p&gt;El archivo &lt;code&gt;.cabal&lt;/code&gt; tiene información sobre cómo se conforma el proyecto. En particular al final obtenemos algo similar a lo siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;executable nombreproyecto
    import:           warnings
    main-is:          Main.hs
    -- other-modules:
    -- other-extensions:
    build-depends:    base ^&amp;gt;=4.17.2.1
    hs-source-dirs:   app
    default-language: Haskell2010
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;hs-source-dirs&lt;/code&gt; indica dónde va a estar el código, si queremos podemos cambiarlo a &lt;code&gt;src&lt;/code&gt; y cambiar de nombre la carpeta existente &lt;code&gt;app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Cuando hagamos &lt;code&gt;% cabal run&lt;/code&gt; dentro de la carpeta &lt;code&gt;nombreproyecto&lt;/code&gt; va a compilar &lt;code&gt;Main.hs&lt;/code&gt; y ejecutar la función &lt;code&gt;main&lt;/code&gt; definida ahí.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% cabal run
Hello, Haskell!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adaptemos el ejemplo de &lt;code&gt;Foo&lt;/code&gt;, &lt;code&gt;Bar&lt;/code&gt; y &lt;code&gt;HUnit&lt;/code&gt; a este esquema.&lt;/p&gt;

&lt;p&gt;Podemos tener un &lt;code&gt;Bar.hs&lt;/code&gt; y &lt;code&gt;Foo.hs&lt;/code&gt; en el directorio &lt;code&gt;app&lt;/code&gt; junto a &lt;code&gt;Main.hs&lt;/code&gt;. Y dejar el test en &lt;code&gt;Main&lt;/code&gt;, de forma que &lt;code&gt;Bar&lt;/code&gt; sólo tenga el código que queríamos escribir.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Foo&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Bar&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Foo&lt;/span&gt;

&lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Main&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Bar&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Test.HUnit&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;runTestTTAndExit&lt;/span&gt; &lt;span class="n"&gt;allTests&lt;/span&gt;

&lt;span class="n"&gt;allTests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;test&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;~?=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora bien, nos falta actualizar el archivo &lt;code&gt;nombreproyecto.cabal&lt;/code&gt; para declarar&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Qué otros archivos forman parte del proyecto: sí hay que listarlos explícitamente.&lt;/li&gt;
&lt;li&gt;Qué paquetes externos queremos usar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quitemos el comentario a &lt;code&gt;other-modules&lt;/code&gt; para listar &lt;code&gt;Bar&lt;/code&gt; y &lt;code&gt;Foo&lt;/code&gt; para lo primero. Agregamos &lt;code&gt;HUnit&lt;/code&gt; opcionalmente con información de versión.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;executable nombreproyecto
    import:           warnings
    main-is:          Main.hs
    other-modules:
        Bar
        Foo
    -- other-extensions:
    build-depends:    base ^&amp;gt;=4.17.2.1, 
                      HUnit ^&amp;gt;=1.6.2.0
    hs-source-dirs:   app
    default-language: Haskell2010
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si hacemos &lt;code&gt;cabal run&lt;/code&gt; obtenemos el resultado de los tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% cabal run 
Cases: 1  Tried: 1  Errors: 0  Failures: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si hacemos &lt;code&gt;cabal repl&lt;/code&gt; vamos a iniciar un &lt;code&gt;ghci&lt;/code&gt; con todo el proyecto ya cargado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% cabal repl
[1 of 4] Compiling Foo              ( app/Foo.hs, interpreted )
[2 of 4] Compiling Bar              ( app/Bar.hs, interpreted )
[3 of 4] Compiling Main             ( app/Main.hs, interpreted )
Ok, three modules loaded.
ghci&amp;gt; main
Cases: 1  Tried: 1  Errors: 0  Failures: 0
*** Exception: ExitSuccess
ghci&amp;gt; 
Leaving GHCi.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si usamos VSCode el editor va a ayudarnos a navegar entro los archivos y otros beneficios. Cada vez que cambiamos el archivo &lt;code&gt;.cabal&lt;/code&gt; vamos a necesitar hacer un &lt;code&gt;Haskell: Restart Haskell LSP Server&lt;/code&gt; (Ctrl + Shift + P o Cmd + Shift + P) para que tome los cambios del entorno.&lt;/p&gt;

&lt;p&gt;Si usamos &lt;code&gt;ghcid&lt;/code&gt; no necesitamos indicar el archivo &lt;code&gt;Main.hs&lt;/code&gt;, solo la función a evaluar, ya que usa la información de &lt;code&gt;main-is&lt;/code&gt; del archivo &lt;code&gt;.cabal&lt;/code&gt; pero vamos a notar que el resultado de los tests no aparece.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% bin/ghcid --test main
Loading cabal repl --repl-options=-fno-break-on-exception --repl-options=-fno-break-on-error --repl-options=-v1 --repl-options=-ferror-spans --repl-options=-j ...
Build profile: -w ghc-9.4.8 -O1
In order, the following will be built (use -v for more details):
 - nombreproyecto-0.1.0.0 (interactive) (exe:nombreproyecto) (first run)
Preprocessing executable 'nombreproyecto' for nombreproyecto-0.1.0.0...
GHCi, version 9.4.8: https://www.haskell.org/ghc/  :? for help
[1 of 4] Compiling Foo              ( app/Foo.hs, interpreted )

app/Foo.hs:3:1-3: warning: [-Wmissing-signatures]
    Top-level binding with no type signature: foo :: Integer
  |
3 | foo = 2
  | ^^^
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En su lugar aparecen solamente &lt;em&gt;warnings&lt;/em&gt;. Esto es porque nuestro archivo &lt;code&gt;.cabal&lt;/code&gt; indica ser muy estricto con los &lt;em&gt;warnings&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;En este caso los &lt;em&gt;warnings&lt;/em&gt; son porque las funciones &lt;code&gt;foo&lt;/code&gt;, &lt;code&gt;bar&lt;/code&gt; y &lt;code&gt;main&lt;/code&gt; no tiene declaración de tipos. Podemos agregarlas, pero en general cuando estamos modificando código vamos a producir varias situaciones de &lt;em&gt;warnings&lt;/em&gt;: variables no usadas, &lt;em&gt;pattern matchings&lt;/em&gt; no exhaustivos, funciones no exportadas no usadas, etc..&lt;/p&gt;

&lt;p&gt;Si cambiamos el archivo &lt;code&gt;.cabal&lt;/code&gt; para que sea más permisivo y no reportemos &lt;em&gt;warnings&lt;/em&gt; nuestro editor también va a dejar de mostrarlos. Lo recomendado es hacer que &lt;code&gt;ghcid&lt;/code&gt; se más permisivo y nada más. Con la opción &lt;code&gt;--warnings&lt;/code&gt; lo logramos. De esta forma si bien va a seguir reportando los &lt;em&gt;warnings&lt;/em&gt;, para que los vayamos arreglando, no va a dejar de ejecutar la función test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% bin/ghcid --warnings --test main
...

Cases: 1  Tried: 1  Errors: 0  Failures: 0

...done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>haskell</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Generating LaTeX Beamer Handouts without changing files</title>
      <dc:creator>Brian J. Cardiff</dc:creator>
      <pubDate>Thu, 27 Feb 2025 13:18:43 +0000</pubDate>
      <link>https://dev.to/bcardiff/generating-latex-beamer-handouts-without-changing-files-1hjp</link>
      <guid>https://dev.to/bcardiff/generating-latex-beamer-handouts-without-changing-files-1hjp</guid>
      <description>&lt;p&gt;When using LaTeX, it's common to use Beamer to create slides for presentations. Typically, a Beamer document starts like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tex"&gt;&lt;code&gt;&lt;span class="k"&gt;\documentclass&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;beamer&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;% Presentation content...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use transitions like &lt;code&gt;\pause&lt;/code&gt; to reveal content step by step. However, when preparing handouts, it's often desirable to remove these transitions for clarity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Standard Approach: Using the &lt;code&gt;handout&lt;/code&gt; Option
&lt;/h2&gt;

&lt;p&gt;A common method to create handouts is to modify the &lt;code&gt;\documentclass&lt;/code&gt; line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tex"&gt;&lt;code&gt;&lt;span class="k"&gt;\documentclass&lt;/span&gt;&lt;span class="na"&gt;[handout]&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;beamer&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;% Presentation content...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This effectively removes all transitions, producing a clean, static document. However, constantly toggling this line on and off can be tedious. Below are alternative approaches to simplify this process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative 1: Using &lt;code&gt;\PassOptionsToClass&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;A more flexible method is to use &lt;code&gt;\PassOptionsToClass&lt;/code&gt;, which allows you to toggle handout mode with a simple comment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tex"&gt;&lt;code&gt;&lt;span class="k"&gt;\PassOptionsToClass&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;handout&lt;span class="p"&gt;}{&lt;/span&gt;beamer&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\documentclass&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;beamer&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To switch back to transition mode, just comment out the first line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tex"&gt;&lt;code&gt;&lt;span class="c"&gt;% \PassOptionsToClass{handout}{beamer}&lt;/span&gt;
&lt;span class="k"&gt;\documentclass&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;beamer&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This avoids direct modifications to the &lt;code&gt;\documentclass&lt;/code&gt; line, making toggling easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative 2: Using a Separate Handout File
&lt;/h2&gt;

&lt;p&gt;If you frequently need both presentation and handout versions, consider creating a separate file. If your main Beamer file is &lt;code&gt;main.tex&lt;/code&gt;, create a new &lt;code&gt;handout.tex&lt;/code&gt; file containing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tex"&gt;&lt;code&gt;&lt;span class="k"&gt;\PassOptionsToClass&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;handout&lt;span class="p"&gt;}{&lt;/span&gt;beamer&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\input&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;main&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, compiling &lt;code&gt;main.tex&lt;/code&gt; gives you the regular slides with transitions, while compiling &lt;code&gt;handout.tex&lt;/code&gt; produces a transition-free handout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative 3: On-the-Fly Handout Generation
&lt;/h2&gt;

&lt;p&gt;For even greater flexibility, you can generate the handout dynamically using a shell command. If you use &lt;code&gt;Makefile&lt;/code&gt; or automation scripts, this method fits well into workflows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'\\PassOptionsToClass{handout}{beamer}\\input{main}'&lt;/span&gt; | pdflatex &lt;span class="nt"&gt;-jobname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;handout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that when piping LaTeX source to &lt;code&gt;pdflatex&lt;/code&gt; you will need to pass &lt;code&gt;-jobname&lt;/code&gt; to setup the output file name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By using &lt;code&gt;\PassOptionsToClass&lt;/code&gt;, separate handout files, or shell scripting, you can streamline the process of generating handouts from Beamer presentations. Choose the method that best fits your workflow and avoid the hassle of manually toggling the &lt;code&gt;handout&lt;/code&gt; option!&lt;/p&gt;

</description>
      <category>latex</category>
      <category>beamer</category>
    </item>
    <item>
      <title>Contributing to devenv</title>
      <dc:creator>Brian J. Cardiff</dc:creator>
      <pubDate>Mon, 21 Nov 2022 20:23:00 +0000</pubDate>
      <link>https://dev.to/bcardiff/contributing-to-devenv-50ag</link>
      <guid>https://dev.to/bcardiff/contributing-to-devenv-50ag</guid>
      <description>&lt;p&gt;I wanted to contribute a bit to &lt;a href="https://github.com/cachix/devenv" rel="noopener noreferrer"&gt;devenv&lt;/a&gt;. I consider myself a novice nix user. Anything beyond a couple of recipes I know fall out of my comfort zone. Yet the goals of devenv plus how supportive the maintainers seems to be were enough to do an attempt.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Build, share, and run your local development environments with a single command. Without containers.&lt;br&gt;
&lt;a href="https://devenv.sh/" rel="noopener noreferrer"&gt;https://devenv.sh/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I want to cover how you could contribute to add support for the language, or improve an existing one.&lt;/p&gt;

&lt;p&gt;There are many options of course, but a workflow that worked for my was&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Nix+Cachix+Devenv as explained in &lt;a href="https://devenv.sh/getting-started/" rel="noopener noreferrer"&gt;https://devenv.sh/getting-started/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(Optional) Install &lt;a href="https://direnv.net/" rel="noopener noreferrer"&gt;direnv&lt;/a&gt;, most likely you already use this :-)&lt;/li&gt;
&lt;li&gt;Fork and Clone &lt;a href="https://github.com/cachix/devenv" rel="noopener noreferrer"&gt;https://github.com/cachix/devenv&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The devenv repo defines both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a cli tool that will set up your environment&lt;/li&gt;
&lt;li&gt;a repository of devenv modules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The modules are a description of which nix packages should be downloaded and how they should be setup when devenv options are declared in the &lt;code&gt;devenv.nix&lt;/code&gt; file of your project.&lt;/p&gt;

&lt;p&gt;We are interested in the second aspect: the modules repository.&lt;/p&gt;

&lt;p&gt;For contributing to those we actually don't need to build a new version of the cli (as long as we are not changing some core functionality of course).&lt;/p&gt;

&lt;p&gt;When you create a new project powered by devenv you will have at least: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;devenv.nix&lt;/code&gt; file where you setup what languages/packages you want&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;devenv.yaml&lt;/code&gt; file that defines some pinning and source of truth to be used.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In particular &lt;code&gt;devenv.yaml&lt;/code&gt;  there is a &lt;code&gt;input.devenv.url&lt;/code&gt; key that points to the modules repository. By default points to &lt;code&gt;github:cachix/devenv?dir=src/modules&lt;/code&gt; (defined in &lt;a href="https://github.com/cachix/devenv/blob/329935d67aaf2ec75d9326098a749673525138c0/src/flake.nix#L7" rel="noopener noreferrer"&gt;flake.nix#L7&lt;/a&gt;), but we can override it! To a local path!&lt;/p&gt;

&lt;p&gt;That's what happening in &lt;a href="https://github.com/cachix/devenv/tree/329935d67aaf2ec75d9326098a749673525138c0/examples/supported-languages" rel="noopener noreferrer"&gt;examples/supported-languages&lt;/a&gt;. The &lt;code&gt;input.devenv.url&lt;/code&gt;  key points to the working copy &lt;code&gt;src/modules&lt;/code&gt;. We can use this example as a playground or create a new empty project devenv.&lt;/p&gt;

&lt;p&gt;If you choose to work on a new empty project, run &lt;code&gt;devenv init&lt;/code&gt; in an empty folder and edit &lt;code&gt;devenv.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nixpkgs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github:NixOS/nixpkgs/nixpkgs-unstable&lt;/span&gt;
  &lt;span class="na"&gt;devenv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;path:/absolute/path/to/src/modules&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running &lt;code&gt;direnv allow&lt;/code&gt;, or &lt;code&gt;devsenv shell&lt;/code&gt; if you don't use &lt;code&gt;direnv&lt;/code&gt; you should get the packages and languages defined in &lt;code&gt;devenv.nix&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I added &lt;code&gt;languages.elm.enable = true;&lt;/code&gt; to &lt;code&gt;devenv.nix&lt;/code&gt; to get elm compiler and it works!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% devenv shell
Building shell ...
Entering shell ...

elm --version
0.19.1
elm2nix --version
/nix/store/3szqhljvvkynvfi5gymfnxsiljpd6hmg-elm2nix-0.3.0/bin/elm2nix
hello from devenv
git version 2.38.1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this does not come with &lt;code&gt;elm-format&lt;/code&gt;. We want the formatter, always. That's the contribution we want to make. We could make the formatter optional, but it's so widely used in the elm community that I think we can install it always. What could be nice is a pre-commit hook integration to run it. That could be configurable, but let's stick to get the &lt;code&gt;elm-format&lt;/code&gt; installed for now.&lt;/p&gt;

&lt;p&gt;The package already exists in nixpkgs as &lt;code&gt;elmPackages.elm-format&lt;/code&gt; so this should be easy.&lt;/p&gt;

&lt;p&gt;Go to &lt;code&gt;src/modules/languages/elm.nix&lt;/code&gt;, and add &lt;code&gt;elm-format&lt;/code&gt; to the package dependency. Additionally add some advertisement you think pertinent. Unfortunately &lt;code&gt;elm-format&lt;/code&gt;  does not returns it's version with &lt;code&gt;--version&lt;/code&gt;, so we will just show that elm-format is indeed available.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;--- a/src/modules/languages/elm.nix
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/src/modules/languages/elm.nix
&lt;/span&gt;&lt;span class="p"&gt;@@ -11,6 +11,7 @@&lt;/span&gt; in
   config = lib.mkIf cfg.enable {
     packages = with pkgs; [
       elmPackages.elm
&lt;span class="gi"&gt;+      elmPackages.elm-format
&lt;/span&gt;       elm2nix
     ];
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;@@ -18,6 +19,8 @@&lt;/span&gt; in
       echo elm --version
       elm --version
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+      which elm-format
+
&lt;/span&gt;       echo elm2nix --version
       which elm2nix
     '';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, how we check if this changes are good?&lt;br&gt;
If you followed along you should be on a devenv shell (via direnv or explicit &lt;code&gt;devenv shell&lt;/code&gt; command).&lt;/p&gt;

&lt;p&gt;Update the shell by either running &lt;code&gt;direnv allow&lt;/code&gt; again, or exiting the devenv shell (&lt;code&gt;ctrl+D&lt;/code&gt;) and entering again.&lt;/p&gt;

&lt;p&gt;And that's it. You should have elm-format available.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/cachix/devenv/pull/104" rel="noopener noreferrer"&gt;Submit a PR&lt;/a&gt;!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Caveats for aarch64-darwin&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I needed to comment out &lt;code&gt;pkgs.python3Packages.cairocffi&lt;/code&gt; in &lt;a href="https://github.com/cachix/devenv/blob/329935d67aaf2ec75d9326098a749673525138c0/devenv.nix#L7" rel="noopener noreferrer"&gt;devenv.nix#L7&lt;/a&gt; for devenv source to work on aarch64-darwin, thanks &lt;a href="https://discord.com/channels/1036369714731036712/1036369758024650792/1043183592165097574" rel="noopener noreferrer"&gt;@domenkozar&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devenv</category>
      <category>nix</category>
      <category>elm</category>
    </item>
    <item>
      <title>An iterative validation of a new implementation</title>
      <dc:creator>Brian J. Cardiff</dc:creator>
      <pubDate>Mon, 21 Dec 2020 22:46:13 +0000</pubDate>
      <link>https://dev.to/bcardiff/an-iterative-validation-of-a-new-implementation-168m</link>
      <guid>https://dev.to/bcardiff/an-iterative-validation-of-a-new-implementation-168m</guid>
      <description>&lt;p&gt;Sometimes I need to replace or refactor a function in a program. In this post I want to share a process I’ve used to make such change. The goal is to improve our confidence in the end result.&lt;/p&gt;

&lt;p&gt;Suppose you have a function &lt;code&gt;f&lt;/code&gt; we need to migrate. For the sake of simplicity, we will assume &lt;code&gt;f&lt;/code&gt; will never raise an exception.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# ... stripped ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are no unit tests, but said function is widely used through the whole suite of tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First step&lt;/strong&gt;, leave the original function and define a wrapper.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;original_f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# ... stripped ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;original_f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Second step&lt;/strong&gt;, define a new implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new_f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# something new we hope will work&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Third step&lt;/strong&gt;, run both implementations and detect invalid behaviors of &lt;code&gt;new_f&lt;/code&gt; with respect to  &lt;code&gt;original_f&lt;/code&gt;. These invalid behaviors can be either crashes or unexpected results.&lt;/p&gt;

&lt;p&gt;To detect them we are going to change the wrapper with a bit of code that you will probably not like at all. Relax, it will be gone at the end.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;original_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;original_f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;begin&lt;/span&gt;
    &lt;span class="n"&gt;new_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
    &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect_with_backtrace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;STDOUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"bug.txt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;original_result&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;new_result&lt;/span&gt;
    &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"bug.txt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;Unexpected result: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  Expected: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;original_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;       Got: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;new_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;original_result&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there is an unexpected result the program will stop. Immediately. This can be done differently but, for the sake of simplicity, we are stopping at the first invalid behavior.&lt;/p&gt;

&lt;p&gt;We run the whole suite of tests and, if there is a crash, a &lt;code&gt;bug.txt&lt;/code&gt; file will be created with the &lt;code&gt;input&lt;/code&gt; that caused the invalid behavior.&lt;/p&gt;

&lt;p&gt;We can use a smaller program to work on the input that causes the crash.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;original_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;original_f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;new_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;original_result&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;new_result&lt;/span&gt;
    &lt;span class="n"&gt;pp!&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;original_result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_result&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Some trivial cases, maybe&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"abc"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"   abc    "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"   "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# The input that caused the crash&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"bug.txt"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# You could also use a test framework, of course.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way we can work on &lt;code&gt;new_f&lt;/code&gt; until the identified case is fixed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Iterate the process&lt;/strong&gt; of running the whole suite of tests until there is no crash.&lt;/p&gt;

&lt;p&gt;Now you have a &lt;code&gt;new_f&lt;/code&gt; that works as &lt;code&gt;original_f&lt;/code&gt;. At least, &lt;em&gt;to the extent the suite of tests needs&lt;/em&gt;. Note that we are not talking about only unit tests of &lt;code&gt;f&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Drop the "ugly" code to compare both implementations. Drop the &lt;code&gt;original_f&lt;/code&gt;. We don't need them anymore. Leave only the &lt;code&gt;new_f&lt;/code&gt; as the implementation of &lt;code&gt;f&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# something new we hope will work&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are done! 🎉&lt;/p&gt;

&lt;p&gt;This process was explained with &lt;a href="http://crystal-lang.org/"&gt;Crystal&lt;/a&gt; but it can be adapted easily to other languages.&lt;/p&gt;

&lt;p&gt;Programming is a tool. Yet, as a tool, it can be used as a process. We made temporal additions to our codebase as part of the process. There is no need for the code you write to always be permanent in the code base.&lt;/p&gt;

&lt;p&gt;There are more advanced processes and tools in software verification. This is a small example that might motivate you to look into them.&lt;/p&gt;

</description>
      <category>crystal</category>
      <category>testing</category>
      <category>refactor</category>
    </item>
    <item>
      <title>A counting triangles story</title>
      <dc:creator>Brian J. Cardiff</dc:creator>
      <pubDate>Thu, 26 Nov 2020 18:18:12 +0000</pubDate>
      <link>https://dev.to/bcardiff/a-counting-triangles-story-492l</link>
      <guid>https://dev.to/bcardiff/a-counting-triangles-story-492l</guid>
      <description>&lt;p&gt;Programming is a tool that can be used for a wide range of problems. Usually we code solutions for our clients, sometimes we build applications for ourselves. Programs don’t always need to be products at all, they can act as tiny pieces towards a larger objective.&lt;/p&gt;

&lt;p&gt;It was back in May 2009 in &lt;a href="https://manas.tech"&gt;Manas.Tech&lt;/a&gt; when &lt;a href="https://manas.tech/staff/ndt/"&gt;Nico&lt;/a&gt; came with a simple question. &lt;strong&gt;How many triangles can you find in this figure?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UFLTJIow--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/scdq738oe3usc5rvqb9k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UFLTJIow--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/scdq738oe3usc5rvqb9k.png" alt="Triangles to be counted"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Obviously &lt;code&gt;1-3-10&lt;/code&gt;, &lt;code&gt;1-2-7&lt;/code&gt; are triangles. For sure &lt;code&gt;7-9-2&lt;/code&gt; is easy to depict. &lt;code&gt;2-4-6&lt;/code&gt; is a bit small but definitely one to count and so on. Each of these triangles has another mirror image. After a little while, you realise there is also &lt;code&gt;1-2-6&lt;/code&gt;, and &lt;code&gt;2-6-7&lt;/code&gt; and –oh boy!– &lt;code&gt;1-2-9&lt;/code&gt;. Most likely you will have lost count of how many triangles there are unless you are seriously organized.&lt;/p&gt;

&lt;p&gt;Since we like having fun, either with arcades, drinks or whatever challenge comes to our daily life in Manas, we decided to tackle down this problem using our favorite tools.&lt;/p&gt;

&lt;p&gt;In May 2009, some of us were nearing graduation, teaching assistants at college; school was another daily activity.&lt;/p&gt;

&lt;p&gt;Most of us are programmers, and as such, we program. But each programmer has different preferences, backgrounds, areas of expertise, and this simple exercise was a perfect manifestation of that richness.&lt;/p&gt;

&lt;p&gt;During the whole day a bunch of emails were sent with the proposed answers. Claims were made around 53, 54, 47, 63, 65. 47 was the most popular answer by far, yet, incorrect according to some sources.&lt;/p&gt;

&lt;p&gt;The difference between the numbers is based on whether or not three aligned points shall be considered a triangle. And if &lt;code&gt;2-6-8&lt;/code&gt; is equal to &lt;code&gt;2-8-10&lt;/code&gt;... definitely not the important thing here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Different approaches
&lt;/h2&gt;

&lt;p&gt;So the result was that we had lots of implementations, with completely different “mathematical” backgrounds to solve this riddle.&lt;/p&gt;

&lt;p&gt;In chronological order we had the following solutions&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/spalladino"&gt;Santiago Palladino&lt;/a&gt;, with &lt;a href="https://github.com/manastech/triangles/blob/master/01-spalladino/triangles.py"&gt;62 lines of Python&lt;/a&gt;, he counted 3-segment cycles in a graph. Yep, he likes Python and Graph Theory (and Numerical Methods).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/aromero"&gt;Adrian Romero&lt;/a&gt;, with &lt;a href="https://github.com/manastech/triangles/blob/master/02-aromero/triangles2.py"&gt;35 lines of Python&lt;/a&gt;, he focused more on the lines than on the dots. He counted the intersections between pairs of lines that correspond to a triangle.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/waj"&gt;Juan Wajnerman&lt;/a&gt;, with &lt;a href="https://github.com/manastech/triangles/blob/master/03-waj/Triangles.cs"&gt;41 lines of C#&lt;/a&gt; and heavy use of LINQ, he took a relational algebra approach (or SQL-ish if Algebra is not your cup of tea) to get a cross product and filter, achieving the same answer as the previous ones.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/bcardiff"&gt;Brian J. Cardiff&lt;/a&gt; (that’s me!), wrote a shameful and silly &lt;a href="https://github.com/manastech/triangles/blob/master/04-bcardiff/triangulos.pl"&gt;30 lines of Prolog&lt;/a&gt; (&lt;a href="http://www.swi-prolog.org/pldoc/man?predicate=between/3"&gt;could have been 20&lt;/a&gt;). Same answer! It was a Generate &amp;amp; Test algorithm that searched for three not aligned points that were aligned in pairs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There were rounds of iteration along the day (we are agile developers after all) for fixing, discussing and discovering the different opinions around what is or isn’t a triangle. We relaxed the triangle criteria since we were not reaching the expected answer and we wanted to know why.&lt;/p&gt;

&lt;p&gt;Adapting software is a big concern. If the inner functioning of the algorithm is not evident by reading the code, changing it is pretty hard. None of the above were too long or too cryptic, specially for the author himself. But, maybe because of my bias, Prolog was a clear winner here. Check the code!&lt;/p&gt;

&lt;p&gt;But you know what? The solutions didn’t stop there.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/asterite"&gt;Ary Borenszweig&lt;/a&gt; codes a lot, &lt;a href="https://github.com/crystal-lang/crystal/graphs/contributors"&gt;seriously&lt;/a&gt;. Back then &lt;a href="https://crystal-lang.org/"&gt;Crystal&lt;/a&gt; was not even a dream and he wrote &lt;a href="https://github.com/manastech/triangles/tree/master/05-asterite"&gt;334 lines of Java&lt;/a&gt;. He even created a &lt;a href="https://github.com/manastech/triangles/blob/master/05-asterite/Triangles/src/asterite/triangles/Graph.java"&gt;Graph&lt;/a&gt; class, &lt;a href="https://github.com/manastech/triangles/tree/master/05-asterite/TrianglesTests/src/asterite/triangles/tests"&gt;tests&lt;/a&gt; and &lt;a href="https://github.com/manastech/triangles/blob/master/05-asterite/Triangles/src/asterite/triangles/TrianglesCounter.java"&gt;TrianglesCounter&lt;/a&gt; class. It’s Java’s way. The idea behind it was similar to Adrian’s, focused on the lines.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.tojkicillof"&gt;Jonathan Kicillof&lt;/a&gt; (our graphic designer!) submitted his own. Although he knew ActionScript and today I am amazed about the Javascript plugins he is able to pull off, he submitted &lt;a href="https://github.com/manastech/triangles/blob/master/06-jkicillof/65.pdf"&gt;a PDF&lt;/a&gt;. Yeap, a well organized PDF that helped us point directly to the good, the bad and the ugly triangles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/asterite"&gt;Ary Borenszweig&lt;/a&gt;, that guy that still codes a lot, submitted a total of &lt;a href="https://github.com/manastech/triangles/tree/master/07-asterite-ui"&gt;676 lines of Java&lt;/a&gt;. This time with a &lt;a href="https://github.com/manastech/triangles/tree/master/07-asterite-ui/Triangles/src/asterite/triangles/ui"&gt;UI&lt;/a&gt; to draw and solve any triangle based problem.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given that the input is fixed, the shortest program would be &lt;code&gt;echo 47&lt;/code&gt; but that would have taken all the fun out of it.&lt;/p&gt;

&lt;p&gt;And it’s nice to use your skills and the computer to solve a problem for yourself, by yourself. I happily remember when I already had lots of fun and challenges programming with nothing but a &lt;a href="http://www.annehelmond.nl/wordpress/wp-content/uploads/2007/11/logo_mit.png"&gt;turtle&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>challenge</category>
      <category>programming</category>
      <category>prolog</category>
      <category>python</category>
    </item>
    <item>
      <title>Debug Crystal in VSCode via CodeLLDB</title>
      <dc:creator>Brian J. Cardiff</dc:creator>
      <pubDate>Fri, 17 Apr 2020 21:06:39 +0000</pubDate>
      <link>https://dev.to/bcardiff/debug-crystal-in-vscode-via-codelldb-3lf</link>
      <guid>https://dev.to/bcardiff/debug-crystal-in-vscode-via-codelldb-3lf</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This post mentions features that will be released in 0.35.0, or that will require you to compile Crystal master branch ;-)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Crystal uses LLVM under the hood. To allow a more comfortable debugging experience it is required to instruct &lt;code&gt;lldb&lt;/code&gt; how to understand the values stored in memory. Recently this story got a lot of effort and it finally got merged. You can read more at &lt;a href="https://github.com/crystal-lang/crystal/pull/8538" rel="noopener noreferrer"&gt;#8538&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Let me share with you the configurations that will let you use the  &lt;a href="https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb" rel="noopener noreferrer"&gt;CodeLLDB&lt;/a&gt; &lt;br&gt;
extension to debug &lt;a href="https://crystal-lang.org/" rel="noopener noreferrer"&gt;Crystal&lt;/a&gt; programs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://go.microsoft.com/fwlink/?LinkId=733558" rel="noopener noreferrer"&gt;Create a task&lt;/a&gt; that will compile the current file and leave it in &lt;code&gt;bin/&lt;/code&gt; folder. In your project’s &lt;code&gt;.vscode/tasks.json&lt;/code&gt; add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tasks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crystal: build current file (debug)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shell&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;command&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crystal build --debug ${relativeFile} -o bin/${fileBasenameNoExtension}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;You might need to set the Crystal binary path in &lt;code&gt;"command"&lt;/code&gt; field depending on your environment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Check you have the &lt;a href="https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb" rel="noopener noreferrer"&gt;CodeLLDB&lt;/a&gt; extension installed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://go.microsoft.com/fwlink/?linkid=830387" rel="noopener noreferrer"&gt;Create a launch configuration&lt;/a&gt; that will run the previous task and start debugging the binary left in &lt;code&gt;bin/&lt;/code&gt;. It will also set up &lt;code&gt;lldb&lt;/code&gt; with the appropriate formatters. In your project’s &lt;code&gt;.vscode/launch.json&lt;/code&gt; add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.2.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;configurations&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lldb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;request&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;launch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crystal: debug current file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preLaunchTask&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crystal: build current file (debug)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;program&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${workspaceFolder}/bin/${fileBasenameNoExtension}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;args&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cwd&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${workspaceFolder}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;initCommands&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;command script import /path/to/crystal/etc/lldb/crystal_formatters.py&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;You will need to set the &lt;code&gt;crystal_formatters.py&lt;/code&gt; path in &lt;code&gt;"initCommands"&lt;/code&gt; field accordingly to your environment. The file is located in the compiler’s repo at &lt;a href="https://github.com/crystal-lang/crystal/blob/master/etc/lldb/crystal_formatters.py" rel="noopener noreferrer"&gt;etc/lldb/crystal_formatters.py&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You are all set, have fun!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fl798idf1xt2hsfdukrjx.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fl798idf1xt2hsfdukrjx.gif" alt="GIF Video debugging a hello world program"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Keep in mind we are still in the early days for these improvements. Debug information metadata and more formatters are still pending. But the recent effort to improve their current state sets the scaffolding to move steadily forward.&lt;/p&gt;

&lt;p&gt;Happy Crystalling!&lt;/p&gt;

</description>
      <category>crystal</category>
      <category>debug</category>
      <category>lldb</category>
    </item>
  </channel>
</rss>
