DEV Community

Brian J. Cardiff
Brian J. Cardiff

Posted on

1

¿Cómo instalar Haskell?

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.

GHCup

Primero vamos a instalar el instalador GHCup. En https://www.haskell.org/ghcup/ vamos a encontrar el siguiente comando que funciona para Linux, macOS, FreeBSD o WSL2 y lo podemos ejecutar desde una terminal.

% curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
Enter fullscreen mode Exit fullscreen mode

Nos va a hacer algunas preguntas, podemos usar las opciones por defecto que son buenas.

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

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

% ghcup --version
The GHCup Haskell installer, version 0.1.40.0
Enter fullscreen mode Exit fullscreen mode

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

Por ejemplo si usan macOS y zsh agregando lo siguiente a ~/.zprofile vamos a lograr tener ghcup en el path.

export PATH="/Users/nombreusuario/.ghcup/bin:$PATH"
Enter fullscreen mode Exit fullscreen mode

Si hacemos algún cambio para modificar el PATH cerremos y vuelvamos a abrir la terminal. Probemos si ghcup --version anda esta vez.

Si anduvo ya está la parte más engorrosa.

GHC

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 ghc.

Entre todas las versiones hay una que se llama recommended. Actualmente es la 9.4.8.

Si ejecutamos ghcup tui vamos a ver un menu para elegir instalar (presionando i) y establecer como default (presionando s).

% ghcup tui
Enter fullscreen mode Exit fullscreen mode

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.

Para verificar si tienen GHC instalado podemos hacer lo siguiente:

% ghc --version
The Glorious Glasgow Haskell Compilation System, version 9.4.8
Enter fullscreen mode Exit fullscreen mode

Si no funcionó podemos usar los siguientes comandos para instalar y establecer la versión recomendada de GHC.

% ghcup install ghc recommended
% ghcup set ghc recommended
Enter fullscreen mode Exit fullscreen mode

GHCi

Junto con GHC viene GHCi, el intérprete. Con GHCi podemos experimentar en forma interactiva, sin necesidad de crear archivos incluso.

% ghci
GHCi, version 9.4.8: https://www.haskell.org/ghc/  :? for help
ghci> 1+1
2
ghci> mayor a b = if a > b then a else b
ghci> mayor 3 4
4
ghci> :q
Leaving GHCi.
Enter fullscreen mode Exit fullscreen mode

Trabajando con archivos en GHCi

También se pueden cargar archivos. Si creamos un archivo Ejemplo.hs (la convención es que empiecen con mayúscula) con el siguiente contenido:

mayor a b = if a > b then a else b
Enter fullscreen mode Exit fullscreen mode

Podemos cargarlo en ghci usando :l Ejemplo.hs y usar la función definida en él.

% ghci
GHCi, version 9.4.8: https://www.haskell.org/ghc/  :? for help
ghci> :l Ejemplo.hs 
[1 of 2] Compiling Main             ( Ejemplo.hs, interpreted )
Ok, one module loaded.
ghci> mayor 2 4
4
Enter fullscreen mode Exit fullscreen mode

Si cambiamos el contenido del archivo con :r vamos a recargarlo

ghci> :r
[1 of 2] Compiling Main             ( Ejemplo.hs, interpreted ) [Source file changed]
Ok, one module loaded.
Enter fullscreen mode Exit fullscreen mode

Trabajando con VSCode

Si elegimos VSCode como editor, lo recomendable es instalar extensión haskell.haskell. Se integra con GHCup y cuenta con algunas herramientas adicional.

La configuración sugerida ( Ctrl + Shift + P o Cmd + Shift + P , > Open User Settings (JSON)) es la siguiente.

{
    "haskell.manageHLS": "GHCup",
    "haskell.upgradeGHCup": false,
    "haskell.toolchain": {
        "ghc": "recommended",
        "hls": "recommended",
        "cabal": "recommended",
        "stack": null
    },
    "editor.formatOnSave": true
}
Enter fullscreen mode Exit fullscreen mode

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

Si abrimos el archivo Ejemplo.hs con el editor vamos a tener coloreo de sintaxis. 🎨

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

Es posible que necesitemos reiniciar el editor (Ctrl + Shift + P o Cmd + Shift + P , > Developer: Reload Window).

Ahora disponemos de HLS (Haskell Language Server) que nos dará acceso a documentación y otras herramientas integradas para

  • Dar formato al código usando ormolu
  • Sugerencias sintácticas usando hlint
  • Anotaciones de tipo usando el algoritmo de inferencia
  • Ir a la definición de la función
  • Ver documentación
  • Evaluar código en líneas que empiezan con -- >>>

Por ejemplo, si el archivo contiene

mayor a b = if a > b then a else b

-- >>> mayor 2 3
Enter fullscreen mode Exit fullscreen mode

Nos va a aparecer un Evaluate... arriba del -- >>> que al hacer click nos dará el resultado.

mayor a b = if a > b then a else b

-- >>> mayor 2 3
-- 3
Enter fullscreen mode Exit fullscreen mode

Trabajando con múltiples archivos

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.

Supongamos que en una carpeta tenemos Foo.hs y Bar.hs con el siguiente contenido

module Foo where

foo = 2
Enter fullscreen mode Exit fullscreen mode
module Bar where

import Foo

bar = foo + foo

-- >>> bar
-- 4
Enter fullscreen mode Exit fullscreen mode

En GHCi podemos cargar cualquiera de los dos módulos con :l y evaluar sus funciones.

% ghci
GHCi, version 9.4.8: https://www.haskell.org/ghc/  :? for help
ghci> :l Bar.hs 
[1 of 2] Compiling Foo              ( Foo.hs, interpreted )
[2 of 2] Compiling Bar              ( Bar.hs, interpreted )
Ok, two modules loaded.
ghci> bar
4
Enter fullscreen mode Exit fullscreen mode

En VSCode basta con abrir la carpeta que los contiene para que todo funcione y podamos evaluar -- >>> bar como antes.

Cabal

Es usual aprovechar paquetes y aplicaciones definidos por otras personas. En Haskell se registran y distribuyen en Hackage. Para descargar los paquetes o aplicaciones de Hackage se usa Cabal. Si hemos seguido las instrucciones ya tenemos Cabal instalado, sino podemos usar GHCup para obtener la versión recomendada.

% cabal --version
cabal-install version 3.12.1.0
compiled using version 3.12.1.0 of the Cabal library 
Enter fullscreen mode Exit fullscreen mode

A continuación usaremos aplicaciones y paquetes de Hackage.

Re-evaluando expresiones

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.

Si usamos GHCi tenemos que hacer :r y escribir la expresión a evaluar.

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 -- >>> . Con un click en Evaluate... o Refresh... obtenemos el resultado.

Hay otra opción que no require alejarnos del código que estamos editando. La herramienta ghcid permite ejecutar un expresión ni bien se hacen cambios en un archivo.

Para instalarla primero debemos tener una versión actualizada del índice de paquetes.

% cabal update
Enter fullscreen mode Exit fullscreen mode

Luego podemos proceder a instalar la aplicación ghcid.

% cabal install ghcid
Enter fullscreen mode Exit fullscreen mode

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

Como alternativa podemos indicar en qué directorio instalar la aplicación. Por ejemplo en un directorio bin junto a los archivos que estamos editando.

% cabal install ghcid --installdir=bin
Enter fullscreen mode Exit fullscreen mode

Volviendo al ejemplo de Bar.hs, podemos querer evaluar la función bar cada vez que hagamos cambios en el archivo.

% bin/ghcid Bar.hs --test bar
Enter fullscreen mode Exit fullscreen mode

En la pantalla veremos:

4

...done
Enter fullscreen mode Exit fullscreen mode

Probemos cambiar el contenido de Bar.hs o Foo.hs y el valor se actualizará.

Trabajando con paquetes externos

Para trabajar con paquetes hay dos alternativas

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

Forma manual

Por ejemplo si queremos escribir casos de prueba podemos optar por usar el paquete HUnit e instalarlo de forma manual y que esté disponible universalmente.

% cabal install --lib HUnit
Enter fullscreen mode Exit fullscreen mode

Luego podemos usarlo directamente al importarlo.

module Bar where

import Foo
import Test.HUnit

bar = foo + foo

main = runTestTTAndExit allTests

allTests =
  test
    [ bar ~?= 4
    ]
Enter fullscreen mode Exit fullscreen mode

En GHCi podemos evaluar la función main

