📜 ⬆️ ⬇️

Writing the "Hello, world!" Application for the Haskell web (Spock)

I was bored writing in Python, I wanted something unusual. Decided to try Haskell. I don’t know the language, but I didn’t want to simply write console training programs, such as calculating factorial. After studying a fairly large number of posts about Haskell and its use in real life, I realized that one of the potential points of growth in the popularity of a language is writing web applications. Oddly enough, under Haskell there are quite a few web-frameworks . My choice fell on Spock , because, judging by the description, this is a simple and quick framework to develop. I have some experience writing web applications on Flask, so I thought it would be interesting to compare such dissimilar approaches in solving similar problems. In this article I will try to set out my way of trial and error in the study of Haskell as detailed as possible on the example of writing the simplest web application on Spock. Perhaps it will be useful for those who doubt whether to try to learn Haskell and whether it will be useful in real life.


A little about Haskell and how to cook it


The first thing that every developer encounters when learning a new language is the choice and setting up the development environment. Of course, you can write in a notebook, but if you have at least a little experience in developing production projects, this method will cause you pain. By the way, Haskell is quite an old and common language and has support for most well-known editors and ide. My friend haskelist uses emacs. I'm used to normal IDE, so I put the plugin for IntelliJ.


Also, for development, you will need a stack , which is now a standard and combines a compiler, a package management system, an assembly and testing system.


Everything looks pretty friendly, there were no problems with the installation. I use Mac OS for development, I haven’t checked it on other systems, but I suspect that everything will work fine under Linux too.


Hello, world!


Training


We go to the tutorial and try to do everything according to the instructions. They propose to first create a standard project via stack: stack new MyLovelyProlect . A standard project is a folder with three subfolders: app , src , test . It looks quite logical: one folder for the main application, one for support functions, and a third for testing. Since we write "Hello, world!", We do not need the src and test folders, but we don’t need to delete them, because otherwise we will have to clean up other files, for example HelloWorld.cabal .


Actually, the code


Further in the tutorial it is proposed to copy some code into Main.hs We will simplify it a little more in order to compare it with what flask offers.


 {-# 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 

For comparison, I will give the same code on flask:


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

In terms of the number of lines, flask still wins: 8 against 13. But given that Haskell is a statically typed language and 2 lines are occupied by the definition of types, the difference is, in my opinion, not great. At least, the above code did not scare me away from further language learning.


Build and Run


Next we go to HelloWorld.cabal and add the executable HelloWorld-exe to the build-depends: section build-depends: line Spock >=0.13 . In the tutorial on the site it is proposed to include 2 more dependencies, but for my purposes they are not needed yet. If now try to build the application using stack build --fast --pedantic , we get the following 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. 

Quite understandably: stack does not know which version of Spock to install, so it needs to be written in stack.yaml . We add extra-deps and repeat the build attempt. There are several similar errors that will pop up, and as a result, I have the following in stack.yaml :


 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 

After that, everything gathered. I collected the artifacts in the .stack-work/dist/x86_64-osx/Cabal-2.4.0.1/build .


I started everything by the stack exec HelloWorld-exe command, and on localhost:8080 I saw the coveted "Hello, world!". No dancing with a tambourine is needed.


Trying to figure out what's going on.


So far, we have not used any specific knowledge of functional programming (FP) and Haskell. We used common sense and basic development knowledge. So it is impossible further. For further understanding, we need to know some things about FP. OP is not the opposite of OOP. Those who are familiar with the Scala language know that in both of these concepts it is easy to get along. The antithesis of OP is imperative programming. While the functional model of computation relies on the composition of functions, the imperative model relies on the process of successive changes in the states of the system. It follows from this that in purely functional languages, such as Haskell, it is assumed that the functions are "pure", that is, they do not contain a changeable state and "side effects", besides the return value. This makes it easy to build compositions of functions. Actually, the requirement of "purity" imposes many restrictions on the use of functional languages ​​in the real world. However, since there are production applications in Haskell, it means you can somehow use pure functions in the real world. Let's take a closer look at our Main.hs


As I understand it, an app is a variable of type SpockM , which is a monad . Most likely, if you are not familiar with the functional programming style and category theory, you will not understand from the first time what it is and why you need it. However, it is necessary to deal with this at least at a basic level, since it is the monads that are the basis of the applied use of the Haskell language. There are quite a few articles of varying degrees of detail on this topic, including on Habré. I will not bring them here, of course. So far, I propose to assume that monads are the kind of magic that allows one to produce so-called side effects. In our application there is another monad: IO . Its side effect is data input and output.


SpockM is parameterized by four other types. They correspond to the database connection, session, state, and return value. For an empty application, this is not needed, so we will use the type () called Unit everywhere. Inside the app we tie paths to action. In this case, we defined the base path / and the action "Hello, world! get- .


Next, we create the default config and assign it to cfg . Next, using the spock function, spock create middleware for the app and cfg and pass it to runSpock along with the desired launch port.


Conclusion


It is clear that everything described here is very simple, and every person who speaks English and equipped with a brain will be able to do the same thing, looking at the spoch tutorial in izachalny tutorial. This article was more about how my acquaintance with the language Haskell. What's next? Then almost all learning resources suggest using state and writing an application todo, then connecting the database, then ... Maybe in the future I will write a sequel.


Links



')

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


All Articles