Skip to content

Latest commit

 

History

History
164 lines (110 loc) · 6.61 KB

ch02.md

File metadata and controls

164 lines (110 loc) · 6.61 KB

Chapter 2: Hello, Haskell

Introduction

This is my notes from Chapter 2: Hello, Haskell of the book Haskell Programming From First Principles.

2.1 Hello, Haskell

2.2 Interacting with Haskell Code

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.

2.3 Understanding expressions

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.

2.4 functions

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.

2.5 Evaluation

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.

2.6 Infix operators

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.

Declaring values

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.

2.8 Arithmetic functions in Haskell

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.

2.9 Parenthesization

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

2.10 Let and where

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

Rewrite with where clauses:

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

2.12 Definitions

  • 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 declaration f. We can apply the function f to an argument 4 to give us 6.

References

  1. Haskell Programming from First Principles

Further Reading

  1. Let vs. Where
  2. How to desugar Haskell Code