Thursday, September 14, 2017

Quick Haskel

I have been documenting the  concepts and apis of the programming language Haskel. This document has examples of various constructs of the Haskel programming language. It is a live document. Until I complete the contents of [0], I will be updating this document.

function declaration
f x = x + 2   # f(x) = x + 2

conditional
abs x = if x < 0 (-1) * x else x  # an if should always have an else

list
list contains element of the same type.
let myList = [1,2,3]
strings are considered as lists too. "abc" is equivalent to ['a', 'b', 'c']

append to last [slower operation if the first list is big]
myList ++ [5, 6]

append single element to first
7 : myList
[1, 2, 3] is equivalent to 1:2:3:[]

access list element
myList !! 2     # access 2nd element of the list

list comparison
rule: 2 lists can be compared if the elements can be compared. Nonempty list is greater than empty list. element by element is done from start of the list until a match found or one/both of the lists ends.
operator: <, <=, >=, >, ==
a = [1,2,3], b = [4,5,6]
a < b # False

list of list
a = [[], [1,2,3], [4]]

list operations
[<head><......tail......>]
[<.......init.....><last>]
operations does not have side effect meaning they don't modify the list.
head [1,2,3,4,5] #1
tail [1,2,3,4,5] #[2,3,4,5]
init [1,2,3,4,5] #[1,2,3,4]
last [1,2,3,4,5] #5
length [1,2,3] # 3
null [] # True
null [1] # false
reverse [1,2,3] # [3,2,1]
take 1 [7,2,3] # [7]
drop 1 [7,2,3] #[2,3]
maximum [2, 4, 5, 1] # 5
minimum [2, 3, 1, 5] # 1
sum [1, 2, 3] # 6
product [1, 2, 3, 4] # 24
elem 7 [1, 6, 7] # True, 7 belongs to the list
[1..5] #[1,2,3,4,5]
['a'..'d'] # ['a', 'b', 'c', 'd']
[5,4..1] #[5,4,3,2,1]
cycle[1,2,3] #produces infinite list [1,2,3,1,2,3,1,2,3,...infinite]
repeat 5 # [5,5,5,5,5,5,5....infinite size]
repeat [1] # [[1], [1], [1], [1], [1] ... infinite size]
replicate 4 2 # [2, 2, 2, 2]

list comprehension
[x * 2 | x <- [0..5]]  # all x * 2 s such that x belongs to the set [0, 1, 2, 3, 4, 5]
[x * 2 | x <- [0..5], x > 5] # multiple predicate
evenOdd xs = [ if x `mod` 2 == 0 then 0 else 1 | x <- xs ] # function evenOdd takes a list xs and returns a list of 0s and 1s
usage: evenOdd [0..10] # [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
[x + y | x <- [0..5], y <- [0..3]] # for all x and y in the sets, generates a list that has the value x + y
length' ls = sum [1 | _ <- ls] # generate a list that has 1 for each element of ls, then sum up all the 1s

Tuple
stores heterogenous typed elements. size is fixed.
(1, 1.1, 'a', "saif")
tuple types are defined by the number of elements in it. a list can hold only same typed elements. thus,
[(1,2), (2, 3), (1,2,3)] causes ERROR
[(1, 2), ('a', 1)] also causes ERROR

Pairs
(1, 3)
fst (1,3) # 1
snd (1,3) # 3
zip ['a', 'b', 'c'] ['x', 'y', 'z'] # [('a','x'),('b','y'),('c','z')]
zip "abc" [1..] # [('a',1),('b',2),('c',3)] notice how only 3 elements are taken from the infinite set

## Type ##
Type is fixed.
ghci command :t shows type of a variable or function.
function type
sum :: Int -> Int -> Int
sum a b =  a + b

common types
Int : bounded by underlying system
Integer : unbounded
Float : real number with single precision
Double : real number with double precision
Bool : boolean type
Char : a Unicode character

Type Class
A type class encloses one or more types.
A type can be member of one more type classes.

ghci command. :t (==)
(==) :: (Eq a) => a -> a -> Bool
How to read. (==) takes 2 argument of type class Eq and returns a Bool type.

