Play Haskell

Original author: Bob Ippolito
  • Transfer
  • Tutorial


I had a wonderful time studying Haskell in recent months, and it seems to me that taking the first steps in this lesson is more difficult than it could actually be. I was lucky to work at the right time and place, and on Facebook I took a Haskell course from Bryan O'Sullivan , but you can definitely get involved in the topic without anyone else’s help. To do this, you can play Haskell on the Try Haskell website , and ultimately install GHC for yourself.

Install the Haskell Platform (GHC)


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

The manual is written for users of Mac OS X 10.8 with Homebrew installed (and the latest version of Xcode), but to figure out how to do the same on other platforms using the Haskell Platform should be simple. The current version of the Haskell Platform is currently 2012.4.0.0.

$ brew install haskell-platform

Install Cabal


Cabal is the Common Architecture for Building Applications and Libraries for Haskell. 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 into ~/.cabal/bin/. You need to add these paths to the PATH environment variable. Something similar is enough, but it all depends on your preferences (personally, I use for these purposes ~/.profile- 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/configwithout profiling libraries enabled. You will probably want to use it later, and if you do not turn it on now, then in the future you will have to reassemble everything again. To enable it, change the line -- library-profiling: Falseto library-profiling: Truein 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 the Cabal installer:

$ cabal install cabal-install

Install ghc-mod (improved support for Emacs / Vim)


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

$ cabal install ghc-mod

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

Install Cabal-dev (build sandbox)


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 usage approach is different. It will save you from the “bondage hell” in which no one can install some packages due to conflicts with the dependencies of others.

Use cabal-devinstead of easy cabalto 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 clog up disk space), but this is certainly a fair price.

The normal cabal-dev installation should look like cabal install cabal-dev, but so far no one has closed the bug # 74, You will have to collect and install it from the 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

At the moment, some work is underway to enable support for Assemblies in the Sandbox and Isolated Environments in cabal-install, so the information about cabal-dev that is in this post will lose its 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, then just 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) in a folder /usr/local/Cellar/darcs/2.8.2, and ask Homebrew to make symlinks for me. On other platforms, you will most likely have to use your own directory structure, as well as manually edit the 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 go to 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. In this case, --overwriteit can be used almost painlessly, but I recommend that you first run with the key --overwrite --dry-run. It bothers you, but it certainly won't ruin you all day.

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

The rest are fun things to play with (order doesn't matter):
  • pandoc - Swiss knife in the context of markup formats (markdown, reStructuredText, org-mode, LaTeX, etc.)
  • gitit - a wiki running git, darcs or mercurical
  • pronk is an HTTP load testing tool similar to ab and httperf, only more modern and simple

For packages such as pronk, which are currently not available in Hackage, installation through 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 terminal). For detailed documentation, I recommend referring to the GHC Users Guide ( Chapter 2. Using GHCi ). You will spend a lot of time there playing with the code, so I suggest you shorten the greeting first. It looks like this:

Prelude>

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

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

This can be fixed using 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 (unofficial) mirrors exist


Unfortunately, Hackage is not known for its reliability. I do not know what the problem is, but I hope that they will do something with this in the near future. There is a workaround ( Workarounds in the event of a Hackage crash ), you just need to use the repository from hdiff at hdiff.luite.com or from hackage.csc.stanford.edu .

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

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

On 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 bring everything back after a while!

Create a project (using cabal-dev)


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

For your own projects, you need to remove the option -nto set the list of necessary options manually. The option -nuses 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 files Setup.hsand hs-hello-world.cabal. The next step is to change the line main-is:so that the bondage knows from which source to collect the executable file. The end result should be as follows:

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 this content:

HelloWorld.hs

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

Here is what you need to build and “install” the 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 a little 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 cut corners a bit.

For example, run using the interpreter, without compilation:

$ 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!

Yes, and you can even collect 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 are 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 name 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 the 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 for myself the following books and websites useful while I was teaching Haskell on my own.

Books

  • Explore Haskell for Good!
    This book turned out to be a great starting point for me, I recommend it first for reading. It doesn't go too deep to give you a REALLY complete understanding of the GHC, but after reading it I began to feel comfortable writing and understanding the Haskell code.
  • Real World Haskell
    Это увесистая книга и по размерам, и по глубине, но это не мешает ей быть доступной даже новичку. Она охватывает множество вещей из Реального Мира: написание теста, профилирование, IO, параллелизм и т.д. Я до сих пор ее изучаю, но эта книга обязательна к прочтению.


Сайты

  • CS240h: Functional Systems in Haskell — был такой курс по Haskell в Стенфорде, который преподавали David Mazières и Bryan O'Sullivan. Он похож (но его охват шире) на тот курс, который я прошел в Facebook. Конспекты лекций и программа — просто фантастические, читайте их все!
  • Real World Haskell
  • Learn You a Haskell
  • haskell.org отличная вещь для погружения, там Вы найдете все эти ссылки + ГОРАЗДО больше. Рассчитывайте потратить там много времени!
  • H-99 содержит некоторые маленькие задачки, над которыми можно поработать. Он во многом похож на Euler project. Их довольно просто решить после прочтения LYAH.
  • Typeclassopedia отличный ресурс для изучения множества тайпклассов Haskell Platform
  • Hoogle — это поисковик по Haskell API, поддерживающий поиск по сигнатурам типов! Я провел за ним очень много времени.
  • Hayoo! еще один поисковик, подходит для случаев, когда невозможно найти необходимую информацию с помощью Hoogle
  • HWN — еженедельная рассылка Хаскеля, которая собирает в себе ключевые моменты из мэйл листов, вопросы со stackoverflow, реддит и т.п..
  • Haskell :: Reddit — сабреддит по Haskell
  • stackoverflow - haskell - questions about Haskell on stackoverflow, often worth reading (to be honest, I often sit there after HWN)
  • C9 Lectures: FP Fundamentals 13 lectures on the Fundamentals of Functional Programming (in Haskell), taught by Dr. Erik Meijer (I haven’t watched them yet, but they were advised by Adam Breen ).

IRC

#haskell on Freenode is where you can find several hundred people interested in Haskell at any time. Great place to seek help.

Suggestions?


I plan to try to keep all this up to date, depending on the suggestions. 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 can do this much better. But I would like to capture the main points.

Also popular now: