Upgrade Yourself
26 set 2024

Haskell notes (part 01)

What is Haskell?

  • Haskell is a functional language
  • Meaning that its paradigm is not OO (Object Oriented), neither Imperative
  • A functional programming language uses a basic method of aplying functions to its arguments (or parameters)
  • There ara a ton of good reasons why you should learn a functional language like Haskell
  • Suffice to say that most OO and Imperative languages borrow methods and concepts from functional ones…
  • But, you can do your own research on this subject…

What is a Haskell function? (01)

  • It is an entity that takes a value or a set of values (including other functions)
  • And returns (reduces it to, evaluate it to, execute it to) a new value ;)
  • You should first define a function, and then, execute (call, evaluate) it
  • You can define a function in a script, using an code editor
  • As well as in GHCI, but you need to write the definition and its body on a single line separated by “;” (a semi-colon)

What is a Haskell function? (02)

  • e.g.:
  • Int -> Int -> Int ; soma x y = x + y
  • or
  • Float -> Float -> Float ; soma x y = x + y
  • or
  • Double -> Double -> Double ; soma x y = x + y
  • Call it like so: soma 2 3 – (et.al)
  • :t – check their types

Translating mathematics functions into Haskell ones

  • Note that function applications default from left to right
  • f(x) ≍ f x
  • f(x,y) ≍ f x y
  • f(g(x)) ≍ f (g x)
  • f(x,g(y)) ≍ f x (g y)
  • f(x)g(y) ≍ f x * g y
  • et.al.

The Haskell platform (01)

  • Avoid Window$ OS for working at all costs…
  • Especially when learning coding/programming…
  • Avoid VsCode (and VsCodium) at all costs as well…
  • They are a declaration of lazy programmers (in an extremely bad sense (note in the good sense of coding))
  • Worst of all, if they are used on a Linux environment, it is an heresy and a profanation ate the same time… ;)
  • Unless, they impose it on you when working locally and/or remotely

The Haskell platform (02)

  • Preferably, use a GNU/Linux distro like Debian…
  • and Emacs (or an Emacs start-kit) and/or Vim (or a Vim start-kit)
  • These are real editors for serious programmers ;)
  • If you do not have the muscle brain to use one of them or both, Zed can be berable as your code editor:
  • https://zed.dev/
  • Installing haskell on Linux Debian (or Debian-like) OSes
  • sudo apt install haskell-platform
  • sudo apt autoremove

Haskell Programming Language

  • A simple “Hello Haskell!” script
  • Copy this code into a, say, “hello_hask.hs”
  • And read on to learn how to compile/run it…
import Data.Binary.Put (putShortByteString)
import Data.Text.Encoding.Error (ignore)
main = do
  putStrLn "Hello! World!"

-- Just ignore this part, if you do not use Emacs and eev

-- (buffer-file-name)

{-
 (eepitch-ghci)
 (eepitch-kill)
 (eepitch-ghci)
:load hello.hs
-}

  • How do you start a ghci REPL in Linux?
  • Just type “ghci” in a terminal
  • Then you can “:set prompt ”$sth“” as you wish
- :set prompt "hsk > "
  • You can call “M-x helm-ucs” and choose “𝜆 > ”
  • as your prompt, e.g. :)

The haskell interpreter

  • ghci is the haskell interpreter
  • You can also run a program callint it on a terminial
  • followed bye the name of the haskell script. Like so:
  • ghci foo.hs
  • ghci /path/to/script.hs

Then you can start issuing commands at the REPL..

- putStrLn "Hello Haskell!"

