Haskell Notes

I wanted to learn more about Haskell so I can understand the Pandoc code base more.

1 18

References

Lecture 1: ...And so It Begins

This is an online course on Functional Programming that uses the Haskell programming language. This course is aimed at beginners who wish to learn functional programming, but also people who have experience with functional programming and want to learn Haskell in particular. The course assumes no previous knowledge.

Haskell

Haskell is:

Features

Haskell Uses

Running Haskell

The easiest way to get Haskell is to install the stack tool, see this resource for instructions. Type stack ghci in the command line to start using Haskell. Prelude> is the GHCi prompt. It indicates that we can use the functions from the Haskell base library called Prelude. The :type GHCi command can give you the type of an expression. The tail function works on lists and returns all except the first element of the list.

Expressions and Types

expressions and types are the bread and butter of Haskell. In fact, almost everything in a Haskell program is an expression. There are no statements like in Python, Java, or C. An expression has a value and a type. We write an expression and its type like this: expression :: type.

Syntax of Expressions

Expressions consist of functions applied to arguments. Functions are applied (called) by placing the arguments after the name of the function - there is no special syntax for a function call.

Haskell Python, Java or C
f 1 f(1)
f 1 2 f(1,2)

Parentheses can be used to group expressions (just like in math or other languages).

Haskell Python, Java or C
g h f 1 g(h,f,1)
g h (f 1) g(h,f(1))
g (h f 1) g(h(f,1))
g (h (f 1)) g(h(f(1)))

Function calls bind tighter than operators, just like multiplication binds tighter than addition. Function application associates left.

Syntax of Types

Some basic types of Haskell to get you started.

Type Literals Use Operations
Int 1, 2, 3 Number tpe +, - , *, div, mod
Integer 1, -2, 900000000 Unbounded number type +, - , *, div, mod
Double 0.1, 1.2e5 FLoating point number +, - , *, /, sqrt
Bool True, False Truth Values &&, || not
String or [Char] "abcd", "" Strings of characters reverse, ++

The names of types in Haskell start with a capital letter. Some values like True also start with a capital letter, but variables and functions start with a lower case letter (reverse, not, x). Functions are written using the -> syntax:

In Haskell, number literals are overloaded which means they can be interpreted as any number type (e.g. Int or Double). The type String is just an alias for type [Char] which means "list of characters".

The Structure of a Haskell Program

Haskell uses the .hs file extension, and you can run a haskell file with stack runhaskell <filename>.

polynomial :: Double -> Double
polynomial x = x^2 - x - 1

The above is a definition of a function called polynomial. It has a type annotation and an equation. Note how an equation for a function differs from the equation of a constant by the presence of a parameter x left of the = sign. Note that ^ is the power operator in Haskell. The code below is the definition of a function called f.

f x = polynomial (polynomial x)

The below code is the description of what happens when you run the program. It uses do-syntax and the IO Monad. You can use ; to separate lines or use the special :{:} syntax to paste a block of code into GHCi. You can :load code form a file into the GHCi. If the file has already been loaded, you can use reload.

How do I get anything Done?

Conditionals

In other languages, if is a statement. It doesn't have a value, it just conditionally executes other statements. In Haskell, if is an expression. It has a value. It selects between two other expressions. It corresponds to the ?: operator in C or Java.

price = if product == "milk" then 1 else 2

Because Haskell's if returns a value, you always need an else. The not-equals operator is written /= in Haskell.

Haskell has two different ways of creating local definitions: let ... in and where. where adds local definitions to a definition:

circleArea :: Double -> Double
circleArea r = pi * rsquare
    where pi = 3.1415926
          rsquare = r * r

let... in is an expression:

circleArea r = let pi = 3.1415926
                   rsquare = r * r
               in pi * rsquare

Haskell variables into which you can put new values. Haskell variables name a value (or rather, an expression) and that's it.

A defintion of a function can consist of multiple equations. The equations are matched in order against the arguments until a suitable one is found. This is called pattern matching. Pattern matching in Haskell is very powerful:

greet :: String -> String -> String
greet "Finland" name = "Hei, " ++ name
greet "Italy"   name = "Ciao, " ++ name
greet "England" name = "How do you do, " ++ name
greet _         name = "Hello, " ++ name

The function greet generates a greeting given a country and a name (both Strings). It has a special case for three casesm and then a default case. The special pattern _ matches anything. it's usually used for default cases. The standard library function show can turn almost anything into a string.

In Haskell, all sorts of loops are implemented with recursion. Function calls are very efficient, so you don’t need to worry about performance.

