Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructure Getting Started documentation to be more compact and beginner friendly #9212

Merged
merged 31 commits into from
Oct 24, 2023
Merged
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8b270be
Rewrite installation section of getting-started.rst
malteneuss Aug 26, 2023
9531fd9
Rephrase creating a package documentation section
malteneuss Aug 27, 2023
2123b9e
Length align titles in getting-started.rst
malteneuss Aug 27, 2023
7eceaa3
Fix length alignment in getting-started.rst
malteneuss Aug 27, 2023
21354e7
Update doc/getting-started.rst
malteneuss Aug 29, 2023
b588579
Update getting-started.rst
malteneuss Aug 29, 2023
26ad26b
Update doc/getting-started.rst
malteneuss Oct 11, 2023
178efb1
Align package and script example in getting-started.rst
malteneuss Oct 11, 2023
05e630b
Align example package versions in getting-started.rst
malteneuss Oct 11, 2023
d891e8a
Update doc/getting-started.rst
malteneuss Oct 13, 2023
98060c6
Update doc/getting-started.rst
malteneuss Oct 13, 2023
3e3968b
Update doc/getting-started.rst
malteneuss Oct 13, 2023
b483931
Update doc/getting-started.rst
malteneuss Oct 13, 2023
2c5f4cf
Update doc/getting-started.rst
malteneuss Oct 13, 2023
ea88c70
Update doc/getting-started.rst
malteneuss Oct 13, 2023
0465bc3
Update doc/getting-started.rst
malteneuss Oct 13, 2023
6029a36
Update doc/getting-started.rst
malteneuss Oct 13, 2023
3a99fe5
Added review suggestions
malteneuss Oct 13, 2023
569d34d
Update doc/getting-started.rst
malteneuss Oct 21, 2023
6ec10c1
Update doc/getting-started.rst
malteneuss Oct 21, 2023
420a77a
Update doc/getting-started.rst
malteneuss Oct 21, 2023
fb70883
Update doc/getting-started.rst
malteneuss Oct 21, 2023
6523b7e
Update doc/getting-started.rst
malteneuss Oct 21, 2023
87ad204
Update doc/getting-started.rst
malteneuss Oct 21, 2023
4071777
Update doc/getting-started.rst
malteneuss Oct 21, 2023
a9e9291
Update doc/getting-started.rst
malteneuss Oct 21, 2023
562e0d6
Update doc/getting-started.rst
malteneuss Oct 21, 2023
a6e957f
Update getting-started.rst
malteneuss Oct 22, 2023
75b31f2
Update getting-started.rst
malteneuss Oct 22, 2023
bf4aaa4
Update doc/getting-started.rst
ulysses4ever Oct 22, 2023
43d97a5
Merge branch 'master' into patch-1
mergify[bot] Oct 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 96 additions & 79 deletions doc/getting-started.rst
Original file line number Diff line number Diff line change
@@ -1,90 +1,104 @@
Getting Started with Haskell and Cabal
======================================
Getting Started
===============
ffaf1 marked this conversation as resolved.
Show resolved Hide resolved

Installing the Haskell toolchain
--------------------------------

To install the Haskell toolchain follow the `ghcup instructions
<https://www.haskell.org/ghcup/>`__.
Installing Cabal
----------------
ffaf1 marked this conversation as resolved.
Show resolved Hide resolved

The easiest and recommended way to install the ``cabal`` command-line tool
on Linux, macOS, FreeBSD or Windows is through `ghcup <https://www.haskell.org/ghcup/>`__.
It installs the “Haskell toolchain”, which includes Cabal,
the Haskell compiler `GHC <https://www.haskell.org/ghc/>`__
and optionally other useful Haskell tools.

Creating a new application
--------------------------

Let's start by creating a simple Haskell application from scratch where we'll
learn about a Haskell package's directory structure, how to run the executable,
and how to add external dependencies.
We create a minimal Haskell application to get a quick overview
of the ``cabal`` command-line tool:

1. How to initialize a Haskell package.
2. How files are organized inside a package.
3. How to compile Haskell files and run a resulting executable.
4. How to manage external dependencies.