Eq
applicable function: ==, /= (not equal)

Ord
values of Ord type can be sorted.
functions to apply : >, >=, <, <=.
comparator function returns GT, LT or EQ.

Show
the value can be presented as a string.
function to apply on this type: show # show 3 => "3"

Read
from string, raw type can be formed
applicable function: read
ex: add (read "3") + 3  # 6
read function need enough hint to know which raw type to produce. for example,
this does not work, read "3"
but read "3" + 3 works, because read knows "3" to be converted to Int
the following example works similar to type casting (according to me)
read "3" :: Int # specifically specify we need 3 to be Int.

more examples:
read "[1, 2, 3]" :: [Int]  # [1,2,3]
read "(2, 'a')" :: (Int , Char) # (2, 'a')
[read "True", True, False, True]

Enum
sequentially enumerable values.
applicable functions: succ, pred

Bounded
has an upper and lower bound

Num
values act like numbers

Floating
applicable functions: sin cos
Enclosing type: Float, Double

Integral
enclosing type: Int, Integer

## Syntax in Functions ##
Pattern matching: choosing a function based on input parameters. Pattern matching works very similar to if else construct.
citizen :: String -> String
citizen "BD" = "Bangladeshi"
citizen "USA" = "American"
citizen x = "Unknown citizen"

line 0, is function input and output type declaration. line 1, says what to do if input = "BD", so on and so forth.

can be used to define base case.
fibonacci :: Int -> Int
fibonacci 0 = 0
fibonacci 1 = 1
fibonacci n = fibonacci(n-1) + fibonacci(n-2)

If the pattern matching does not contain all the possibilities of input, interpreter will throw an exception.

vector_add :: (Double, Double) -> (Double, Double) -> (Double, Double)
vector_add a b = (fst a + fst b, snd a + snd b)
another way to write
vector_add (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)

Usage of '_'
fst' :: (a, b, c) -> a
fst' (a, _, _) = a

head' :: [a] -> a
head' (a:_) = a

As pattern break up input in parts, also gives a way to access the whole. can be applied on list only.
shead :: [Int] -> Int
shead whole@(frst : rest) = frst

Guards
bmiTell :: Double -> String
bmiTell bmi
  | bmi <= 18.5 = "underweight"
  | bmi <= 25.0 = "normal wieght"
  | bmi <= 30.0 = "fat"
  | otherwise = "unhealthy fat"

guard syntax | boolean-expression = expression-to-be-evaluated

where
clause. provides variable like functionality of imperative programming language.

bmiTell w h
  | bmi <= skinny = "you are fine"
  | bmi <= fat = "you are not fine"
  where bmi = w / h ^ 2
        skinny = 18.5
        fat = 23.5

forming tuple and accessing it
initials :: String -> String -> String
initials first last = [f] ++ "." ++ [l] ++ "."
  where (f:_) = first
        (l:_) = last
where to pattern match
desList :: [a] -> String
desList ls = "the list is " ++ check ls
        where check [] = "empty"
              check [x] = "singleton"
              check xs = "a longer list"

Let
let lets you create an expression that generates a value. let are local in scope.
cylinder :: Double -> Double -> Double
cylinder r h =
  let sideArea = 2 * pi * r * h
      topArea = pi * r ^ 2
  in sideArea + 2 * topArea

pattern: let <variable binding> in <expression>
let square x = x * x in (square 2, square 3, square 4)

list comprehension
calcBMI xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2, bmi > 25.0]
the value bound through let is visible before '|' and after the let

Case expression
syntax:
case expression of pattern -> result
                   pattern -> result
                   pattern -> result
                   pattern -> result
example:
sum' :: [Int] -> Int
sum' xs = case xs of [] -> error "empty list"
                     _ -> sum xs

case can be used inside a function too.
describeList ::[a] -> String
describeList ls = "The list is " ++ case ls of [] -> "empty"
                                               [x] -> "singleton"
                                               xs -> "a longer list"

Reference:
[0] http://learnyouahaskell.com/

No comments:

Post a Comment