Haskell Programming Language
Haskell Programming Language
Haskell is a general-purpose, statically typed, purely functional programming language with type inference and lazy evaluation. Developed to be suitable for teaching, research and industrial application, Haskell has pioneered a number of advanced programming language features such as type classes, which enable type-safe operator overloading. Haskell’s main implementation is the Glasgow Haskell Compiler (GHC). It is named after logician Haskell Curry.
Features
- Statically typed
- Purely functional
- Type inference
- Concurrent
- Lazy
- Packages
Overview
- GHC: A compiler and interpreter for Haskell programs.
- Cabal: Common Architecture for Building Applications and Libraries.
- Stack: A project builder for multi-package Haskell projects.
- Haddock: A documentation generator for Haskell packages.
- Hackage: The Haskell central packages repository.
- Stackage: A curated repository of thousands of packages installed on demand.
Usage
Haskell has significant usage in:
- Web development
- Concurrent and parallel programming
- Cluster computing
- Financial modeling
- Scientific and biotech modeling
- Parsers, compilers, type-checkers
- Blockchain
Documentation
- Haskell 2010 Language Report - git
- Haskell 2010 Language Report - pdf
- Haskell 2010 Language Report - online
- GHC Developer Blog
- Haskell Package Versioning Policy
- The GHC Milestones
- The GHC User’s Guide and Libraries - gitlab
- The GHC User’s Guide and Libraries - latest
- The GHC User’s Guide and Libraries - 9.0
- The GHC User’s Guide and Libraries - 8.10
- The GHC User’s Guide and Libraries - 8.8
- The Cabal User Guide
- The Haskell Tool Stack User Guide
- The Haddock User Guide
- How to write a Haskell program
- FP Complete Haskell
- Why Applied Haskell
- Promote Haskell
- Asynchronous and Concurrent Programming
- Decoding and encoding binary data
- How to Script with Stack
- Profiling and Performance
- Mutable variables
- Why you should use Software Transactional Memory
- Haskell Tutorial for C Programmers
- What I Wish I Knew When Learning Haskell
- Haskell in Depth
- Learn You a Haskell for Great Good!
- Real World Haskell
- Parallel and Concurrent Programming in Haskell
- Stable Haskell package sets
- Hackage: The Haskell Package Repository
- Haskell API search engine
- Eta - Modern Haskell on the JVM
- Eta Cheatsheet
- 2020 State of Haskell Survey
- Simple Haskell is Best Haskell
- Delivering with Haskell
- A Brief Example of servant-persistent
- Basic Type Level Programming in Haskell
- Servant Route Smooshing
- Haskell Language Extension Taxonomy
- Language pragma history
- GHC 2021
Download and Install
The latest (2021-03-13) LTS Haskell 17 use ghc 8.10.4, so don’t install ghc 9.0 or later if you are beginners.
Visual Studio Code
See Haskell Language Server (HLS), you can install from the VSCode marketplace, or manually from the repository Haskell for Visual Studio Code.
OS-specific packages
The OS-specific packages (eg. RPMs on Linux) are generally a better bet than the vanilla binary bundles, because they will check for dependencies and allow the package to be uninstalled at a later date.
e.g., install GHC 8.10.4 and cabal-install 3.4 on Debian Linux 10 (buster) amd64:
GHC on Debian 10
1 | sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys BA3CBA3FFE22B574 |
Minimal installation
The Minimal installation include GHC (the compiler), build tools (primarily Cabal and Stack), and documentation generator (primarily Haddock).
GHC
GHC 8.10 only works with cabal-install version 3.2 or later. GHC 9.0 only works with cabal-install version 3.4 or later. GHC 9.2.1 will be released in June 2021 sporting Darwin/ARM support.
- Downloads for Linux
- GHC & Cabal APT Repository
- GHC APT Repository
- Cabal APT Repository
- GHC Downloads Repository
- GHC - 8.8 Latest
- GHC - 8.10.4 Source
- GHC - 8.10.4 for Alpine Linux
- GHC - 8.10.4 for Debian Linux
- GHC - 8.10.4 for Windows
- GHC - 9.0 Latest
- GHC - 9.0.1 Source
- GHC - 9.0.1 for Alpine Linux
- GHC - 9.0.1 for Debian Linux
- GHC - 9.0.1 for Windows
Cabal
- Cabal Repository
- Cabal Repository - Latest
- Cabal Repository - Alpine Linux
- Cabal Repository - Debian/Ubuntu Linux
- Cabal Repository - Windows
Cabal install is done by installing them in the store and symlinking/copying the executables in the directory specified by the --installdir
flag (~/.cabal/bin/
by default). If you want the installed executables to be available globally, make sure that the PATH environment variable contains that directory.
1 | -- ~/.cabal/config |
Stack
1 | ~/.stack/config.yaml |
Haddock
Haddock is a documentation generator for Haskell packages.
1 | PS C:\> cabal update |
Quick Start
Docker
1 | docker run -it --rm --pull always haskell:8.10-stretch |
Hello GHC
1 | export PATH=/opt/ghc-8.10/bin:/bin:/usr/bin:/sbin:/usr/sbin |
Hello Cabal
1 | export https_proxy=http://example.com:8080 |
Hello Stack
1 | export https_proxy=http://example.com:8080 |
The Stable Haskell package sets
- Stable Haskell package sets
- LTS Latest
- LTS 17@2021-03-20, GHC 8.10.4, base 4.14.1, 2659 packages
- LTS 16@2021-01-17, GHC 8.8.4, base 4.13.0, 2512 packages
- LTS 14@2020-02-15, GHC 8.6.5, base 4.12.0, 2474 packages
The Popular Haskell Packages
Sites
- Awesome Haskell - Konstantin
- Awesome Haskell - LibHunt
- Top 20 Haskell Projects by mentions
- Packages by category
- Top Downloaded packages
Standard Packages
1 | /opt/ghc-8.10/lib/ghc-8.10.4/lib/package.conf.d |
Packages
- aeson: Fast JSON parsing and encoding
- Alex: A lexical analyser generator for Haskell
- async: Run IO operations asynchronously and wait for their results
- attoparsec: Fast combinator parsing for bytestrings and text
- auto-update: Efficiently run periodic, on-demand actions
- base16-bytestring: Fast base16 (hexadecimal) encoding and decoding for Haskell bytestrings
- base64-bytestring: Fast base64 encoding and decoding for Haskell
- binary: Binary serialisation for Haskell values using lazy ByteStrings
- bytestring: Fast, compact, strict and lazy byte strings with a list interface
- conduit: Streaming data processing library
- Conferer: Configuration managment for haskell
- containers: Assorted concrete container types
- cql-io: Cassandra CQL client
- cql: cql: Cassandra CQL binary protocol
- criterion: Robust, reliable performance measurement and analysis
- datadog: Haskell DataDog client library
- deepseq: Deep evaluation of data structures
- directory: Platform-agnostic library for filesystem operations
- fgl: A Functional Graph Library for Haskell
- filepath: Library for manipulating FilePaths in a cross platform way
- gauge: Lean Haskell Benchmarking
- Happy: The Parser Generator for Haskell
- Haxl: Simplifies access to remote data.
- hoopl: Higher-order optimization library
- hpack: A modern format for Haskell packages
- hsc2hs: Haskell Pre-processor for C FFI bindings
- hspec: A Testing Framework for Haskell
- http-client-openssl: http-client backend using the OpenSSL library
- http-client-tls: http-client backend using the connection package and tls library
- http-client: An HTTP client engine
- http-streams: An HTTP client using io-streams
- http2: HTTP/2 library
- hw-json: Memory efficient JSON parser
- hw-simd: Library of simd functions
- hw-xml: XML parser based on succinct data structures
- inline-c: Haskell and C can be freely intermixed in the same source file
- iproute: A Simple Routing Table Structure for CIDR
- lens: Lenses, Folds and Traversals
- math-functions: Special mathematical functions
- msgpack-binary: A Haskell implementation of MessagePack
- mime-types: Basic mime-type handling types and functions
- mtl: The Monad Transformer Library
- mwc-random: Fast, high quality pseudo random number generation
- network-uri: URI manipulation facilities
- network: Low-level networking interface
- odbc: Haskell binding to the ODBC API, aimed at SQL Server driver
- optparse-applicative: Command line options parsing
- ormolu: A formatter for Haskell source code
- parallel: A library for parallel programming
- pretty: Haskell Pretty-printer library
- primitive: Primitive memory-related operations
- quickcheck: Framework for running and organising tests, with HUnit and QuickCheck support
- random: Pseudo-random number generation
- req: Easy-to-use, type-safe, expandable, high-level HTTP client library
- rio: A standard library for Haskell
- safe-exceptions: safe-exceptions: Safe, consistent, and easy exception handling
- serialise: Binary serialisation in the CBOR format
- servant-server: A family of combinators for defining webservices APIs and serving them
- servant: A family of combinators for defining webservices APIs
- snap-server: Snap Framework HTTP Server Library
- socket: POSIX sockets API
- stm: Software Transactional Memory
- tar: Reading, writing and manipulating “.tar” archive files
- time-manager: Scalable timer
- time: A Time, clocks and calendars library
- tls-session-manager: In-memory TLS session manager
- tls: Native Haskell TLS and SSL protocol implementation for server and client
- transformers: Monad transformers
- typed-process: Run external processes, with strong typing of streams
- unliftio: Lifting and unlifting IO actions
- uuid: For creating, comparing, parsing and printing Universally Unique Identifiers
- vector: Efficient Arrays
- wai-extra: Provides some basic WAI handlers and middleware.
- wai: Web Application Interface
- warp-quic: WAI handler for HTTP/3 based on QUIC
- weigh: Memory benchmarking
- wrap: A fast, light-weight web server for WAI applications
- wreq: An easy-to-use HTTP client library
- xhtml: XHTML combinator library
- yaml: Parsing and rendering YAML
- zlib: Compression and decompression in the gzip and zlib formats
- zstd: Haskell bindings to the Zstandard compression algorithm]
Tricks to Fight Pain
Static Linking
Alpine Linux use musl libc, it can generate statically-linked programs correctly, see ghc-musl for more details. GNU C Library (glibc) based distributions have this blocker issue Wrong order of -lc
and -lpthread
when building a static binary.
ghc-pkg and cabal does not list user installed packages
After you install packages by cabal, you can not found them by cabal list --installed
, this issue had reported to upstream. Here is the workaround.
1 | ~/.ghc/x86_64-linux-8.10.4/environments/default |
GHC on Alpine Linux
Prepare Alpine Linux
Both Docker or chroot are good for us.
Prepare by Docker
1 | docker run --rm -it --pull always -w /root alpine:3 |
Prepare by Chroot
- Alpine Linux 3.13 Minimal root filesystem
- Alpine Linux 3.12 Minimal root filesystem
- Alpine Linux 3.11 Minimal root filesystem
1 |
|
Install Haskell
1 | export PS1="\[\e[31m\][\[\e[m\]\[\e[38;5;172m\]\u\[\e[m\]@\[\e[38;5;153m\]\h\[\e[m\] \[\e[38;5;214m\]\W\[\e[m\]\[\e[31m\]]\[\e[m\]\\$ " |
Using Haskell
1 | ghc --version |
Cleanup Alpine Linux
This just need for the chroot setup.
1 | umount --recursive $LFS/run |
GHC on SUSE Linux 15
Install Haskell
1 | export PS1="\[\e[31m\][\[\e[m\]\[\e[38;5;172m\]\u\[\e[m\]@\[\e[38;5;153m\]\h\[\e[m\] \[\e[38;5;214m\]\W\[\e[m\]\[\e[31m\]]\[\e[m\]\\$ " |
Using Haskell
1 | ghc --version |
GHC on RHEL 8
Install Haskell
1 | export PS1="\[\e[31m\][\[\e[m\]\[\e[38;5;172m\]\u\[\e[m\]@\[\e[38;5;153m\]\h\[\e[m\] \[\e[38;5;214m\]\W\[\e[m\]\[\e[31m\]]\[\e[m\]\\$ " |
Using Haskell
1 | ghc --version |
Program Structure
Every complete Haskell program must define main in module Main in package main.
At the topmost level a Haskell program is a set of modules. Modules provide a way to control namespaces and to re-use software in large programs.
The top level of a module consists of a collection of declarations, of which there are several kinds. Declarations define things such as ordinary values, datatypes, type classes, and fixity information.
At the next lower level are expressions. An expression denotes a value and has a static type; expressions are at the heart of Haskell programming “in the small.”
At the bottom level is Haskell’s lexical structure. The lexical structure captures the concrete representation of Haskell programs in text files.
Language extensions
50% of all production Haskell code is language extension and import lines
1 |
Added at the top of your file. Basic structure:
1 |
|
Modules
A module defines a collection of values, datatypes, type synonyms, classes, etc., in an environment created by a set of imports (resources brought into scope from other modules). It exports some of these resources, making them available to other modules. We use the term entity to refer to a value, type, or class defined in, imported into, or perhaps exported from a module.
A Haskell program is a collection of modules, one of which, by convention, must be called Main and must export the value main. The value of the program is the value of the identifier main in module Main, which must be a computation of type IO τ for some type τ. When the program is executed, the computation main is performed, and its result (of type τ) is discarded.
Module Structure
A module defines a mutually recursive scope containing declarations for value bindings, data types, type synonyms, classes, etc.
1 | module → module modid [exports] where body |
A module begins with a header: the keyword module, the module name, and a list of entities (enclosed in round parentheses) to be exported. The header is followed by a possibly-empty list of import declarations that specify modules to be imported, optionally restricting the imported bindings. This is followed by a possibly-empty list of top-level declarations.
An abbreviated form of module, consisting only of the module body, is permitted. If this is used, the header is assumed to be ‘module Main(main) where’. If the first lexeme in the abbreviated module is not a {, then the layout rule applies for the top level of the module.
Export Lists
1 | exports → ( export1 , … , exportn [ , ] ) (n ≥ 0) |
An export list identifies the entities to be exported by a module declaration. A module implementation may only export an entity that it declares, or that it imports from some other module. If the export list is omitted, all values, types and classes defined in the module are exported, but not those that are imported.
Import Declarations
1 | impdecl → import [qualified] modid [as modid] [impspec] |
The entities exported by a module may be brought into scope in another module with an import declaration at the beginning of the module. The import declaration names the module to be imported and optionally specifies the entities to be imported. A single module may be imported by more than one import declaration. Imported names serve as top level declarations: they scope over the entire body of the module but may be shadowed by local non-top-level bindings.
The effect of multiple import declarations is strictly cumulative: an entity is in scope if it is imported by any of the import declarations in a module. The ordering of import declarations is irrelevant.
Lexically, the terminal symbols “as”, “qualified” and “hiding” are each a varid rather than a reservedid. They have special significance only in the context of an import declaration; they may also be used as variables.
What is imported
Exactly which entities are to be imported can be specified in one of the following three ways:
- The imported entities can be specified explicitly by listing them in parentheses. Items in the list have the same form as those in export lists, except qualifiers are not permitted and the ‘module modid’ entity is not permitted. When the (..) form of import is used for a type or class, the (..) refers to all of the constructors, methods, or field names exported from the module.
The list must name only entities exported by the imported module. The list may be empty, in which case nothing except the instances is imported.
- Entities can be excluded by using the form hiding(import1 , … , importn ), which specifies that all entities exported by the named module should be imported except for those named in the list. Data constructors may be named directly in hiding lists without being prefixed by the associated type. Thus, in
import M hiding (C)
any constructor, class, or type named C is excluded. In contrast, using C in an import list names only a class or type.
It is an error to hide an entity that is not, in fact, exported by the imported module.
- Finally, if impspec is omitted then all the entities exported by the specified module are imported.
Lexical Structure
- Notational Conventions
- Lexical Program Structure
- Comments
- Identifiers and Operators
- Numeric Literals
- Character and String Literals
- Layout
Expressions
- Errors
- Variables, Constructors, Operators, and Literals
- Curried Applications and Lambda Abstractions
- Operator Applications
- Sections
- Conditionals
- Lists
- Tuples
- Unit Expressions and Parenthesized Expressions
- Arithmetic Sequences
- List Comprehensions
- Let Expressions
- Case Expressions
- Do Expressions
- Datatypes with Field Labels
- Expression Type-Signatures
- Pattern Matching
Predefined Types and Classes
- Standard Haskell Types
- Strict Evaluation
- Standard Haskell Classes
- Numbers
Standard Haskell Types
Booleans
1 | data Bool = False | True deriving |
The boolean type Bool is an enumeration. The basic boolean functions are && (and), || (or), and not. The name otherwise is defined as True to make guarded expressions more readable.
Characters and Strings
The character type Char is an enumeration whose values represent Unicode characters. Type Char is an instance of the classes Read, Show, Eq, Ord, Enum, and Bounded. The toEnum and fromEnum functions, standard functions from class Enum, map characters to and from the Int type.
A string is a list of characters:
1 | type String = [Char] |
Lists
1 | data [a] = [] | a : [a] deriving (Eq, Ord) |
Lists are an algebraic datatype of two constructors, although with special syntax. Lists are an instance of classes Read, Show, Eq, Ord, Monad, Functor, and MonadPlus.
Tuples
Tuples are algebraic datatypes with special syntax. Each tuple type has a single constructor. All tuples are instances of Eq, Ord, Bounded, Read, and Show (provided, of course, that all their component types are).
Haskell implementation must support tuples up to size 15, together with the instances for Eq, Ord, Bounded, Read, and Show. The Prelude and libraries define tuple functions such as zip for tuples up to a size of 7.
The Unit Datatype
1 | data () = () deriving (Eq, Ord, Bounded, Enum, Read, Show) |
The unit datatype () has one non-⊥ member, the nullary constructor ().
Function Types
Functions are an abstract type: no constructors directly create functional values. The following simple functions are found in the Prelude: id, const, (.), flip, ($), and until.
The IO and IOError Types
The IO type serves as a tag for operations (actions) that interact with the outside world. The IO type is abstract: no constructors are visible to the user. IO is an instance of the Monad and Functor classes.
IOError is an abstract type representing errors raised by I/O operations. It is an instance of Show and Eq.
Other Types
1 | data Maybe a = Nothing | Just a deriving (Eq, Ord, Read, Show) |
The Maybe type is an instance of classes Functor, Monad, and MonadPlus. The Ordering type is used by compare in the class Ord. The functions maybe and either are found in the Prelude.
Standard Haskell Classes
- Eq
- Ord
- Read and Show
- Enum
- Functor
- Monad
- Bounded
- Numbers
- Integer (Integral)
- Int [−2^29, 2^29−1] (Integral)
- Float (RealFloat)
- Double (RealFloat)
- The class Integral contains integers of both limited and unlimited range; the class Fractional contains all non-integral types; and the class Floating contains all floating-point types, both real and complex.
Basic Input/Output
Standard I/O Functions
Output Functions
These functions write to the standard output device (this is normally the user’s terminal).
1 |
|
Input Functions
These functions read input from the standard input device (normally the user’s terminal).
1 | getChar :: IO Char |
Files
These functions operate on files of characters. Files are named by strings using some implementation-specific method to resolve strings as file names.
The writeFile and appendFile functions write or append the string, their second argument, to the file, their first argument. The readFile function reads a file and returns the contents of the file as a string. The file is read lazily, on demand, as with getContents.
1 | type FilePath = String |
Sequencing I/O Operations
The type constructor IO is an instance of the Monad class. The two monadic binding functions, methods in the Monad class, are used to compose a series of I/O operations. The >> function is used where the result of the first operation is uninteresting, for example when it is (). The >>= operation passes the result of the first operation as an argument to the second operation.
1 | (>>=) :: IO a -> (a -> IO b) -> IO b |
Exception Handling in the I/O Monad
The I/O monad includes a simple exception handling system. Any I/O operation may raise an exception instead of returning a result.
Exceptions in the I/O monad are represented by values of type IOError. This is an abstract type: its constructors are hidden from the user. The IO library defines functions that construct and examine IOError values. The only Prelude function that creates an IOError value is userError. User error values include a string describing the error.
1 | userError :: String -> IOError |
Exceptions are raised and caught using the following functions:
1 | ioError :: IOError -> IO a |
Foreign Function Interface
- Foreign Languages
- Contexts
- Lexical Structure
- Foreign Declarations
- Calling Conventions
- Foreign Types
- Char, Int, Double, Float, and Bool as exported by the Haskell Prelude as well as
- Int8, Int16, Int32, Int64, Word8, Word16, Word32, Word64, Ptr a, FunPtr a, and StablePtr a, for any type a, as exported by Foreign
- Import Declarations
- Export Declarations
- Specification of External Entities
- Standard C Calls
- Win32 API Calls
- Marshalling
- The External C Interface
Compiler Pragmas
- Inlining
- Specialization
- Language extensions