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

Add Basics/Types #41

Open
wants to merge 1 commit into
base: development
Choose a base branch
from
Open
Changes from all commits
Commits
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
177 changes: 177 additions & 0 deletions en/lessons/basics/types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
---
version: 1.0.0
title: Types
---

Types are a fundamental and integral part of Haskell. Haskell's advanced
type system sets it apart from other languages, and is a powerful method for
ensuring that your code does what you want it to do.

{% include toc.html %}

## Extensions and Imports

You will need to add the following lines to the top of your Haskell source
file (`.hs`) to be able to run these examples:

```haskell
{-# LANGUAGE OverloadedStrings #-}

import Data.Text ( Text )
```

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add "we'll explain why this is needed later" or something similar?

## Static Typing

Haskell is a statically-typed programming language. This means that the type
of all data must be known before the program is compiled. Some imperative
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
of all data must be known before the program is compiled. Some imperative
of all data must be known before the program is executed. Some

languages, such as Java and C++ are also statically-typed, while others like
Python and JavaScript are not.

## Type Inference

Haskell's type system works very differently from that of Java and C++.
Instead of declaring the type of every single function and variable, Haskell
can *infer* the type of values based on just a few declarations.

Typically, you just need to specify the type of a function. The types of all
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this isn't actually required, consider saying something like this instead:

while Haskell does not require type annotations in most cases, it is good practice to annotate the types of top-level definitions. This adds an extra layer of documentation, and safety where the Haskell compiler can verify our intent (as expressed in the type annotation) matches the code.

intermediate values used in the function will be inferred by Haskell, and you
don't have to state their types explicitly.

Type inference is a killer feature of Haskell, and once you get used to it, you
won't want to work without it.

## Type Declarations
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider changing this to "type signatures" or "type annotations", so it won't be confused with declaring new types (using data/newtype/etc)


In Haskell, you declare types on a separate line from where they are used.
Even though I said above that you usually only declare types for functions, in
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can avoid this line by saying "top-level definitions"

these examples we are going to declare them for single values.

Type names are always capitalized in Haskell, and value (or function) names
are always lower-case.

### Syntax

```
valueName :: Type
valueName = definition
```

## Primitive types

### Boolean

Haskell has booleans, and they can either be `True` or `False`

```haskell
imTrue :: Bool
imTrue = True

imFalse :: Bool
imFalse = False
```

### Integer

Haskell has two common integer types, `Int` and `Integer`

#### `Int`

A fixed-precision type, with at least the range `[-2^29 .. 2^29-1]`, or 30 bits
It is commonly implemented as 32 or 64 bits

```haskell
positiveInt :: Int
positiveInt = 42

negativeInt :: Int
negativeInt = -37
```

The fact that `Int`'s size is limited means it is subject to overflows. These
occur without warning, so if they are a concern, use `Integer`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
occur without warning, so if they are a concern, use `Integer`
occur without warning, so if they are a concern, use `Integer`.


#### `Integer`

An arbitrary-precision type. Its size is only limited by the memory on your
machine.

```haskell
positiveInteger :: Integer
positiveInteger = 42

negativeInteger :: Integer
negativeInteger = -37
```

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any chance you could add a little something about Word? I'm especially interested in promoting it as a type that can't be negative, instead of using Int and hoping for the best. It's also the occasion to evoke the correct by construction paradigm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider mentioning Natural instead of or together with Word?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the fact that arithmetic underflows are handled differently:

When doing 0 - 1

  • Since Word is modular, it loops back to 18446744073709551615
  • In the case of Natural, an arithmetic underflow exception is thrown

### Floating Point

Haskell has floating-point numbers, single-precision `Float` and
double-precision `Double`

A `Float` will be 32 bits. For more information see this [wikipedia page](https://en.wikipedia.org/wiki/Single-precision_floating-point_format)
A `Double` will be 64 bits. For more information see this [wikipedia page](https://en.wikipedia.org/wiki/Double-precision_floating-point_format)

```haskell
aFloat :: Float
aFloat = 3.14159

smallDouble :: Double
smallDouble = 0.00003

mediumDouble :: Double
mediumDouble = 17.4

bigDouble :: Double
bigDouble = 156042.4039

negativeDouble :: Double
negativeDouble = -137.485

wholeDouble :: Double
wholeDouble = 42.0
```

### Char

Haskell represents single characters in the `Char` type.

`Char` literals are always surrounded with single quotes (`''`)

```haskell
imAChar :: Char
imAChar = 'a'

imZChar :: Char
imZChar = 'z'

singleQuote :: Char
singleQuote = '\''
```

### Text

Text values can go in the `Text` type

`Text` literals are always surrounded with double quotes (`""`)

```haskell
someText :: Text
someText = "Let's learn Haskell"
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a couple of examples for Text? Especially the functions that do not exist in base for String?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, great idea


#### The `String` Type

Haskell's default text type is `String`. You may notice that none of the
examples in this course refer to `String`, using `Text` instead.

Unfortunately, `String` is a bit of a historical accident. Internally, it
is a linked-list of single characters. While this may be a satisfying use of
linked lists, it is not a practical design for representing strings.

Since it has been around from the beginning, and it works fine for small
strings, the `String` type is common in Haskell. It is used everywhere in
Haskell's default libraries.

`Text` is more convenient, performant and capable than `String`. We want
beginners to avoid the mistakes of the past and start off with good
practices, so we have chosen to teach `Text`.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this would be a good place to mention that text lives in a different package/module, what overloadedstrings does, and how to convert String <-> Text?