This is my notes from Chapter 2: Hello, Haskell of the book Haskell Programming From First Principles.
- Install stack: https://docs.haskellstack.org/en/stable/README/
- Learn Haskell: https://github.com/bitemyapp/learnhaskell
Haskell has a REPL (read-eval-print-loop) or GHCi
Prelude is a library of standard functions. Prelude is contained in Haskell's base package (https://www.stackage.org/package/base).
::
means "has the type". :load
is used to load a .hs
file.
Everything in Haskell is an expression or declaration. Expressions may be values, combinations of values, and/or functions applied to values. Declarations are top-level bindings which allow us to name expressions. Expressions are in normal form when there are no more evaluation steps that can be taken (when they have reached an irreducible form). The normal form of 1 + 1
is 2
. Reducible expressions are called redexes. Reducing an expression can also be called normalizing or executing an expression, though those terms are somewhat imprecise.
Expressions are the most basic unit of a Haskell program. Functions are a specific type of expression. A function is an expression that is applied to an argument and always returns a result. All functions in Haskell take one argument and return one result. When it seems that a function takes more than one argument, it is a series of nested functions, each to one argument. This is called currying. Function names start with lowercase letters. You can use camelCase as a style. Variables must also begin with lowercase letters.
Evaluating an expression means reducing the terms until the expression reaches its simplest form. Haskell uses a nonstrict evaluation ("lazy evaluation") strategy which defers evaluation of terms until they are forced by other terms referring to them. Values are irreducible, but applications of functions to arguments are reducible. Values are expressions that cannot be reduced further. Haskell only evaluates to weak head normal form (WHNF) by default. Refer to WHNF in Chapter 9 for more information.
Functions in Haskell default to prefix syntax - that is, the function being applied is at the beginning of the expression and not in the middle. Operators are functions which can be used in infix style. All operators are functions; not all functions are operators. We can sometimes use functions in infix style.
Prelude> 12 `div` 5
2
Prelude> div 12 5
2
We use infix operators in prefix fashion by wrapping them in parentheses.
Prelude> (=) 200 2
202
A function with alphanumeric name is a prefix function by default. A function with a symbol name is an infix function by default & can be made prefix by wrapping it in parentheses.
We use :info
command to get information about associativity and precedence of operators and functions. Precedence is on a scale of 0 - 9, higher is applied first. infixl
means an infix operator, left associative. infixr
means an infix operator, right associative.
Module names are capitalized, unlike variable names. We use spaces, not tabs, to indent your source code. Whitespace is significant in Haskell. We reserve breaking up of lines for when you have code exceeding 100 columns in width. All declarations within a module must start at the same column. The column that all declarations within a module must start in is determined by the first declaration in the module.
Operator | Name | Purpose |
---|---|---|
+ |
plus | addition |
- |
minus | subtraction |
* |
asterisk | multiplication |
/ |
slash | fractional division |
div |
divide | integral division, truncated towards negative infinity |
mod |
modulo | like rem , but after modular division |
quot |
quotient | integral division, truncated towards zero |
rem |
rem | remainder after division |
rem
is integer remainder, which satisfies
(x `quot` y) * y + (x `rem` y) == x
where x
is dividend , y
is divisor. The result of rem
will have the same sign as the dividend.
mod
is integer modulus, which satisfies
(x `div` y) * y + (x `mod` y) == x
where x
is dividend , y
is divisor. Recall that modulus wrap around. The results of mod
will have the same sign as the divisor.
-
as an unary operator is a syntactic sugar for negate
function.
-
as an infix operator is also the subtract
function.
The $
operator will allow everything to the right of it to be evaluated and can be used to delay function application.
Order matters when using sectioning with a function that is not commutative.
Prelude> (2/) 1
2.0
Prelude> (/2) 1
0.5
Use subtract
to connote minus 5.
Prelude> (2 -) 1
1
Prelude> (subtract 2) 1
-1
where
is a declaration and is bound to a surrounding syntactic construct.
module Area where
area1 d = pi * r * r
where r = d / 2
let
introduces an expression so that it can be used whenever you can have an expression.
module Area where
area2 d = let r = d / 2
in pi * r * r
evalStuff :: Num a => a
evalStuff = x * 3 + y
where x = 3
y = 1000
evalNum :: Num a => a
evalNum = x * 5
where x = 10 * 5 + y
y = 10
evalMore :: Fractional a => a
evalMore = z / x + y
where x = 7
y = negate x
z = y * 10
- A parameter, or formal parameter, represents a value that will be passed to the function when the function is called.
- An argument is an input value the function is applied to.
- In
f x = x + 2
,x
that occurs after the function is the parameter of the function declarationf
. We can apply the functionf
to an argument4
to give us6
.