% ghci Bar.hs 
ghci> main
Cases: 1  Tried: 1  Errors: 0  Failures: 0
*** Exception: ExitSuccess
Enter fullscreen mode Exit fullscreen mode

En VSCode podemos evaluar -- >>> main pero la salida vamos a verla en la pestaña de OUTPUT si seleccionamos Haskell en la lista de la derecha.

Con ghcid podemos ejecutar el siguiente comando para correr los test automáticamente con cada cambio.

% bin/ghcid Bar.hs --test main
Enter fullscreen mode Exit fullscreen mode

⚠️ Si bien cabal install --lib paquete 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.

‼️ En VSCode es posible que necesitemos ejecutar el comando Haskell: Restart Haskell LSP Server (Ctrl + Shift + P o Cmd + Shift + P) para que tome los cambios del entorno.

Definir un proyecto

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.

Para inicializar un proyecto podemos usar cabal init nombreproyecto y aceptar todas las opciones por defecto.

% cabal init nombreproyecto
What does the package build:
   1) Library
 * 2) Executable
   3) Library and Executable
   4) Test suite
Your choice? [default: Executable] 
...
Enter fullscreen mode Exit fullscreen mode

Vamos a obtener la siguiente estructura en la carpeta nombreproyecto

.
├── CHANGELOG.md
├── LICENSE
├── app
│   └── Main.hs
└── nombreproyecto.cabal
Enter fullscreen mode Exit fullscreen mode

Podemos borrar CHANGELOG.md y LICENSE para código de prueba.

El archivo .cabal tiene información sobre cómo se conforma el proyecto. En particular al final obtenemos algo similar a lo siguiente:

executable nombreproyecto
    import:           warnings
    main-is:          Main.hs
    -- other-modules:
    -- other-extensions:
    build-depends:    base ^>=4.17.2.1
    hs-source-dirs:   app
    default-language: Haskell2010
Enter fullscreen mode Exit fullscreen mode

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

Cuando hagamos % cabal run dentro de la carpeta nombreproyecto va a compilar Main.hs y ejecutar la función main definida ahí.

% cabal run
Hello, Haskell!
Enter fullscreen mode Exit fullscreen mode

Adaptemos el ejemplo de Foo, Bar y HUnit a este esquema.

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

module Foo where

foo = 2
Enter fullscreen mode Exit fullscreen mode
module Bar where

import Foo

bar = foo + foo
Enter fullscreen mode Exit fullscreen mode
module Main where

import Bar
import Test.HUnit

main = runTestTTAndExit allTests

allTests =
  test
    [ bar ~?= 4
    ]
Enter fullscreen mode Exit fullscreen mode

Ahora bien, nos falta actualizar el archivo nombreproyecto.cabal para declarar

  • Qué otros archivos forman parte del proyecto: sí hay que listarlos explícitamente.
  • Qué paquetes externos queremos usar.

Quitemos el comentario a other-modules para listar Bar y Foo para lo primero. Agregamos HUnit opcionalmente con información de versión.

executable nombreproyecto
    import:           warnings
    main-is:          Main.hs
    other-modules:
        Bar
        Foo
    -- other-extensions:
    build-depends:    base ^>=4.17.2.1, 
                      HUnit ^>=1.6.2.0
    hs-source-dirs:   app
    default-language: Haskell2010
Enter fullscreen mode Exit fullscreen mode

Si hacemos cabal run obtenemos el resultado de los tests.

% cabal run 
Cases: 1  Tried: 1  Errors: 0  Failures: 0
Enter fullscreen mode Exit fullscreen mode

Si hacemos cabal repl vamos a iniciar un ghci con todo el proyecto ya cargado.

% 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> main
Cases: 1  Tried: 1  Errors: 0  Failures: 0
*** Exception: ExitSuccess
ghci> 
Leaving GHCi.
Enter fullscreen mode Exit fullscreen mode

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

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

% 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
  | ^^^
...
Enter fullscreen mode Exit fullscreen mode

En su lugar aparecen solamente warnings. Esto es porque nuestro archivo .cabal indica ser muy estricto con los warnings.

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

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

% bin/ghcid --warnings --test main
...

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

...done
Enter fullscreen mode Exit fullscreen mode

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

👋 Kindness is contagious

If this article connected with you, consider tapping ❤️ or leaving a brief comment to share your thoughts!

Okay