A pure, lazy, functional programming language. Basically, it is something that happens when like-minded cool people come together.
What does it mean for Haskell to be a functional programming language? Well, it means that Haskell follows the principle of functional programming — a programming paradigm where functions are the basic building blocks of computation.
Def: A function is a mapping that takes one or more arguments and produces a single result.
Haskell comes with a large number of built-in functions, which are defined in a library file called the standard prelude.
Just as in lambda calculus haskell follows a fixed pattern for functions. Here are some examples to elaborate:
f x y
f (g x)
f x (g y)
f x * g y
x `f` yis a syntactic sugar for
f x y
-- Program 1 main = print (a ++ b ++ c) a = [((2**3) * 4)] b = [(2*3) + (4*5)] c = [2 + (3 * (4**5))] -- Program 2 main = print (n) n = (a `div` (length xs)) where a = 10 xs = [1 .. 5] -- Program 3 main = print (a [1 .. 5]) a xs = sum (drop (length xs - 1) (take (length xs) xs)) main = putStrLn "hello, world"
f :: A -> Band
e :: Athen,
f e :: B
[[’a’,’b’],[’c’,’d’,’e’]] :: [[Char]]
["One","Two","Three"] :: [String]
("Yes",True,’a’) :: (String,Bool,Char)
not :: Bool -> Booland
add :: (Int,Int) -> Int
length :: [a] -> Intand
zip :: [a] -> [b] -> [(a, b)]
(==) :: Eq a => a -> a -> Bool
<, >, min, maxwith
(<) :: Ord a => a -> a -> Bool
show :: a -> String
read :: String -> a
(+), (-), negate, abs, signumwith
(+) :: Num a => a -> a -> a
div :: Int a => a -> a -> aand
mod :: Int a => a -> a -> a, also Int and Integer types are instances of this class.
Let us now introduce some really cool implementation techniques in haskell with respect to defining functions.
-- Let's see an example even :: a -> Bool even n = (n `mod` 2 == 0) -- Conditional using "if else" signum n = if n > 0 then 1 else if n < 0 then -1 else 0 -- Conditional using "such that" signum n | n > 0 = 1 | n < 0 = -1 | otherwise = 0
-- Define functions using '_' len  = 0 len (_:xs) = 1 + len xs initials :: String -> String -> String initials firstname lastname = [f] ++ ". " ++ [l] ++ "." where (f:_) = firstname (l:_) = lastname -- Defining using '_' fundamentally test :: Int -> Int test 0 = 1 test 1 = 2 test _ = 0
\x -> x + 1
-- For example, add :: Int -> Int -> Int add x y = x + y -- and odds n = map f [0 .. n - 1] where f x = x * 2 + 1 -- can be written as add :: Int -> (Int -> Int) add = \x -> (\y -> x + y) -- and odds n = map (\x -> x * 2 + 1) [0 .. n - 1]
Let $x = f(a, b, c)$ then, we shall have the following.
Upon currying, this gets translated to the below expression.
This is because, $x = f(a, b, c)$ becomes $h = g(a), i = h(b), x = i(c)$ or if called in sequence $x = g(a)(b)(c)$.
fst :: (a, b) -> a zip :: [a] -> [b] -> [(a, b)] id :: a -> a take :: Int -> [a] -> [a] head :: [a] -> a
-- Operator Sections w = 1 + 2 -- is same as x = (+) 1 2 -- is same as y = (1+) 2 -- or z = (+2) 1
This is very useful to construct certain functions.
The idea is based on set construction from other sets.
xy = [(x, y) | x <- [1..3], y <- [x..3]] -- The above is an example of dependent generators. -- Definitions of x and y serve as generators. -- Check out the usability of .. operator. concat :: [[a]] -> [a] concat xss = [x | xs <- xss, x <- xs] -- Guards are possible for example as bellow. evens = [x | x <- [1..10], even x]
-- Example of a recursion zip :: [a] -> [b] -> [(a, b)] zip  _ =  zip _  =  zip (x:xs) (y:ys) = (x, y) : zip xs ys -- Append Definition (++) :: [a] -> [a] -> [a]  ++ ys = ys (x:xs) ++ ys = x : (xs ++ ys)
The following memoize function takes a function of type
Int -> a and returns a memoized version of the same function. The trick is to turn a function into a value because, in Haskell, functions are not memoized but values are.
import Data.Function (fix) memoize :: (Int -> a) -> (Int -> a) memoize f = (map f [0 ..] !!) fib :: (Int -> Integer) -> Int -> Integer fib f 0 = 0 fib f 1 = 1 fib f n = f (n - 1) + f (n - 2) fibMemo :: Int -> Integer fibMemo = fix (memoize . fib)
A function is called a higher order if it takes a function as an argument or returns a function as a result.
twice :: (a -> a) -> a -> a twice f x = f (f x)
-- Example map :: (a -> b) -> [a] -> [b] map f xs = [f x | x <- xs] -- Alternate map :: (a -> b) -> [a] -> [b] map f  =  map f (x:xs) = f x : map f xs
-- Example filter :: (a -> Bool) -> [a] -> [a] filter f xs = [x | x <- xs, f x] -- Alternatively filter f  =  filter f (x:xs) | f x = x : filter f xs | otherwise = filter f xs
A number of functions on lists can be defined using the following simple pattern of recursion.
f  = v f (x:xs) = x ⊕ f xs
Here $f$ maps the empty list to some value $v$ and any non-empty list to some function $⊕$ applied to its head and $f$ of its tail.
The higher-order library function foldr (fold-right) encapsulates this simple pattern of recursion with the function $ $$⊕$ and the value $v$ as arguments.
foldr :: (a -> b -> b) -> b -> [a] -> b foldr f v  = v foldr f v (x:xs) = f x (foldr f v xs)
-- Generic Examples sum = foldr (+) 0 product = foldr (*) 1 or = foldr (||) False and = foldr (&&) True -- Other examples length = foldr (\ _ n -> 1 + n) 0 reverse = foldr (\ x xs -> xs ++ [x])  (++ ys) = foldr (:) ys
(.) :: (b -> c) -> (a -> b) -> (a -> c) f . g = \x -> f (g x) odd :: Int -> Bool odd = not . even
all :: (a -> Bool) -> [a] -> Bool all f xs = and [f x | x <- xs] any :: (a -> Bool) -> [a] -> Bool any f xs = or [f x | x <- xs] takeWhile :: (a -> Bool) -> [a] -> [a] takeWhile f  =  takeWhile f (x:xs) | f x = x : takeWhile f xs | otherwise =  dropWhile :: (a -> Bool) -> [a] -> [a] dropWhile f  =  dropWhile f (x:xs) | f x = dropWhile f xs | otherwise = x:xs
Moreover, curried functions are higher-order functions that returns a function.
-- Let f = let x = 1; y = 2 in (x + y) -- Where f = x + y where x = 1; y = 1
type Pos = (Int, Int) type Trans = Pos -> Pos type Tree = (Int, [Tree])
A completely new type can be defined by specifying its values in context-free formulation.
data Bool = False | True
data Answer = Yes | No | Unknown answers :: [Answer] answers = [Yes, No, Unknown] flip :: Answer -> Answer flip Yes = No flip No = Yes flip Unknown = Unknown
Circle :: Float -> Shape Rect :: Float -> Float -> Shape data Shape = Circle Float | Rect Float Float square :: Float -> Shape square n = Rect n n area :: Shape -> Float area (Circle r) = pi * r^2 area (Rect x y) = x * y
data Maybe a = Nothing | Just a safediv :: Int -> Int -> Maybe Int safediv _ 0 = Nothing safediv m n = Just (m `div` n) safehead :: [a] -> Maybe a safehead  = Nothing safehead xs = Just (head xs)
This is basically a cool syntactic encapsulation to prevent crashing. This is used to often deal with exceptions and create failsafe programs.
data Nat = Zero | Succ Nat -- we have Zero :: Nat -- and Succ :: Nat -> Nat
data Expr = Val Int | Add Expr Expr | Mul Expr Expr eval :: Expr -> Int eval (Val n) = n eval (Add x y) = eval x + eval y eval (Mul x y) = eval x * eval y
This is a problem because Haskell is designed to have no side effects and thus only to create batch programs.
Interactive programs, on the other hand, necessarily require side effects.
IO Charis the type of actions that return a character.
IO ()is the type of purely side effecting actions that return no result value.
The standard library provides a number of actions including the following three primitives.
-- reads character from the keyboard -- and echoes it o the screen -- returning the character as the result value getChar :: IO Char -- takes a character as a input and writes it to the screen -- and returns no result value putChar :: Char -> IO () -- simply return value without performing any interaction -- this is basically a pure to impure conversion return :: a -> IO a
act :: IO (Char, Char) act = do x <- getChar getChar y <- getChar return (x, y)
getLine :: IO String getLine = do x <- getChar if x == '\n' then return  else do xs <- getLine return (x:xs)
putStr :: String -> IO () putStr  = return () putStr (x:xs) = do putChar x putStr xs
-- Just mentioned here so that -- one can try out problems with input import Control.Arrow ((>>>)) main :: IO () main = interact $ lines >>> head >>> read >>> solve >>> (++ "\n") solve :: Int -> String -- Type 2 import Control.Arrow ((>>>)) main :: IO () main = interact $ words >>> map read >>> solve >>> show >>> (++ "\n") solve :: [Integer] -> Integer
These are in-built.
putChar :: Char -> IO() putStr :: String -> IO () putStrLn :: String -> IO () print :: Show a => a -> IO () getChar :: IO Char getLine :: IO String getContents :: IO String interact :: (String -> String) -> IO () show :: Show a => a -> String read :: Read a => String -> a
main = do putStrLn "enter value for x: " input1 <- getLine putStrLn "enter value for y: " input2 <- getLine let x = (read input1 :: Int) let y = (read input2 :: Int) print (x + y)
Why is it important?
Haskell is very expressive language. It makes you think abstractly and forces to model and define the problem mathematically.
The main drawback is that it is hard to reason about efficiency.