Escribimos "¡Hola, mundo!" Aplicación web Haskell (Spock)

Estaba aburrido de escribir en Python, quería algo inusual. Decidí probar Haskell. No sé el idioma, pero no quería escribir programas de entrenamiento de consola, como el cálculo factorial. Después de estudiar una gran cantidad de publicaciones sobre Haskell y su aplicación en la vida real, me di cuenta de que uno de los puntos potenciales del crecimiento de la popularidad del lenguaje es escribir aplicaciones web. Por extraño que parezca, hay bastantes marcos web bajo Haskell. Mi elección recayó en Spock , porque, a juzgar por la descripción, es un marco simple y rápido de desarrollar. Tengo cierta experiencia escribiendo aplicaciones web en Flask, así que pensé que sería interesante comparar enfoques tan diferentes para resolver problemas similares. En el artículo, intentaré dar mi forma más detallada de prueba y error en el estudio de Haskell usando el ejemplo de escribir la aplicación web de Spock más simple. Quizás esto sea útil para aquellos que dudan si intentar estudiar Haskell y si será útil en la vida real.


Un poco sobre Haskell y cómo cocinarlo


Lo primero que enfrenta todo desarrollador al aprender un nuevo idioma es elegir y configurar un entorno de desarrollo. Por supuesto, puede escribir en un cuaderno, pero si tiene al menos algo de experiencia en el desarrollo de proyectos de producción, este método le causará dolor. Por cierto, Haskell es un lenguaje bastante antiguo y común y tiene soporte para los editores e ide más famosos. Mi amigo Haskellist usa emacs. Estoy acostumbrado al IDE normal, así que instalé el complemento para IntelliJ.


Además, para el desarrollo, necesita stack , que ahora es el estándar y combina un compilador, un sistema de administración de paquetes, un sistema de compilación y prueba.


Todo parece bastante amigable, no hubo problemas con la instalación. Para el desarrollo, uso Mac OS, no lo he probado en otros sistemas, pero sospecho que en Linux todo comenzará sin problemas tampoco.


Hola mundo


Preparación


Vamos al tutorial e intentamos hacer todo de acuerdo con las instrucciones. Allí sugieren crear primero un proyecto estándar a través de stack: stack new MyLovelyProlect . El proyecto estándar es una carpeta con tres subcarpetas: app , src , test . Parece bastante lógico: una carpeta para la aplicación principal, una para funciones auxiliares, la tercera para pruebas. Como escribimos "¡Hola, mundo!", No necesitamos las carpetas src y test , pero no necesitamos eliminarlas, porque de lo contrario tendremos que limpiar cuidadosamente otros archivos, por ejemplo, HelloWorld.cabal .


En realidad, el código


Más adelante en el tutorial se propone copiar algún código en Main.hs Lo simplificaremos un poco más para compararlo con lo que ofrece el matraz.


 {-# LANGUAGE OverloadedStrings #-} module Main where import Web.Spock import Web.Spock.Config app :: SpockM () () () () app = get root $ text "Hello World!" main :: IO () main = do cfg <- defaultSpockCfg () PCNoDatabase () let mw = spock cfg app runSpock 8080 mw 

A modo de comparación, daré el mismo código en el matraz:


 from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World!" app.run() 

Por el número de líneas, el matraz aún gana: 8 contra 13. Pero teniendo en cuenta que Haskell es un lenguaje estáticamente tipado y 2 líneas ocupan la determinación del tipo, la diferencia, en mi opinión, es pequeña. Al menos el código anterior no me asustó de seguir aprendiendo el idioma.


Montaje y lanzamiento


A continuación, vaya a HelloWorld.cabal y agregue el executable HelloWorld-exe a la sección build-depends: la build-depends: línea Spock >=0.13 . En el tutorial en el sitio, se propone incluir 2 dependencias más, pero para mi propósito aún no son necesarias. Si ahora intentamos compilar la aplicación usando stack build --fast --pedantic , obtenemos el siguiente error:


 Error: While constructing the build plan, the following exceptions were encountered: In the dependencies for HelloWorld-0.1.0.0: Spock must match >=0.13, but the stack configuration has no specified version (latest matching version is 0.13.0.0) needed since HelloWorld is a build target. Some different approaches to resolving this: * Consider trying 'stack solver', which uses the cabal-install solver to attempt to find some working build configuration. This can be convenient when dealing with many complicated constraint errors, but results may be unpredictable. * Recommended action: try adding the following to your extra-deps in /Users/dkvasov/Documents/Haskell/Spock/HelloWorld/stack.yaml: Spock-0.13.0.0@sha256:8115862eb4fb84a26fb7bcd34f30acf036bd2e7c4eaf813c185c5562d138bba2 Plan construction failed. 

Está bastante claro: stack no sabe qué versión de Spock debe instalarse, por lo que debe escribirse en el archivo stack.yaml . Agregue extra-deps e intente construir de nuevo. Allí aparecerán otros errores similares, y como resultado, en el archivo stack.yaml , obtuve lo siguiente:


 extra-deps: - Spock-0.13.0.0 - Spock-core-0.13.0.0 - reroute-0.5.0.0 - stm-containers-0.2.16 - focus-0.1.5.2 

Después de eso, todo se reunió. Los artefactos de mi colección estaban en la .stack-work/dist/x86_64-osx/Cabal-2.4.0.1/build .


Todo comenzó con el comando stack exec HelloWorld-exe , y en localhost:8080 Vi la bienvenida "Hello, world!". No se necesitaba bailar con una pandereta.


Estamos tratando de descubrir qué está pasando.


Hasta ahora, no hemos utilizado ningún conocimiento específico de programación funcional (FP) y el lenguaje Haskell. Utilizamos el sentido común y el conocimiento de los conceptos básicos del desarrollo. No puedes hacer eso más allá. Para una mayor comprensión, necesitamos saber algunas cosas sobre la FA. AF no es la antípoda de OOP. Aquellos familiarizados con el lenguaje Scala saben que ambos conceptos coexisten fácilmente. La antípoda de FP es una programación imperativa. Mientras que el modelo funcional de cálculos se basa en la composición de funciones, el modelo imperativo se basa en el proceso de cambios sucesivos en los estados del sistema. De ello se deduce que en lenguajes puramente funcionales como Haskell, se supone que las funciones son "puras", es decir, no contienen un estado mutable y "efectos secundarios", además del valor de retorno. Esto facilita la creación de composiciones de características. En realidad, el requisito de "pureza" impone muchas restricciones al uso de lenguajes funcionales en el mundo real. Sin embargo, dado que hay aplicaciones de producción en Haskell, aún puede utilizar de alguna manera funciones puras en el mundo real. Echemos un vistazo más de cerca a nuestro Main.hs


Según tengo entendido, la aplicación de la app es una variable de tipo SpockM , que es una mónada . Lo más probable es que si no está familiarizado con el estilo funcional de la programación y la teoría de categorías, no entenderá la primera vez qué es y por qué lo necesita. Sin embargo, es necesario tratar esto al menos en el nivel básico, ya que las mónadas son la base para la aplicación del lenguaje Haskell. Hay bastantes artículos de diversos grados de detalle sobre este tema, incluido Habré. Por supuesto, no los traeré aquí. Hasta ahora, propongo considerar que las mónadas son una magia que te permite producir los llamados efectos secundarios. Hay otra mónada en nuestra aplicación: IO . Su efecto secundario es la entrada / salida de datos.


SpockM está parametrizado por otros cuatro tipos. Corresponden a la conexión de la base de datos, sesión, estado y valor de retorno. Para una aplicación vacía, no se necesita nada de esto, por lo que siempre usaremos el tipo () , que se llama Unidad. Dentro de la app vinculamos caminos a las acciones. En este caso, determinamos la ruta base / y la acción "Hello, world! get- .


A continuación, creamos una configuración predeterminada y la asignamos a cfg . Luego, usando la función spock cree middleware para la aplicación y cfg y transfiéralo a runSpock junto con el puerto de inicio deseado.


Conclusión


Está claro que todo lo que se describe aquí es muy simple, y todos los que hablen inglés y estén equipados con un cerebro podrán hacer lo mismo mirando el tutorial inicial de spock. Este artículo fue más sobre cómo me familiaricé con el lenguaje Haskell. Que sigue Además, casi todos los recursos de aprendizaje sugieren usar el estado y escribir una aplicación de tareas pendientes, luego conectar la base de datos y luego ... Quizás en el futuro escriba una secuela.


Referencias


Source: https://habr.com/ru/post/449628/


All Articles