For getting help and information, do:

  • :doc $func
  • :help $func
  • :info $func
  • local help:
  • dino laptop
  • (browse-url-firefox “~/.ghcup/ghc/9.4.8/share/doc/ghc-9.4.8/html/index.html”)
  • cypher laptop
  • (browse-url-firefox “~/.ghcup/ghc/9.6.1/share/doc/ghc-9.6.1/html/index.html”)
  • On-line help:
  • ghc-docs
  • (browse-url-firefox “https://downloads.haskell.org/ghc/latest/docs”)
  • hoogle-docs
  • (browse-url-firefox https://hoogle.haskell.org")
  • On Emacs (a personal local function):
  • M-x cypher/haskell-docs

For repeating the last command

  • Type “it” on GHCI

For loading, reloading and calling a function from your prompt, do:

  • :main
  • :l(oad)
  • :l /path/to/script.hs
  • :r(eload)
  • :r /path/to/script.hs
  • :q(uit) or “C-d”
  • setting your Haskell editor
  • ghci> :edit hello.hs
  • editor not set, use :set editor
  • ghci> :set editor emacsclient

For running a program on console, do:

  • runhaskell $script.hs

For compiling a script, do:

  • ghc $script.hs

Then you can run your compiled code like so:

  • ./$script

For issuing a bash command inside de REPL, do:

  • :!$cmd
  • $cmd is just a variable

Start writing your haskell scripts with: (01)

- This is just an example:

- module $Test where

- main :: IO() -- it is the monad IO () - the Input/Output monad
- main = putStrLn "Hello Haskell!"

- If you have multiple lines after "main =", you've to write:

- main = do

- and open a new line (2 spaces of left-indentation)
- for writing your code...

Start writing your haskell scripts with: (02)

  • What is a module?
  • module is a place where we keep all functions we’ve defined
  • Prelude is the default Haskell module where all standard functions are already defined
  • Sometimes, we have to import a module for building more specific applications…

Commenting your Haskell code

  • Commenting your code is a good programming practise
  • It helps you, and others, who reads the code
  • Especially, if you visit it after a while…
  • It serves as a way of documenting your code as well
  • For commenting single lines, use two dashes “–” before or after them
  • Like so: – this is a single-line comment
  • Multi-line comments start with curl-braces and a single dash and close the with single dash and curl-braces.
  • Like so: {- Write lines here -}
  • Multi-line comments can be nested

Haskell classes and types

  • Note Haskell is case-sensitive
  • What is a type?
  • It is set of related values. E.g.: Numbers (Int, Integers, Double and Float)
  • Boolean types hold logic values: True and False
  • We can combine types and build functions
  • Boolean types map all functions from a Bool to another Bool
  • Bool -> Bool
  • :t (&&) - yields True if the two sides are True
  • :t (||) - inclusive Or - yields False if the two are False, otherwise renders True
  • :t not - it changes the Boolean values to be the opposite of themselves
  • Haskell has got a short-circuit semantic
  • We can call it a lazy evaluation
  • False && True && True – this yields False, because it stops after evaluating the two first elements
  • T~ (v has got a type T)
  • We have to assing a type to every expression we intend to execute (evaluate)
  • Example of expressions: 1; not True; not (not False); 3 + 4; et.al.
  • :t (+)
  • :t map
  • :t filter
  • Int~) + 2
  • Float~) + 2
  • Bool~ (3 has got a type Bool) gives an error
  • Types should be coherent, otherwise the interpreter will yell at them
  • Before evaluating any expression, Haskell checks its type on the background
  • This checking up is called type inference
  • if True 1 ; else False – this gives an error. Because True is an Bool and has to return a Bool and not an Int

You can check types with:

  • :t(ype) $func ($id)
  • for operators, you’ve to place them inside parenthesis, so that it will be possible to see their types:
  • :t (*) – you’ve to enclose infix operators with parentheses to turn them into prefix ones for checking their types
  • :t (==) – you’ve to enclose infix operators with parentheses to turn them into prefix ones for checking their types
  • An script to show some math operators and math functions in action
module Main where

main :: IO ()
main = do
  print (5 + 5)
  print (5 * 7)
  print (8 - 3)
  print (5 / 2)
  print (3 * 6.0)
  print (4 ** 3)
  print (sqrt 36.0)
  print (round 4.4)
  print (round 4.6)
  print (floor 4.6)
  print (ceiling 4.6)
  return ()

-- Just ignore this part, if you do not use Emacs and eev

-- or type "C-c C-l". So that, the function is automagically loaded into haskell REPL
-- M-x haskell-doc-mode

-- (buffer-file-name)

{-
 (eepitch-ghci)
 (eepitch-kill)
 (eepitch-ghci)
:load maths.hs
:main
-}

