📜 ⬆️ ⬇️

We play in Haskell



I had a wonderful time studying Haskell in recent months, and it seems to me that making the first steps in this lesson is more difficult than it could be. I was lucky to work at the right time and in the right place, and on Facebook I took a Bryan O'Sullivan Haskell course, but you can definitely join the topic without the help of others. To do this, you can play Haskell on the Try Haskell site, and eventually set up a GHC for yourself.

Install the Haskell Platform (GHC)


The Haskell Platform is a Glasgow Haskell Compiler (GHC) and a standard “fully loaded” library. GHC is not the only Haskell compiler, but you need it. Another implementation worth seeing, Hugs , is more suitable for academic purposes than practical ones.

The instructions are written for Mac OS X 10.8 users with Homebrew installed (and the latest version of Xcode), but it should be easy to figure out how to do the same on other platforms using the Haskell Platform . The current version of the Haskell Platform is currently 2012.4.0.0.
')
$ brew install haskell-platform 

Install Cabal


Cabal is Common Architecture for Haskell's Common Architecture for Building Applications and Libraries . Paired with Hackage , Cabal is similar in meaning to tools such as CPAN for Perl, pip for Python, or gem for Ruby. You will probably be disappointed, but still he is not so bad.

Cabal installs its packages in ~/.cabal/ , and the scripts go to ~/.cabal/bin/ . You need to add these paths to the PATH environment variable. Something similar is enough, but it all depends on your preferences (I personally use ~/.profile for this purpose - approx. Translator):

 $ echo 'export PATH=$HOME/.cabal/bin:$PATH' >> ~/.bashrc 

Before you start using cabal, you need to expand the list of available packages. Sometimes you will have to run this command, in particular before installing or updating packages.

 $ cabal update 

At the moment, we have ~/.cabal/config without library profiling enabled. You will probably want to use it later, and if you do not turn it on now, you will have to rebuild everything in the future. To enable it, change the line -- library-profiling: False to library-profiling: True in the file ~/.cabal/config .

 $ for f in ~/.cabal/config; do \ cp $f $f.old && \ sed -E 's/(-- )?(library-profiling: )False/\2True/' < $f.old > $f; \ done 

Your very first package should be Cabal installer:

 $ cabal install cabal-install 

Install ghc-mod (improved Emacs / Vim support)


ghc-mod comes in handy for you to integrate GHC with Emacs or Vim. The same effect can be achieved in Sublime Text 2 and ghc-mod using SublimeHaskell . For now, I have only used Emacs integration. Vim users can use hdevtools , since it is much faster and just as accurate (see kamatsu comment )

 $ cabal install ghc-mod 

I will not cover the setting of your own Emacs (but you can use my current ~ / .emacs.d for an example).

Install Cabal-dev (sandbox for assembly)


Cabal-dev is a tool that makes it easy for you to install applications on Haskell. It is similar to virtualenv for Python and rvm for Ruby, but the approach to use is different. It will save you from the "Kabbalian hell", in which no one can install one package due to conflicts with the dependencies of others.

Use cabal-dev instead of simple cabal to build wherever possible. The main compromise is that you have to spend (much) more time compiling packages that have already been installed somewhere else (and fill up disk space), but this is certainly a fair fee.

A normal installation of cabal-dev should look like cabal install cabal-dev , but so far no one has closed bug # 74 , you will have to build and install it from source:

 $ git clone https://github.com/creswick/cabal-dev.git /tmp/cabal-dev-src && \    (cd /tmp/cabal-dev-src; cabal install) && \    rm -rf /tmp/cabal-dev-src 

Currently, some work is underway on enabling support for Sandbox Assemblies and Isolated Environments in cabal-install, so information on cabal-dev that is in this post will lose relevance in a few months (years?).

Installing tools with cabal-dev


If you want to try some tool, but there is no desire to pollute your Haskell installation, in this case you just need to use cabal-dev. By default, the cabal-dev sandbox is in ./cabal-dev , but you can keep it anywhere. In this example, I will install darcs 2.8.2 (a distributed version control system written in Haskell) into the /usr/local/Cellar/darcs/2.8.2 folder and ask Homebrew to make symlinks for me. On other platforms, you will most likely have to use your own directory structure, and also manually edit your PATH.

 $ cabal-dev install -s /usr/local/Cellar/darcs/2.8.2 darcs-2.8.2 $ brew link --overwrite darcs 

Tydyzh! Now darcs is in your PATH, and you no longer have to worry about conflicting versions. Well, unfortunately, conflicts will still occur, but now not so often. In particular, cabal-dev installs packages in such a way that they reach the very top of the selected sandbox. This means that if two packages have common dependencies (VERY common), then they will jig on each other's symlinks, up to such things as license agreement files and dependency documentation files. In this case, --overwrite can use --overwrite almost painlessly, but I recommend that you first --overwrite --dry-run with the --overwrite --dry-run key --overwrite --dry-run . It bothers you, but surely will not spoil you the whole day.

If you want to see the available versions of darcs, use use cabal info darcs and find the Versions available: section Versions available:

The rest of the fun stuff you can play with (order doesn't matter):

For packages like pronk that are currently missing from Hackage, installing via cabal-dev should look something like this:

 $ git clone https://github.com/bos/pronk.git /tmp/pronk-src && \ (cd /tmp/pronk-src; \ cabal-dev install -s /usr/local/Cellar/pronk/$(git rev-parse --short HEAD)) && \ rm -rf /tmp/pronk-src 

GHCi Setup


ghci is an interactive GHC interpreter (REPL, similar to python or irb in a terminal). For detailed documentation I recommend to refer to the GHC Users Guide ( Chapter 2. Using GHCi ). You will spend a lot of time there playing with the code, so I suggest that you start by shortening the greeting. It looks like this:

 Prelude> 

When you start importing modules, the greeting will grow, and in fact nobody needs it.

 Prelude> :m + Data.List Prelude Data.List> :m + Data.Maybe Prelude Data.List Data.Maybe> 

This can be fixed with the .ghci file. I use a very simple ASCII character, although some like something like λ>.

 echo ':set prompt "h> "' >> ~/.ghci 

You can also use the command :set prompt "h> " every time you start GHCi, but this is also superfluous.

 $ ghci h> putStrLn "Hello World!" Hello World! h> 

Hackage is fragile, but there are (unofficial) mirrors


Unfortunately, Hackage is not famous for its reliability. I do not know what the problem is, but I hope that they will do something about it soon. There is a workaround ( Workarounds if Hackage crashes ), all you need is to use the hdiff repository on hdiff.luite.com or with hackage.csc.stanford.edu .

To do this, change the line in ~ / .cabal / config:

 remote-repo: hackage.haskell.org:http://hackage.haskell.org/packages/archive 

For something like:

 -- TODO When hackage is back up, set back to hackage.haskell.org! -- remote-repo: hackage.haskell.org:http://hackage.haskell.org/packages/archive remote-repo: hdiff.luite.com:http://hdiff.luite.com/packages/archive -- remote-repo: hackage.csc.stanford.edu:http://hackage.scs.stanford.edu/packages/archive 

After the changes, you need to update the list of packages

 $ cabal update 

And do not forget to return everything back after a while!

Create a project (using cabal-dev)


In the end, you yourself would have realized this, but the fastest way to start a project is to start it with cabal-dev. Here is what you need to do for a simple program.

For your own projects, you need to remove the -n option to specify the list of necessary options manually. The -n option uses all the default settings and does not ask you anything.
 $ mkdir -p ~/src/hs-hello-world $ cd ~/src/hs-hello-world $ touch LICENSE $ cabal init -n --is-executable 

This will generate the Setup.hs and hs-hello-world.cabal . The next step is to change the line main-is: so that bondage knows from which source code to compile the executable file. The end result should be like this:

hs-hello-world.cabal

 -- Initial hs-hello-world.cabal generated by cabal init. For further -- documentation, see http://haskell.org/cabal/users-guide/ name: hs-hello-world version: 0.1.0.0 -- synopsis: -- description: license: AllRightsReserved license-file: LICENSE -- author: -- maintainer: -- copyright: -- category: build-type: Simple cabal-version: >=1.8 executable hs-hello-world main-is: HelloWorld.hs -- other-modules: build-depends: base ==4.5.* 

Then create HelloWorld.hs , with the following contents:

HelloWorld.hs

 main :: IO () main = putStrLn "Hello, world!" 

Here is what you need to build and “install” a program in the current sandbox:
 $ cabal-dev install Resolving dependencies... Configuring hs-hello-world-0.1.0.0... Building hs-hello-world-0.1.0.0... Preprocessing executable 'hs-hello-world' for hs-hello-world-0.1.0.0... Installing executable(s) in /Users/bob/src/hs-hello-world/cabal-dev//bin Installed hs-hello-world-0.1.0.0 $ ./cabal-dev/bin/hs-hello-world Hello, world! 

The executable file is too big, but it is also statically linked. You can copy it to any machine with the same operating system and architecture, and it will just work.

You can save some time by skipping the installation step:

 $ cabal-dev configure Resolving dependencies... Configuring hs-hello-world-0.1.0.0... $ cabal-dev build Building hs-hello-world-0.1.0.0... Preprocessing executable 'hs-hello-world' for hs-hello-world-0.1.0.0... [1 of 1] Compiling Main ( HelloWorld.hs, dist/build/hs-hello-world/hs-hello-world-tmp/Main.o ) Linking dist/build/hs-hello-world/hs-hello-world ... $ ./dist/build/hs-hello-world/hs-hello-world Hello, world! 

Since the project has no dependencies that need to be installed, you can slightly cut corners.

For example, run using the interpreter, without compiling:

 $ runghc HelloWorld.hs Hello, world! 

 $ ghci GHCi, version 7.4.2: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Prelude> :load HelloWorld [1 of 1] Compiling Main ( HelloWorld.hs, interpreted ) Ok, modules loaded: Main. *Main> main Hello, world! 

Anyway, you can build it without cabal-dev (or cabal ):

 $ runghc Setup.hs configure Configuring hs-hello-world-0.1.0.0... $ runghc Setup.hs build Building hs-hello-world-0.1.0.0... Preprocessing executable 'hs-hello-world' for hs-hello-world-0.1.0.0... [1 of 1] Compiling Main ( HelloWorld.hs, dist/build/hs-hello-world/hs-hello-world-tmp/Main.o ) Linking dist/build/hs-hello-world/hs-hello-world ... 

But for a more complex project, you can use cabal-dev ghci (after cabal-dev configure && cabal-dev build ). Please note that in this case the code will be loaded into the interpreter automatically:

 $ cabal-dev ghci on the commandline: Warning: -O conflicts with --interactive; -O ignored. GHCi, version 7.4.2: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Ok, modules loaded: Main. h> main Hello, world! 

GHCi Basics


Some basic GHC tricks that would be good to know. In addition to those that I have indicated here, I advise you to study Chapter 2. Using GHCi .

: t shows the type of expression

 h> :t main main :: IO () h> :t map map :: (a -> b) -> [a] -> [b] h> :t map (+1) map (+1) :: Num b => [b] -> [b] 

: i shows title information (function, typeclass, type, ...)

 h> :i Num class Num a where (+) :: a -> a -> a (*) :: a -> a -> a (-) :: a -> a -> a negate :: a -> a abs :: a -> a signum :: a -> a fromInteger :: Integer -> a -- Defined in `GHC.Num' instance Num Integer -- Defined in `GHC.Num' instance Num Int -- Defined in `GHC.Num' instance Num Float -- Defined in `GHC.Float' instance Num Double -- Defined in `GHC.Float' h> :info map map :: (a -> b) -> [a] -> [b] -- Defined in `GHC.Base' h> :info Int data Int = ghc-prim:GHC.Types.I# ghc-prim:GHC.Prim.Int# -- Defined in `ghc-prim:GHC.Types' instance Bounded Int -- Defined in `GHC.Enum' instance Enum Int -- Defined in `GHC.Enum' instance Eq Int -- Defined in `ghc-prim:GHC.Classes' instance Integral Int -- Defined in `GHC.Real' instance Num Int -- Defined in `GHC.Num' instance Ord Int -- Defined in `ghc-prim:GHC.Classes' instance Read Int -- Defined in `GHC.Read' instance Real Int -- Defined in `GHC.Real' instance Show Int -- Defined in `GHC.Show' 

: m adds a module to the current scope

 h> :m + Data.List h> sort [10,9..1] [1,2,3,4,5,6,7,8,9,10] 

: l loads the module,: r reloads

 h> :! echo 'hello = print "hello"' > Hello.hs h> :l Hello [1 of 1] Compiling Main ( Hello.hs, interpreted ) Ok, modules loaded: Main. h> hello "hello" h> :! echo 'hello = print "HELLO"' > Hello.hs h> :r [1 of 1] Compiling Main ( Hello.hs, interpreted ) Ok, modules loaded: Main. h> hello "HELLO" 

Recommended reading


I noted the following books and websites useful for myself while I was teaching Haskell on my own.

Books



Sites


IRC

#haskell on Freenode is where you’ll find hundreds of people interested in Haskell at any time. Great place to look for help.

Suggestions?


I plan to try to keep it all up to date, depending on the proposals. If I missed something important, let me know! I do not pretend to create a complete picture, it seems to me that the Haskell wiki does this much better. But I would like to capture the main points.

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


All Articles