In Haskell indentation matters, a bit like in Python. The complete set of rules for indentation is hard to describe, but you should get along fine with these rules of thumb:

  1. Things that are groped together start from the same column.
  2. If an expression (or equation) has to be split on to many lines, increase indentation.

Lecture 2: Either you Die a Hero...

Haskell helper variables for recursive functions:

repeatString n str = repeatHelper n str ""

repeatHelper 0 _   result = result
repeatHelper n str result = repeatHelper (n-1) str (result++str)

Haskell's conditional definition or guarded definition is a better way to handle conditionals with multiple cases. This is a bit like pattern matching in that you have multiple equations, but you can have arbitrary code deciding which equation to use.

describe :: Int -> String
describe n
  | n==2      = "Two"
  | even n    = "Even"
  | n==3      = "Three"
  | n>100     = "Big!!"
  | otherwise = "The number "++show n

The basic data structure in Haskell is the list. Lists are used to store multiple values of the same type (Haskell lists are homogenous). Haskell lists are implemented as singly linked lists.

[True,True,False] :: [Bool]
["Moi","Hei"] :: [String]
[] :: [a]                   -- more about this later
[[1,2],[3,4]] :: [[Int]]    -- a list of lists
[1..7] :: [Int]             -- range syntax, value [1,2,3,4,5,6,7]

The Haskell standard library comes with a lot of functions that operate on lists. here are some of the most important ones, together with their types:

head :: [a] -> a            -- returns the first element
last :: [a] -> a            -- returns the last element
tail :: [a] -> [a]          -- returns everything except the first element
init :: [a] -> [a]          -- returns everything except the last element
take :: Int -> [a] -> [a]   -- returns the n first elements
drop :: Int -> [a] -> [a]   -- returns everything except the n first elements
(++) :: [a] -> [a] -> [a]   -- lists are catenated with the ++ operator
(!!) :: [a] -> Int -> a     -- lists are indexed with the !! operator
reverse :: [a] -> [a]       -- reverse a list
null :: [a] -> Bool         -- is this list empty?
length :: [a] -> Int        -- the length of a list

Some list operations come from the module Data.List. You can import a module in code or in GHCi with the import Data.List syntax. One example is the sort function which sorts a list:

Prelude> import Data.List
Prelude Data.List> sort [1,0,5,3]
[0,1,3,5]

Because Haskell is pure, it also means that functions can't mutate (change) their inputs. Mutation is a side effect, and Haskell functions are only allowed output via their return value. This means that Haskell list functions always return a new list.

So what does a type like head :: [a] -> a mean? It means given a list that contains elements of any type a, the return value will be of the same type a. a is a type variable. A type variable means a type that is not yet known, or in other words a type that could be anything. Two variables can turn into concrete types by the process of type inference.

In a type like [Char] we call Char a type parameter. A type like the list type that needs a type parameter is called a parameterized type.

Comments

You have to be logged in to add a comment

User Comments

Insert Math Markup

ESC
About Inserting Math Content
Display Style:

Embed News Content

ESC
About Embedding News Content

Embed Youtube Video

ESC
Embedding Youtube Videos

Embed TikTok Video

ESC
Embedding TikTok Videos

Embed X Post

ESC
Embedding X Posts

Embed Instagram Post

ESC
Embedding Instagram Posts

Insert Details Element

ESC

Example Output:

Summary Title
You will be able to insert content here after confirming the title of the <details> element.

Insert Table

ESC
Customization
Align:
Preview:

Insert Horizontal Rule

#000000

Preview:


View Content At Different Sizes

ESC

Edit Style of Block Nodes

ESC

Edit the background color, default text color, margin, padding, and border of block nodes. Editable block nodes include paragraphs, headers, and lists.

#ffffff
#000000

Edit Selected Cells

Change the background color, vertical align, and borders of the cells in the current selection.

#ffffff
Vertical Align:
Border
#000000
Border Style:

Edit Table

ESC
Customization:
Align:

Upload Lexical State

ESC

Upload a .lexical file. If the file type matches the type of the current editor, then a preview will be shown below the file input.

Upload 3D Object

ESC

Upload Jupyter Notebook

ESC

Upload a Jupyter notebook and embed the resulting HTML in the text editor.

Insert Custom HTML

ESC

Edit Image Background Color

ESC
#ffffff

Insert Columns Layout

ESC
Column Type:

Select Code Language

ESC
Select Coding Language

Insert Chart

ESC

Use the search box below

Upload Previous Version of Article State

ESC