Bool and compare

  • ’a’ == ’b’ -> False
  • ’a’ `compare` ’b’ -> LT

The “show” type class prints values as strings

- :t show 3 -> show 3 :: String

The “read” type class prints values as non-strings

- :t read "3" -> read "3" :: Read a => a

- read "3" + 5
- read "True" && True

- read "4" -- error, since it needs a type annotation, because it
- does not know if you want a Float or Int

- read "4" :: Int
- read "4" :: Double
- read "5" :: Float
- (read "4" :: Float) * 3
- read "[1,2,2]" :: [Float]
- read "('a', 3.4)" :: (Char, Float)

  • A simple doubleMe and doubleUsSumUs haskell functions
  • As usual, code the code; save it on a “.hs” ending file and compile/run it
-- load the function in the repl with:
-- :l hello
-- after saving it, you do not need to load again, but:
-- :reload
-- and call it with:
-- :main

-- Script from the book:
-- Learn You a Great Haskell

-- double an only given number
doubleMe x = x + x

-- double two given numbers
-- and sum them
doubleUsSumUs x y = (x * 2) + (y * 2)

-- Just ignore this part, if you do not use Emacs and eev

-- or type "C-c C-l". So that, the function is automagically loaded into haskell REPL
-- M-x haskell-doc-mode

-- (buffer-file-name)

{-
 (eepitch-ghci)
 (eepitch-kill)
 (eepitch-ghci)
:load baby.hs
-}

Compiler type inference

- the compiler can infer what we want,
- by looking to the rest of the
- list elements
- [read "True", False, True, False]

You can get a range with “..” notation inside a list

  • [1..10] – [start..end]
  • [LT .. GT]

Checking bounded types

- minBound :: Int
- maxBound :: Int
- maxBound :: (Bool, Int, Char)

Functions (built-in)

  • e.g.:
  • 4 + 2
  • 4 - 2
  • 4 * 2
  • 4 ^ 2
  • 4 ** 2
  • 4 / 2
  • 4 `div` 2
  • 4 / 0
  • 4 `div` 0
  • succ ’a’
  • succ 7
  • sum [1..5]
  • et.al.

Function naming (rules)

  • No space between two or mor strings
  • Must start with downcase letter
  • Can have down, upper-cases letters, digits, underscores, and single quote in its end
  • camelCase style
  • e.g.: fooBar; foo1; foo’; foo’’; foo’’’ (’’’ …)
  module Dup where

-- You can write functions with same names (with two (or more)
-- versions (you can use prime(s) "'" for that), and different types

-- load and call the functions on GHCI

-- dupFoo 3
-- dupFoo' 3

-- function declaration
dupFoo :: Int -> Int

-- build the function
dupFoo n = n + n

-- function declaration
dupFoo' :: Float -> Float

-- build the function
dupFoo' n = 2 * n


{-
 (eepitch-ghci)
 (eepitch-kill)
 (eepitch-ghci)
:load dup.hs

-}

  • Cannot use Haskell reserved words: case, class, data default, deriving, do, else, if, import, in, infix, infixl, infixr, instance, let, module, newtype, of, then, type, where

Function assignments

  • e.g.:
  • What does the following expression mean?
- div :: Integral a => a -> a -> a
- div :: Int -> Int -> Int

  • It means that the div(ision) function takes two arguments (or parameters) of type Int and returns a value of the same type (Int)
  • Integral is a Class, in Haskell
  • division x y = x `div` y
  • or
  • division x y = div x y
  • It is not necessary to add function signatures in your heading code, but Haskell good programming practice say so…

Functions can be classified on:

  • prefixed functions
  • e.g.: - 2
  • div 4 2
  • infix functions
  • 2 + 4
  • 4 `div` 2
  • post-fixed functions
  • 2 sqrt

Assigning non-default types to data

- :t 20

- 20 :: Int
- 20 :: Float
- 20 :: Double

fromIntegral function

  • :t fromIntegral
  • (length [1,2,3,4]) + 3.0 – error
  • fromIntegral (length [1,2,3,4]) + 3.7

Lists are the most common types Haskell uses to manipulate data

  • There are no loops on Haskell
  • It uses recursive functions (functions that call themselves)
  • Which are most powerful methods to reach what loops do on OO and Imperative languages

List names (convention)

  • ns – list of numbers
  • xs – list of arbitrary values
  • xss – list of list of characters

Joining data with “<>” (used to be “++”)

- e.g.:

- lists:
- [1,2,3] <> [4,5,6]

- lists of lists
- [[1,2,3],[4,5,6]] <> [[7,8,9]]

- strings (chars, for real):
- ['h', 'e'] <> "llo"

Accessing data elements with “!!”

- words = ["foo", "bar", "barz", "foo1", "bar2", "barz1", "barz2"]

- words !! 0
- words !! 5
- words !! 10

  • An script to show how to acces list elements with:
  • !!
  • head
  • last
  • init
  • And
  • tail
main :: IO ()

-- Lists start at 0 index

scores :: [Int]
scores = [5, 7, 9, 10]

-- the bang operator access list indexes

main = do
  print [scores !! 0]
  print [scores !! 2]

  print (head scores)
  print (last scores)
  print (init scores)
  print (tail scores)

-- Just ignore this part, if you do not use Emacs and eev

-- or type "C-c C-l". So that, the function is automagically loaded into haskell REPL
-- M-x haskell-doc-mode

-- (buffer-file-name)

{-
 (eepitch-ghci)
 (eepitch-kill)
 (eepitch-ghci)
:load lists.hs
:main
-}

Consing (constructing) lists with “:”

- 1 : [2,3] -- prepends 1 to the list, using cons ":"

- 'h' : ['e', 'l', 'l', 'o']

- 'f' : 'o' : ['o']

- [1,2,3] : []

- [1] : [2] : [3] : [[10,11,12]]

- l = [1] : [2] : [3] : [[10,11,12]]

Accessing list elements with head, init and tail

- l = [1] : [2] : [3] : [[10,11,12]]

- head l
- init l
- tail l

Data pattern matching

  • Copy the function bellow and save it as:
  • e.g.: patMatch.hs
module PatMatch where

-- partern matching

sorte :: Int -> String
sorte 7 = "Acertou! Parabéns"

-- load this function and
-- call this it like so:
-- sorte # -- where "#" is a number

-- we should always add a catchall at the end of our patern matching function

sorte x = "Que pena... Errou"

-- ignore this part if you do not have "eev" in Emacs

{-
 (eepitch-ghci)
 (eepitch-kill)
 (eepitch-ghci)
:load partern_match.hs
-}

Emacs Haskell Niceties (1)

- Type "C-c C-l" when editing a haskell script. So that, the function is automagically loaded into haskell REPL

- (buffer-file-name)
- eval this inside your local buffer or file

Emacs Haskell Niceties (2)

- You can use eeit
- and just add ":main" to its block
- or you can call ghci with "C-c C-l" as well

- use 2 spaces indentation
- M-x haskell-doc-mode

Branches and decision making

  • if, then, else
  • A simple script
module Main where

-- call the down function

main = printSmallNumber 11

-- function name = body

printSmallNumber num =
 if num < 10
 then print num
 else print "The number is too big"

Branches and decision making (cont…)

-- Just ignore this part, if you do not use Emacs and eev
-- or type "C-c C-l". So that, the function is automagically loaded into haskell REPL
-- M-x haskell-doc-mode
-- (buffer-file-name)

{-
 (eepitch-ghci)
 (eepitch-kill)
 (eepitch-ghci)
:load prNum.hs

-}

Good Haskell tutorials:

- Books
- Effective_Haskell
- Learn_You_a_Great_Haskell
- Haskell_98_Tutorial
- Haskell_TCofP
- Haskell_PaTyp

- Introduction au langage Haskell
- by nokomprendo

- gitlab
- http://tny.im/CxTon

- Articles
- http://tny.im/qZbsp

- Videos
- http://tny.im/lFIfd

Tags: Haskell Functional Programming Emacs
RSS

uysf.com by upYsf is licensed under a
Creative Commons Attribution-ShareAlike 3.0 Unported License.
For comments, errata, suggestions and support, please reach me at
Para comentários, erros, sugestões e patrocínio, por favor, entre em contado comigo através de:

VRFdS