Initializing the application
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Initializing an application
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Start by initialising our ``myfirstapp`` project, these instructions work in
unix shells and PowerShell (if you're on Windows).
To initialize a new Haskell application, run

.. code-block:: console

$ cabal init myfirstapp -n

.. note:: ``myfirstapp`` stands for the directory (or path) where the project
will reside in, if omitted, ``cabal init`` will do its proceedings
in the directory it's called in.
$ cabal init myapp --non-interactive

.. note:: ``-n`` stands for ``--non-interactive``, which means that cabal will try to guess
how to set up the project for you and use the default settings, which will serve us
well for the purpose of this tutorial.
When setting up your projects in the future, you will likely want to omit ``-n``
and do just ``cabal init``, so that cabal will interactively ask you
for the details on how the project should be set up
(while still offering reasonable defaults on every step).
Also, you can run ``cabal init --help`` to get more info on how ``cabal init`` can be used.

This will generate the following files:
in a terminal. This generates the following files in a new ``myapp`` directory:

.. code-block:: console

$ tree
.
└── myfirstapp
└── myapp
├── app
│   └── Main.hs
├── CHANGELOG.md
└── myfirstapp.cabal
└── myapp.cabal

``app/Main.hs`` is where your package's code lives.
The ``myapp.cabal`` file is a package description file, commonly referred to as a “Cabal file”:

``myfirstapp.cabal`` is Cabal's metadata file which describes your package,
how it is built and its dependencies. We'll be updating this file in a
little bit when we add an external dependency to our package.
.. code-block:: cabal

cabal-version: 3.0
name: myapp
version: 0.1.0.0
-- ...

Running the application
^^^^^^^^^^^^^^^^^^^^^^^
executable myapp
import: warnings
main-is: Main.hs
build-depends: base ^>=4.19.0.0
hs-source-dirs: app
default-language: Haskell2010

When we ran ``cabal init myfirstapp -n`` above, it generated a package with a single
executable named same as the package (in this case ``myfirstapp``) that prints
``"Hello, Haskell!"`` to the terminal. To run the executable enter the project's
directory and run it, by inputting the following commands:
It contains metadata (package name and version, author name, license, etc.) and sections
to define package components. Components can be used to split large codebases into smaller,
more managable building blocks.
A component can be of one of several types (executable, library, etc.) and describes,
among other things, the location of source files and its dependencies.
The ``myapp.cabal`` file above defines a single component named ``myapp`` of the executable type.
Inside the ``executable`` section, the ``build-depends`` field lists the dependencies of this component.

.. code-block:: console

cd myfirstapp
cabal run myfirstapp
The ``app/Main.hs`` file is where your executable's code lives:

.. code-block:: haskell

You should see the following output in the terminal:
module Main where

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


To run the executable, switch into the application directory with ``cd myapp`` and run

.. code-block:: console

$ cabal run myfirstapp
$ cabal run myapp
...
Hello, Haskell!

Notice that we didn't need to run a `build` command before we ran ``cabal run``.
This is because ``cabal run`` automatically determines if the code needs to be (re)built
before running the executable.
If you just want to build a target without running it, you can do so with ``cabal build``:
This command automatically determines if the executable needs to be (re)built
before running the executable. With only one executable component in the package,
``cabal run`` (without a component name) is smart enough to infer it, so the name can be omitted.

If you just want to build the executable without running it, run:

.. code-block:: console

``cabal build myfirstapp``
$ cabal build
Resolving dependencies...
...
Building executable 'myapp' for myapp-0.1.0.0..
[1 of 1] Compiling Main ( app/Main.hs, /home/.../myapp/dist-newstyle/build/.../myapp-tmp/Main.o )
Linking /home/.../myapp/dist-newstyle/build/.../myapp


Adding dependencies
Expand All @@ -103,16 +117,16 @@ terminal with some embellishment.
need to update the package index, you can do this by running ``cabal
update``.

In our ``myfirstapp.cabal`` file we'll update the ``build-depends`` attribute of
the ``executable myfirstapp`` section to include ``haskell-say``:
In our ``myapp.cabal`` file, we will update the ``build-depends`` field of
the executable section to include ``haskell-say``:

.. code-block:: cabal

executable myfirstapp
executable myapp
import: warnings
main-is: Main.hs
build-depends:
base ^>=4.14.3.0,
base ^>=4.19.0.0,
haskell-say ^>=1.0.0.0
hs-source-dirs: app
default-language: Haskell2010
Expand All @@ -132,8 +146,7 @@ Next we'll update ``app/Main.hs`` to use the ``HaskellSay`` library:
import HaskellSay (haskellSay)

main :: IO ()
main =
haskellSay "Hello, Haskell! You're using a function from another package!"
main = haskellSay "Hello, Haskell!"

``import HaskellSay (haskellSay)`` brings the ``haskellSay`` function from the
module named ``HaskellSay`` into scope. The ``HaskellSay`` module is defined in
Expand All @@ -143,11 +156,10 @@ Now you can build and re-run your code to see the new output:

.. code-block:: console

$ cabal run
$ cabal run myapp
________________________________________________________
/ \
| Hello, Haskell! You're using a function from another |
| package! |
| Hello, Haskell! |
\____ _____________________________________________/
\ /
\ /
Expand All @@ -166,42 +178,47 @@ Now you can build and re-run your code to see the new output:
/ / / / \ \
/____/ /____/ \____\

Run a single-file Haskell script
--------------------------------
Running a single-file Haskell script
------------------------------------

Cabal also enables us to run single-file Haskell scripts
without creating a project directory or ``.cabal`` file.
The cabal directives are placed in the file within a comment.
Cabal also supports running single-file Haskell scripts like
the following file named ``myscript``:

.. code-block:: haskell

#!/usr/bin/env cabal
{- cabal:
build-depends: base, split
build-depends:
base ^>=4.19.0.0,
haskell-say ^>=1.0.0.0
-}

import Data.List.Split (chunksOf)
import HaskellSay (haskellSay)

main :: IO ()
main = getLine >>= print . chunksOf 3
main = haskellSay "Hello, Haskell!"

This can be run using ``cabal run myscript``.
On Unix-like systems this can be run directly with execute permission.
The necessary sections of a ``.cabal`` file are placed
directly into the script as a comment.

Use the familiar ``cabal run`` command to execute this script:

.. code-block:: console

$ cabal run myscript

$ chmod +x myscript
$ ./myscript

Project metadata can also be included:
On Unix-like systems, a Haskell script starting with ``#!/usr/bin/env cabal``, like the one above,
can be run directly after setting the execute permission (+x):

.. code-block:: haskell
.. code-block:: console

{- project:
with-compiler: ghc-8.10.7
-}
$ chmod +x myscript
$ ./myscript
________________________________________________________
/ \
| Hello, Haskell! |
\____ ____________________________________________/
\ ... /

See more in the documentation for :ref:`cabal run`.

Expand Down
Loading