Je m'ennuyais d'écrire en Python, je voulais quelque chose d'inhabituel. J'ai décidé d'essayer Haskell. Je ne connais pas la langue, mais je ne voulais pas écrire de programmes de formation sur console, comme le calcul factoriel. Après avoir étudié un assez grand nombre de publications sur Haskell et son application dans la vie réelle, j'ai réalisé que l'un des points potentiels de la croissance de la popularité de la langue était l'écriture d'applications Web. Curieusement, il existe de nombreux frameworks Web sous Haskell. Mon choix s'est porté sur Spock , car, à en juger par la description, c'est un framework simple et rapide à développer. J'ai une certaine expérience dans l'écriture d'applications Web dans Flask, j'ai donc pensé qu'il serait intéressant de comparer des approches aussi différentes pour résoudre des problèmes similaires. Dans cet article, je vais essayer de donner ma manière la plus détaillée d'essais et d'erreurs dans l'apprentissage de Haskell en écrivant une application web élémentaire dans Spock. Peut-être que cela sera utile pour ceux qui doutent d'essayer d'étudier Haskell et si cela sera utile dans la vie réelle.
Un peu sur Haskell et comment le cuisiner
La première chose à laquelle chaque développeur est confronté lorsqu'il apprend une nouvelle langue est le choix et la configuration d'un environnement de développement. Bien sûr, vous pouvez écrire dans un cahier, mais si vous avez au moins une certaine expérience dans le développement de projets de production, cette méthode vous fera mal. Soit dit en passant, Haskell est un langage assez ancien et commun et prend en charge les éditeurs et les idées les plus célèbres. Mon ami Haskellist utilise emacs. Je suis habitué à l'IDE normal, j'ai donc installé le plugin pour IntelliJ.
De plus, pour le développement, vous avez besoin d'une pile , qui est maintenant la norme et combine le compilateur, le système de gestion des packages, le système de construction et de test.
Tout semble assez convivial, il n'y a eu aucun problème avec l'installation. Pour le développement, j'utilise Mac OS, je ne l'ai pas testé sur d'autres systèmes, mais je soupçonne que sous Linux tout démarrera sans problème non plus.
Bonjour tout le monde!
La préparation
Nous allons au tutoriel et essayons de tout faire selon les instructions. Là, ils suggèrent d'abord de créer un projet standard via la pile: stack new MyLovelyProlect
. Le projet standard est un dossier avec trois sous-dossiers: app
, src
, test
. Cela semble assez logique: un dossier pour l'application principale, un pour les fonctions auxiliaires, le troisième pour les tests. Puisque nous écrivons "Bonjour, monde!", Nous n'avons pas besoin des dossiers src
et test
, mais nous n'avons pas besoin de les supprimer, car sinon nous devrons nettoyer soigneusement les autres fichiers, par exemple HelloWorld.cabal
.
En fait, le code
Plus loin dans le tutoriel, il est proposé de copier du code dans Main.hs
Nous allons simplifier un peu plus pour comparer avec ce que propose le flacon.
{-# 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 titre de comparaison, je donnerai le même code en flacon:
from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World!" app.run()
Par le nombre de lignes, flask gagne toujours: 8 contre 13. Mais étant donné que Haskell est un langage typé typiquement et que 2 lignes occupent la détermination de type, la différence, à mon avis, est petite. Au moins, le code ci-dessus ne m'a pas fait peur d'apprendre davantage la langue.
Assemblage et lancement
Ensuite, accédez à HelloWorld.cabal
et ajoutez l' executable HelloWorld-exe
à la section build-depends:
la build-depends:
ligne Spock >=0.13
. Dans le tutoriel sur le site, il est proposé d'inclure 2 autres dépendances, mais pour mes besoins elles ne sont pas encore nécessaires. Si nous essayons maintenant de créer l'application en utilisant la stack build --fast --pedantic
, nous obtenons l'erreur suivante:
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.
C'est assez clair: la pile ne sait pas quelle version de Spock doit être installée, elle doit donc être écrite dans le fichier stack.yaml
. Ajoutez extra-deps
et essayez de reconstruire. Là, d'autres erreurs similaires apparaîtront et, par conséquent, dans le fichier stack.yaml
, j'ai obtenu ce qui suit:
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
Après cela, tout s'est rassemblé. Mes artefacts de collection se trouvaient dans le .stack-work/dist/x86_64-osx/Cabal-2.4.0.1/build
.
Tout a commencé avec la stack exec HelloWorld-exe
commandes stack exec HelloWorld-exe
, et sur localhost:8080
j'ai vu l'accueil "Hello, world!". Aucune danse avec un tambourin n'était nécessaire.
Nous essayons de comprendre ce qui se passe.
Jusqu'à présent, nous n'avons utilisé aucune connaissance spécifique de la programmation fonctionnelle (FP) et du langage Haskell. Nous avons utilisé le bon sens et la connaissance des bases du développement. Vous ne pouvez pas continuer comme ça. Pour une meilleure compréhension, nous devons savoir certaines choses sur la FA. L'AF n'est pas l'antipode de la POO. Ceux qui connaissent le langage Scala savent que ces deux concepts coexistent facilement. L'antipode de FP est une programmation impérative. Alors que le modèle fonctionnel des calculs repose sur la composition des fonctions, le modèle impératif s'appuie sur le processus de changements successifs des états du système. Il s'ensuit que dans les langages purement fonctionnels tels que Haskell, on suppose que les fonctions sont "pures", c'est-à-dire qu'elles ne contiennent pas d'état mutable et "d'effets secondaires", en plus de la valeur de retour. Cela facilite la création de compositions de fonctionnalités. En fait, l'exigence de «pureté» impose de nombreuses restrictions à l'utilisation des langages fonctionnels dans le monde réel. Cependant, comme il existe des applications de production sur Haskell, vous pouvez toujours utiliser les fonctions pures dans le monde réel. Examinons de plus près nos Main.hs
Si je comprends bien, l'application app
est une variable de type SpockM
, qui est une monade . Très probablement, si vous n'êtes pas familier avec le style fonctionnel de la programmation et de la théorie des catégories, vous ne comprendrez pas la première fois de quoi il s'agit et pourquoi vous en avez besoin. Cependant, il est nécessaire de traiter cela au moins au niveau de base, car les monades sont la base de l'application du langage Haskell. Il y a pas mal d'articles de détails divers sur ce sujet, y compris sur Habré. Bien sûr, je ne les amènerai pas ici. Jusqu'à présent, je propose de considérer que les monades sont une telle magie qui vous permet de produire des soi-disant effets secondaires. Il existe une autre monade dans notre application: IO
. Son effet secondaire est l'entrée / sortie des données.
SpockM est paramétré par quatre autres types. Ils correspondent à la connexion à la base de données, à la session, à l'état et à la valeur de retour. Pour une application vide, rien de tout cela n'est nécessaire, nous utiliserons donc toujours le type ()
, qui est appelé Unit. À l'intérieur de l' app
nous lions des chemins aux actions. Dans ce cas, nous avons déterminé le chemin de base /
et l'action "Hello, world! get-
.
Ensuite, nous créons une configuration par défaut et l'affectons à cfg
. Ensuite, en utilisant la fonction spock
créez un middleware pour l'application et cfg et transférez-le vers runSpock
avec le port de lancement souhaité.
Conclusion
Il est clair que tout ce qui est décrit ici est très simple, et tous ceux qui parlent anglais et qui sont équipés d'un cerveau pourront faire la même chose en regardant le tutoriel de spock initial. Cet article était plus sur la façon dont je me suis familiarisé avec la langue Haskell. Et ensuite? De plus, presque toutes les ressources d'apprentissage suggèrent d'utiliser l'état et d'écrire une application todo, puis de connecter la base de données, puis ... Peut-être qu'à l'avenir j'écrirai une suite.
Les références