Functional Programming
Mechanisms for Defining Functions
1. Conditional Expressions 2. Guarded Equations 3. Pattern Matching 4. Lambda Expressions 5. Sections
Higher-Order Functions
In FP, functions are ____, meaning they can be arguments of other functions. Usefulness of ____: 1. Common Programming idioms can be encoded as functions within the language itself. 2. Domain specific language can be defined as collections of ____. 3. Algebraic properties of ____ can be used to reason about programs. Example: The function called map is ____ as it applies a function to every element of a list. map f xs = [f x | x <- xs] > map (+1) [1, 3, 5, 7] [2, 4, 6, 8]
Type Constraints
This tell us if functions are being used correctly. Any indication that it is or isn't is caught at compile time (which is before the program is used). When you apply an argument of the wrong type, this causes a Type Error! E.g. 1 + False
Types
Understanding this aspect of a function gives us information on how to use it, such as what the input and output, which in turn tell us the constraints of the function.
Mutual Recursion
____ is a form of recursion where two functions are defined in terms of each other. E.g. even :: Int -> Bool even 0 = True even n = odd(n - 1) odd :: Int -> Bool odd 0 = False odd n = even (n - 1)
Functional Programming provides a framework for these goals:
- Programs to be written Concisely - Support Reusable Software Components - Encourage the use of formal verification - Permit Rapid Prototyping - Provide Powerful Problem Solving Tools - Enable Easy Parallel Processing
Some Features of Haskell
1. Types to enforce constraints (and avoid incompatibility errors) 2. Automatic Type inference 3. Polymorphic types and overloading 4. List comprehension, Recursion, Higher-order functions, Lazy Evaluation
Type Variable
> :type head head :: [a] -> a The head function returns the first element of a list, but what is the type of a? When writing types, shouldn't you put explicit types like identifierName :: [Char] -> [Char]? Remember that types are written in capital case, so it can't exactly be a type. Because it's not in capital case it's actually a ______ That means that a can be of any type. These can have names longer than one character, but we usually give them names of a, b, c, d ...
Data Declaration
A completely new type can be defined by specifying its values using a ____. data Bool = False | True Bool is the identifier. False | True are the constructors. Bool is a new data type, with two new values False and True. The two values False and True are called the constructors for the type Bool. Type and constructor names must begin with an upper-case letter. Data declarations are similar to context free grammars. Derived Classes For the elements of a new type to be legally used in standard operations, as in printed, Haskell uses the derived class: data Bool = False | True deriving (Show, Eq) This allows values of type Bool to be "Shown" and "compared by ==". The value of new types can be used the same way as built in types. The Constructors in a ____ can also have parameters. E.g. data Shape = Circle Float | Rect Float Float ____ can also have parameters: data Maybe a = Nothing | Just a New types can be declared recursively. E.g. data Nat = Zero | Succ Nat Nat is a new data type, with constructors Zero :: Nat and Succ :: Nat -> Nat. The value of type Nat is either Zero, or of the form Succ n where n :: Nat. That is, Nat contains the following infinite sequence of values: Zero Succ Zero Succ (Succ Zero) ... We can think of values of type Nat as natural numbers, where zero represents 0, and succ represents the successor function 1+ E.g. Succ (Succ (Succ Zero)) means this: 1 + (1 + (1 + 0)) = 3 Let's look at this, building data types, in another way. Consider a simple form of expressions built up from integers using addition and multiplication. + / \ 1 * / \ 2 3 Using recursion, a suitable new type to represent such expressions can be declared by: data Expr = Val Int | Add Expr Expr | Mul Expr Expr for example, the expression on the previous slide would be represented as: Add(Val 1) (Mul (Val 2) (Val 3)) Now let's define a function to use this data type and process expressions. size :: Expr -> Int size (Val n) = 1 size (Add x y) = size x + size y size (Mul x y) = size x + size y Binary Trees The point of that was to show that it is too often useful to store data in a two-way branching structure or binary tree. 5 / \ 3 7 / \ / \ 1 4 6 9 Using recursion, a new type to represent such binary trees can be declared by: Data Tree = Leaf Int | Node Tree Int Tree The above tree could be represented as: Node (Node (Leaf 1) 3 (Leaf 4)) 5 (Node (Leaf 6) 7 (Leaf 9) Let's try to define a function that decides if a given integer occurs in a binary tree. occurs :: Int -> Tree -> Bool occurs m (Leaf n) = m == n occurs m (Node l n r) = m == n || occurs m l || occurs m r
Foldr Function
A number of functions with list arguments can be defined using the following simple pattern of recursion. The ____ is built like this: f[] = v f(x:xs) = x (x) f xs f maps the empty list to some value v, and any non-empty list to some function (x) applied to its head and f of its tail. Examples of using this PATTERN in building other functions: sum[] = 0 sum (x:xs) = x + sum xs See? It's the same build as the actual foldr function, but its used to build a sum function. This is a recursive function that works on lists. Pretty neat, huh. Let's break it down more. in sum, v = 0. This is because it is the base of the function, it's where the values in the list should 'start' and not go below. The v part is called the base case. Also, the (+) part was the + operator. This is the operator/function you want to apply to every value in the list. Let's take a look at the product function: product [] = 1 product (x:xs) = x * product xs Here, v = 1 and (x) = *. product [] is the base case. It is easy to see why it exists by working through an evaluation of the function. product [5, 4, 8] 5 * product [4, 8] 5 * 4 * product [8] 5 * 4 * 8 * product [] 5 * 4 * 8 * 1 160 If the base case did not exist, product [] would not be able to evaluate to anything. 1 is the identity for multiplication, just as 0 is the identity for addition, i.e. 1 times any number is always that number, just as 0 plus any number is that number. Besides just using the foldr pattern, the actual function encapsulates this pattern of recursion with (+) and v as arguments: for example, sum could be > foldr(+) 0 or product could be >foldr(*) 1 Why is foldr useful? 1. Some recursive functions on lists, such as sum, are simpler to define using foldr. 2. Properties of functions defined using foldr can be proved using algebraic properties of foldr, such as fusion and the banana split rule. 3. Advance program optimisations can be simpler if foldr is used in place of explicit recursion.
String Comprehensions
A string is a sequence of characters enclosed in double quotes. Internally, they are just lists of characters. "abc" :: String means ['a', 'b', 'c'] :: [Char] Because strings are just special kinds of lists, any polymorphic function that operates on lists can also be applied to strings. > length "abcde" 5 > zip "abc" [1, 2, 3] [('a', 1), ('b', 2), ('c', 3)] Back to the topic of List Comprehensions, they can also be used to define functions on Strings, such as a function that counts the lower-case letters in a string: lowers :: String -> Int lowers xs = length [x | x <- xs, isLower x] Where isLower :: Char -> Bool returns True for lower-case characters and False otherwise. >lowers "Haskell" 6
Zip Function
A useful library function is ____, which maps two lists to a list of pairs of their corresponding elements. zip :: [a] -> [b] -> [(a, b)] E.g. >zip ['a', 'b', 'c'] [1, 2, 3, 4] [('a', 1), ('b', 2), ('c', 3)]
Wild-Cards
Another common situation is pattern matching against a value we really care nothing about. For example, the functions head and tail can be rewritten as: head (x:_) = x tail (_:xs) = xs The underscore, '_', is a ____ pattern that matches any argument value.
::
Can be read as 'is of type'
Classes in Scala
Classes in ____ are defined as follows: Class Complex (read: Double, imag: Double, imag: Double) { def re = real def im = imag } Classes in ____ are very much like java classes. The difference is that classes have parameters which are used to form the primary constructor. Let's write the class again but this time with a method. Class Complex (read: Double, imag: Double, imag: Double) { def re = real def im = imag override def toString = re + (if(im<0.0) "" else "+") + im + "I" } Methods must override the parent method. In scala, to use this class and subsequently its method, you would have to type the following: Scala > :load Complex.scala loading... scala> val x = new complex (1, -3) x: Complex = 1.0 - 3.0; scala> x.toString res0: Java.lang.String = 1.0 - 3.0i See, quite similar to Java!? Also keep in mind that classes extent class AnyRef by default.
List Patterns
Every list is constructed by repeated use of an operator (:) called 'cons' that adds an element to the start of a list. [1, 2, 3, 4] means 1:(2:(3:(4:[]))) Functions with list arguments can be defined using x:xs patterns. head :: [a] -> a head (x:_) = x tail :: [a] -> [tail] tail (_:xs) = xs head and tail map any non-empty list to its first and remaining elements, respectively. x:xs patterns only match non-empty lists. E.g. > head[] > Error
Conventions
Function and Argument names must begin with a lower-case letter. List arguments usually have an s suffix on their names: xs ns nss xs as in plural of x and xss as in plural of xs: x :: a (one thing) xs :: [a] (many things) xss :: [[a]] (many of many things) So pronounce them: x, x's, x's's
Lambda Expressions
Functions can be constructed without naming them by using ____. E.g. \x -> x + x This nameless function takes a number x and returns the result of x+x. The '\' represents the ____. Why use ____'s? Put it simply, many Haskell functions are "Higher Order functions", i.e. they expect other functions as parameters. Often, the functions we want to pass to such higher order functions are used only once in the program, at that particular point. It's simply more convenient then to use a ____ than to define a new local function for that purpose. They are used to give a formal meaning to functions defined using currying. ____ can be used to avoid naming functions that are only referenced once. e.g. adds n = map f [0 .. n - 1] where f x = x * 2 + 1 simplified to: adds n = map (\x -> x * 2 + 1)[0 .. n - 1]
Curried Functions
Functions that take their arguments one at a time are called ____. Functions with more than two arguments can be ____ by returning nested functions. E.g. mult :: Int -> (Int -> (Int -> (Int -> Int)) mult x y z = x ** y ** z Mult takes an integer x and returns a function mult x, which in turn takes an integer y and returns a function mult xy, which finally takes an integer z and returns the result x * y * z. Ultimately, a ____ is the process of applying a function to its arguments in order to produce a return value. Why ___? ____ are more convenient because it allows partial application. Partial application involves passing less than the full number of arguments to a function that takes multiple arguments.
The difference Between Imperative Languages and Functional Programming Languages
Imperative: - Computation is done by 'updates' through variable assignments. - Sequence of Instructions - Computation by Instruction Execution - Iteration - Modifiable/Updatable/Mutable Variables - Control Structures (if-then-else, loops, etc) - Instruction sequences for a Von Neumann Computer. The problem is: how to scale up? Functional: - Computation is done by function application. Programming without Mutable variables, assignments, loops, and other imperative control structures. - A collection of function Definitions - Computation by term rewriting - Recursion - Constants
Object Equality in Scala
In Scala, you can use == to compare objects' convents. This is different from Java (because of what the definition of an object is). E.g. > 1==2 (numbers are objects) res0: Boolean = false > List (1, 2) == List (1, 2) res1: Boolean = True > 1 == 1.0 (objects of diff types) res2: Boolean = True > ("he"+"llo") == "hello" res3: Boolean = True Compared with Java: == in scala compares content equality == in java compares reference/pointer equality. In scala, only Eq compares reference/pointer equality. But for real... for primitive types such as Int or String, == is the same as Java. Its not so complicated. Just remember, for objects, == in scala has been carefully crafted. Just take a look at examples res1 and res3 above!
Type Declarations
Is Haskell, a new name for an existing type can be defined using a ____. type String = [Char] In this example case, we've given a new name for a list of Char, as String. String is the identifier. [Char] is the existing type. Like function definitions, ____ can also have parameters. E.g. type Pair a = (a, a) So we can define: mult :: Pair Int -> Int mutl (m, n) = m * n copy :: a -> Pair a copy x = (x, x) ____ can be nested in other ____: type Pos = (Int, Int) type Trans = Pos -> Pos But they cannot be recursive: type Tree = (Int, [Tree]) would not work!
Scala Notation
Let's get into the notation of ____. First of all, 1. Class-based 2. Single Inheritance (means inheritance of properties and behaviour is possible) Now, for writing in ____. use 'var' to declare variables in scala. var x = 3; x += 4; Notice that there isn't any type info? Remember, it is statically typed therefore there is type inference. so var x = 3; x = "hello world" CAUSES AN ERROR type annotations: var x : Int = 3; Let's define hello world in scala: object HelloWorld { def main (args: Array[String]){ println("Hello World!") } } Breaking the above down, there is a single object named HelloWorld. The Main method was defined. A parameter args of type Array[String] was defined. FYI, an Array is a generic class with a type parameter. Running this on the scala interpreter would be: >Scala Welcome scala> 1+2 res0: Int = 3 Let's move on. Numbers are objects in scala. Consider the expression: 1+2+3/x Operators are method calls. Operator symbols are identifiers. Meaning, the expression above is the same as (1).+(((2).*(3))./(x))
Multiparadigm Programming
Let's review some paradigms; we've already spoken about a couple: Imperative and Functional. What is a ____ language? 1. a ____ language is a language with multiple programming paradigms. 2. It allows for programming in a variety of styles, freely intermixing constructs with different paradigms. 3. It also makes for better productivity as people can program in the same language but know different ones. However, one thing that is unclear is the theoretical foundation to it. Did you know that the number of languages you know shows far better expertise than how long you program for! The goal of ____: To provide a number of different problem solving styles so that a programmer can select a solution that best matches the characteristics of a problem. Why do people want to use functional programming in imperative programming? Because it provides a good method of exploiting parallelism.
Lazy Evaluation
Lets move onto the topic of ____. How are expressions evaluated? 1. Successively expanding definitions (or doing B-reduction) by evaluating / reducing redexes (reducible expressions) 2. Until no further simplification is possible Evaluation Order There are different orders in evaluation! In "well-behaving", or pure, functional programming languages like Haskell, any two different reductions of the same expression end with the same result no matter which order it was evaluated. E.g. square n = n * n square (3+4) can be evaluated using the following sequence of reductions: square (3+4) = square 7 = 7 * 7 = 49 But this is possible to: square (3+4) = (3+4) * (3+4) = 7 * (3+4) = 7 * 7 = 49 The church-rosser property in 1936 stated: The end result of evaluating an expression is independent on the evaluation order. The point is to understand how Haskell uses reduction strategies which is how Haskell evaluates expressions. Ok, we now know there are more than one ways to reduce expressions. How does Haskell decided which to reduce? There are two common strategies: 1. Innermost Reduction: Always selecting an innermost redex to reduce. Call by Value. 2. Outermost Reduction: Always selecting an outermost redex to reduce. Call by Name. Ultimately, the number of reduction steps = efficiency in evaluation. Sometimes, the innermost reduction can be more efficient. e.g. square (3+4) -> 3+4 is evaluated twice in outermost but only once in innermost. To fix this outermost efficiency issue, we use something called 'sharing'. Sharing: this is the use of pointers to indicate sharing of expressions during evaluation. square (3+4) = . * . (where . is 3+4) = . * . (whose . is 7) = 49 ____ = outermost reduction + sharing. ____ does not require more reduction steps than the innermost evaluation. Haskell uses ____. Using ____, expressions are only evaluated as much as required to produce the final result. In haskell, lambda expressions are viewed as values (normal forms - not to be further evaluated) Make sure you know WHY ^ ____ in pure FP matters.
Sections
Like partial application and lambda abstraction, ____ provides a convenient way of writing some functions without having to explicitly name them. An operator written between its two arguments can be converted into a curried function written before its two arguments by using parenthesis. > 1 + 2 3 > (-) 2 1 1 This allows one of the arguments of the operature to be included in the parenthesis. E.g. >(1+) 2 3 > (+2) 1 3 In general, if a (+) is an operator then functions of the form ((+)), (x(+)) and ((+)y) are called ____. E.g. (1+) - successor function (*2) - doubling function (/2) - halving function
Guards
List Comprehensions can use ____ to restrict the values produced by earlier generators. > [x | x <- [1 .. 10], even x] [2, 4, 6, 8, 10] In this case, 'even' was the ____. This can be read as, "The list of all x such that x is an element of the list [1 .. 10] and x is even." In practice, using a ____ we can define a function that maps a positive integer to its list of factors: factors :: Int -> [Int] factors n = [x | x <- [1..n], n 'mod' x == 0] >factors 15 [1, 3, 5, 15] Now let's build a function that decides whether a number is prime or not using the factors function above. We use the factor function because a prime is an integer greater than one whose factors are only 1 and itself: prime :: Int -> Bool prime n = factors n == [1, n] Okay, let's now make a function that uses a guard to return the list of all primes up to a number! primes :: Int -> [Int] primes n = [x | x <- [2 .. n], prime x] The above functions would be great for examples on guards, list comprehension, and polymorphism! You should remember it!
List Comprehension in Scala
List comprehension in ____ is called sequence comprehension. In Haskell, e.g, [x * x | x <- [1 .. 3]] in scala, e.g, for (x <- List.range(1, 4)) yield x*x res6: List[Int] = List (1, 49) We can also have nested & Dependant generators: scala > for (x <- List.range(1, 2)) yield for (y <- List.range (x, 4)) yield (x, y) res7: List[List[(Int, Int)]] = List (List ((1, 1), (1, 2), (1, 3)))
Polymorphic Functions
Literally meaning, "Of many forms", a function is considered ____ if its type contains one or more types. length :: [a] -> Int Length takes a list of values and returns an integer. A ____ function is overloaded if its type contains one or more class constraints. >sum :: Num a => [a] -> a Conventionally, a class constraint is usually named 'C' and a type variable is usually 'a'. Class constraints are also called type classes!
Pattern Matching
Many functions have a particularly clear definition using ____ on their arguments. In ____, we attempt to match values against patterns and, if so desired, bind variables to successful matches. not :: Bool -> Bool not False = True not True = False Another example: map _ [] = [] map f (x:xs) = f x : map f xs At surface level, there are four different patterns involved, two per equation. - f is a pattern which matches anything at all, and binds the f variable to whatever is matched. - (x:xs) is a pattern that matches a non-empty list which is formed by something (which gets bound to the x variable) which was cons'd (by the (:) function) onto something else (which gets bound to xs). - [] is a pattern that matches the empty list. It doesn't bind any variables. - _ is the pattern which matches anything without binding (wildcard, "don't care" pattern). In the (x:xs) pattern, x and xs can be seen as sub-patterns used to match the parts of the list. Just like f, they match anything - though it is evident that if there is a successful match and x has type a, xs will have type [a]. Finally, these considerations imply that xs will also match an empty list, and so a one-element list matches (x:xs). From the above dissection, we can say pattern matching gives us a way to: - Recognize values. For instance, when map is called and the second argument matches [] the first equation for map is used instead of the second one. - Bind variables to the recognized values. In this case, the variables f, x, and xs are assigned to the values passed as arguments to map when the second equation is used, and so we can use these values through the variables in the right-hand side of =. As _ and [] show, binding is not an essential part of pattern matching, but just a side effect of using variable names as patterns. - Break down values into parts, as the (x:xs) pattern does by binding two variables to parts (head and tail) of a matched argument (the non-empty list).
Conditional Expressions
Similar to defining methods/functions in other languages, we use ____. E.g. abs :: Int -> Int abs n = if n > 0 then n else -n (In Haskell always include an else branch!) You can use nesting as well. signum :: Int -> Int signum n = if n < 0 then -1 else if n ==0 then 0 else 1
Guarded Equations
Similarly to conditional Expressions, we can use ____. E.g. abs n | n > 0 = n | otherwise = -n Where | is read as "such that", and otherwise is not necessarily there but it provides a convenient way of handling "all other cases". This is similar to the switch statement in Java! Another example: signum n | n < 0 = -1 | n == 0 = 0 | otherwise = 1
Filter Function
The higher-order library function ____, selects every element from a list that satisfied a predicate. >filter even [1 .. 10] [2, 4, 6, 8, 10] filter p xs = [x | x <- xs, p x]
all and any Functions
The library function ____ decides if every element of a list satisfies a given predicate. E.g. >all even [2, 4] True all :: (a -> Bool) -> [a] -> Bool all p xs = and [ p x | x <- xs ] The library function ____ decides if at least one element of a list satisfies a predicate. > any isSpace "abc def" True any :: (a -> Bool) -> [a] -> Bool any p xs = or [p x | x <- xs]
(.) Function
The library function ____ returns the composition of two functions as a single function. E.g. odd :: Int -> Bool odd = not . even
Type Classes
This is a collection of Types. In other words, it is a sort of interface that defines some behavior. If a type is a part of a _____, that means that it supports and implements the behavior the _____ describes. For example: What's the type signature of the == (Eq) function? > :type (==) (==) :: (Eq a) => a -> a -> Bool Interesting. We see a new thing here, the => symbol. Everything before the => symbol is called a class constraint. We can read the previous type declaration like this: the equality function takes any two values that are of the same type and returns a Bool. The type of those two values must be a member of the Eq class (this was the class constraint). This all just means that Eq is a ____ because it provides an interface for testing for equality. ____ provide an interface to define a behaviour. ____ is sometimes synonymous with class constraints. In action: > 5 == 5 True > 5 /= 5 False Other members of the Eq ____ are '==' or '/='. Another example of a ____ is Ord, whose members are >, <, >=, <=. Integral is also a numeric ____. Num includes all numbers, including real numbers and integral numbers, Integral includes only integral (whole) numbers. In this ____ are Int and Integer. Floating includes only floating point numbers, so Float and Double.
Tuple
This is a sequence of values of different types.
Polymorphic Functions
This is the name you'd call functions that have type variables.
Type Inference
Variables don't need explicit statements about their type unlike in Java. Haskell can automatically tell that 1 is of type Int.
List Comprehensions
____ helps us in the topic of building functions with list arguments. In mathematics, ____ is called set comprehension. You may recognise it as: {x^2 | x E {1 ... 5}} In Haskell, it would be ____, e.g. > [x^2 | x <- [1 .. 3]] [1, 4, 9] Where x <- [1 .. 3] is called a generator (used to say how the values of x are generated). Lets see how ____ are used to define functions with list arguments. ____ can have multiple generators, separated by commas > [(x, y) | x <- [1, 2, 3], y <- [4, 5]] [(1, 4), (1, 5), (2, 4), (2, 5), (3, 4), (3, 5)] Dependent Generators Later generators can DEPEND on the variables that are introduced by earlier generators. > [(x, y) | x <- [1 .. 3], y <- [x .. 3]] [(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)] Using a dependant generator, we can define the concat function that concatenates a list of lists: myconcat :: [[a]] -> [a] myconcat xss = [x | xs <- xss, x <- xs] Remember, this list comprehension can be read like this: [element | list <- listOfLists, element <- list] "myconcat exeses is the list of ex where exes are drawn from exeses and then ex is drawn from exes" Again, In list comprehensions, read x <- xs as 'items in collection xs may be thought of as item x' So: [ x | x <- xs , xs <- xss] Reads: "Show me a list of all x, where x may be thought of as an item in the list xs, where xs may be thought of as an item in the list xss" > concat [[1, 2, 3], [4, 5], [6]] [1, 2, 3, 4, 5, 6] Let's recap. [(x, y) | x <- [1, 2, 3], y <- [4, 5]] This is a ____. It is building a list The last part x <- [1, 2, 3], y <- [4, 5] are called generators. These organise how the list is built.
Scala
____ is a language where there is a combination of imperative and functional programming paradigms. ____ is object oriented. 1. It is a pure object oriented language in that every value is an object. 2. Types and behaviours of objects are described by classes, which are extended by subclassing ("subtyping"). ____ is functional (In the "wider" sense) 1. Every function is a value 2. It supports anonymous functions, higher-order functions, and pattern matching. 1. In general ____ supports generic classes and polymorphic methods. 2. It is statically typed, meaning it enforces type checking (enforcing type constraints) at compile time rather than run time. 3. It is extensible (can be expanded in terms of library functions). ____ is compatible with Java!!!! This means it executes on the java platform and integrates with java. Why ____? 1. It runs on a java virtual machine. Can use any java code in ____. It is almost as fast as Java as well! 2. Code is much shorter than Java. up to 50% less. There is also type inference. 3. Fewer errors 4. Flexibility (operation overloading for example) How would you Compare Scala with Haskell? 1. Haskell classes vs the module mechanisms in Scala 2. Higher-order functions in FP vs objects in OOP. (dynamic dispatch methods is analogous to calls to higher-order functions - can we implement one concept in terms of the other?)
Recursive Functions
____ is the basic looping mechanism in functional Programming. E.g. factorial :: Int -> Int factorial 0 == 1 factorial n = n * factorial (n - 1) as you can see in the last line, the factorial (n - 1) is calling the factorial function again, but this time n-1 is decreasing the argument number (thus getting finishing at factorial 0, which == 1.) Why is ____ useful? Many functions can naturally be defined by ____. Properties of functions defined using ____ can be proved using the simple, but powerful, technique of induction. ____ on Lists ____ is not restricted to numbers, but can also be used to define functions on lists. product :: [Int] -> Int product [] = 1 product (n:ns) = n * product ns Product maps the empty list to 1, and any non-empty list to its head multiplied by the product of its tail.
qsort Function
qsort :: [Int] -> [Int] qsort [] = [] qsort (x:xs) = qsort smaller ++ [x] ++ qsort larger where smaller = [ a | a <- xs, a <_ x] larger = [ b | b <- xs, b > x] Remember, ____ is an algorithm that uses pivots to organise lists.
Function Definition in Scala
scala > def sum (xs: List[Int]): Int = xs match { case Nil => 0 case x :: ys => x + Sum (ys) sum: (xs: List[Int]) Int As you can see, this is an example of a recursive function in scala. In haskell, it would be: sum [] = 0 sum (x:xs) = x + sum xs Scala functions are: 1. First Class 2. Can be partially applied 3. Can be higher Order A programming language is said to have first-class functions when functions in that language are treated ike any other variable. For example: in such a language, a function can be passed as an argument to other functions, can be returned by another function and can be assigned as a value to a variable. Polymorphic function in scala: for a recursive function, see the sum function above. For a polymorphic function, see this example! def length [T] (xs: List[T] Int scala > length (List (1, 2, 3)) res3: Int = 3 Pattern Matching in Scala: def reverse [T] (xs: List[T]) : List [T] = xs match { case Nil => Nil case x :: xy => reverse (ys) ::: List (x) } In haskell, the above would be: reverse :: [a] -> [a] reverse [] = [] reverse (x:xs) = reverse xs ++ [x] Another example of a pattern match: Pair-Patterns: Haskell: True && True = True _ && _ = False in Scala: def AND (x: Boolean, y: Boolean) : Boolean = (x, y) match { case (true, true) => true case (_, _) => False }