Skip to content

Instantly share code, notes, and snippets.

@carlosrberto
Last active June 6, 2018 01:43
Show Gist options
  • Save carlosrberto/0828d1eef071c584fe65ee134cc7aab3 to your computer and use it in GitHub Desktop.
Save carlosrberto/0828d1eef071c584fe65ee134cc7aab3 to your computer and use it in GitHub Desktop.
Learning Haskell

Learning Haskell

This is a summary from Yet Another Haskell Tutorial

https://learnxinyminutes.com/docs/pt-br/haskell-pt/

Lazy, pure functional programming language.

Introduction

Definitions

  • It is called lazy because expressions which are not needed to determine the answer to a problem are not evaluated.
  • The opposite of lazy is strict, which is the evaluation strategy of most common programming languages.
  • Haskell is called pure because it does not allow side effects (A side effect is something that affects the "state" of the world.
  • Haskell uses a system of monads to isolate all impure computations from the rest of the program and perform them in the safe way.
  • Haskell is called a functional language because the evaluation of a program is equivalent to evaluating a function in the pure mathematical sense.

Origins

In September of 1987 a meeting was held at the conference on Functional Programming Languages and Computer Architecture (FPCA '87) in Portland, Oregon.

There was a strong consensus at this meeting that more widespread use of this class of functional languages was being hampered by the lack of a common language. It was decided that a committee should be formed to design such a language, providing faster communication of new ideas, a stable foundation for real applications development, and a vehicle through which others would be encouraged to use functional languages.

This document describes the result of that committee's efforts: a purely functional programming language called Haskell, named after the logician Haskell B. Curry whose work provides the logical basis for much of ours.

Why use haskell

  • Write more bug-free code in less time using Haskell than other language.
  • Very readable and extensible.

Getting Started

Compilers

  • Hugs - very fast to load files, slow to run them; implements almost all of Haskell 98 (the standard) and most extensions; built-in support for module browsing; cannot create stand-alones; written in C; works on almost every platform; built-in graphics library.
  • GHC - interactive environment is slower than Hugs to load, but allows function definitions in the environment (in Hugs you have to put them in a file); implements all of Haskell 98 and extensions; good support for interfacing with other languages; in a sense the "de facto" standard. It also allows compiled objects to be loaded and tested.
  • NHC - less used and no interactive environment, but produces smaller and often faster executables than does GHC; supports Haskell98 and some extensions.

Running compiler

ghc --make Main.hs -o main

Language Basics

What is unusual is that Haskell requires that the names given to functions and values begin with a lower-case letter and that the names given to types begin with an upper-case letter. The moral is: if your otherwise correct program won't compile, be sure you haven't named your function Foo, or something else beginning with a capital letter.

Functional language

Haskell eschews side effects. A side effect is essentially something that happens in the course of executing a function that is not related to the output produced by that function.

For instance, in a language like C or Java, you are able to modify "global" variables from within a function. This is a side effect because the modification of this global variable is not related to the output produced by the function. Furthermore, modifying the state of the real world is considered a side effect: printing something to the screen, reading a file, etc., are all side effecting operations.

Pure funcions

Functions that do not have side effects are called pure. An easy test for whether or not a function is pure is to ask yourself a simple question: "Does this function's result depend only on the arguments it receives, and is returning a result the only thing it does?"

Thinking differently

All of this means that if you're used to writing code in an imperative language (like C or Java), you're going to have to start thinking differently. Most importantly, if you have a value x, you must not think of x as a register, a memory location or anything else of that nature. x is simply a name, just as "Hal" is my name. You cannot arbitrarily decide to store a different person in my name any more than you can arbitrarily decide to store a different value in x. This means that code that might look like the following C code is invalid (and has no counterpart) in Haskell:

int x = 5;
x = x + 1;

A call like x = x + 1 is called destructive update because we are destroying whatever was in x before and replacing it with a new value. Destructive update does not exist in Haskell.

Arithmetic

Prelude> 5*4+3
23
Prelude> 5^5-2
3123
Prelude> sqrt 2
1.4142135623730951
Prelude> 5*(4+3)
35

Pairs, Triples and More

Prelude> fst (5, "hello")
5
Prelude> snd (5, "hello")
"hello"

Lists

Prelude> 0:[1,2]
[0,1,2]
Prelude> 5:[1,2,3,4]
[5,1,2,3,4]

Prelude> 5:1:2:3:4:[]
[5,1,2,3,4]

The colon is called the "cons" operator; the process of adding an element is called "consing." The etymology of this is that we are constructing a new list from an element and an old list. We can see the cons operator in action in the following examples:

Prelude> 0:[1,2]
[0,1,2]
Prelude> 5:[1,2,3,4]
[5,1,2,3,4]

Some list functions

Prelude> length [1,2,3,4,10]
5
Prelude> head [1,2,3,4,10]
1
Prelude> length (tail [1,2,3,4,10])
4

Strings

In Haskell, a String is simply a list of Chars

Prelude> 'H':'e':'l':'l':'o':[]
"Hello"

Concat

Prelude> "Hello " ++ "World"
"Hello World"

Convert nunber to string

Prelude> "Five squared is " ++ show (5*5)
"Five squared is 25"

String to number

Prelude> read "5" + 3
8
Prelude> read "Hello" + 3
Program error: Prelude.read: no parse

List functions - map, filter and foldr (also foldl).

Prelude> map Data.Char.toUpper "Hello World"
"HELLO WORLD"

Prelude> filter Data.Char.isLower "Hello World"
"elloorld"

´foldr´ takes three arguments: a function, an initial value and a list. The best way to think about foldr is that it replaces occurrences of the list cons operator (:) with the function parameter and replaces the empty list constructor ([]) with the initial value. Thus, if we have a list:

Prelude> foldr (+) 0 [3,8,12,5]
28

Prelude> foldr (*) 1 [4,8,5]
160

Prelude> foldr (-) 1 [4,8,5]
0

Functions

square x = x * x

signum x =
    if x < 0
      then -1
      else if x > 0
        then 1
        else 0
        
f x =
    case x of
      0 -> 1
      1 -> 5
      2 -> 2
      _ -> -1

Using let

roots a b c =
    let discr = sqrt (b*b - 4*a*c)
        twice_a = 2*a
    in  ((-b + discr) / twice_a,
         (-b - discr) / twice_a)

Function composition

Test> square (f 1)
25
Test> square (f 2)
4
Test> f (square 1)
5
Test> f (square 2)
-1

In mathematics we write f . g to mean "f following g," in Haskell we write f . g also to mean "f following g".

Test> (square . f) 1
25
Test> (square . f) 2
4
Test> (f . square) 1
5
Test> (f . square) 2
-1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment