REAL WORLD
λ Programming
Suraj Atreya
Glassbeam
Goal of this talk
Collections
Hashtable<String, String> flnames = new Hashtable<String, String>();
flnames.put("Bill", "Gates");
flnames.put("Steve", "Jobs");
flnames.put("John", "Doe");
Set<String> keys = flnames.keySet();
for(String key: keys){
System.out.println(key + "," + StringOps.getLastNameInitials(flnames.get(key)));
}
Steve,J
John,D
Bill,G
public class StringOps {
public static char getLastNameInitials(String lname){
return lname.charAt(0);
}
}
public class MathOps{
public ArrayList<Integer> multipleOf3(ArrayList<Integer> arr1){
ArrayList<Integer> result = new ArrayList<Integer>();
for(int i : arr1){
if(i % 3 == 0){
result.add(i);
}
}
return result;
}
}
ArrayList<Integer> alInts = new ArrayList<Integer>();
for (int i = 0; i < 100; i++){
alInts.add(i);
}
ArrayList<Integer> res = new MathOps().multipleOf3(alInts);
System.out.println(res);
//Output
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, ...]
public class MathOps{
public ArrayList<Integer> multipleOf5(ArrayList<Integer> arr1){
ArrayList<Integer> result = new ArrayList<Integer>();
for(int i : arr1){
if(i % 5 == 0){
result.add(i);
}
}
return result;
}
}
ArrayList<Integer> alInts = new ArrayList<Integer>();
for (int i = 0; i < 100; i++){
alInts.add(i);
}
ArrayList<Integer> res = new MathOps().multipleOf5(alInts);
System.out.println(res);
//Output
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, ...]
Hashtable<String, String> flnames = new Hashtable<String, String>();
flnames.put("Bill", "Gates");
flnames.put("Steve", "Jobs");
flnames.put("John", "Doe");
Set<String> keys = flnames.keySet();
for(String key: keys){
System.out.println(key + "," + StringOps.getLastNameInitials(flnames.get(key)));
}
scala> val ls = List(("Bill", "Gates"), ("Steve", "Jobs"), ("John", "Doe"))
ls: List[(String, String)] = List((Bill,Gates), (Steve,Jobs), (John,Doe))
scala> ls.map ( t => println(t._1 + "," + t._2(0)) )
Bill,G
Steve,J
John,D
public class StringOps {
public static char getLastNameInitials(String lname){
return lname.charAt(0);
}
}
scala> (1 to 100).toList.filter(x => x % 3 == 0)
public class MathOps{
public ArrayList<Integer> multipleOf3(ArrayList<Integer> arr1){
ArrayList<Integer> result = new ArrayList<Integer>();
for(int i : arr1){
if(i % 3 == 0){
result.add(i);
}
}
return result;
}
}
λ>filter (\x -> x `mod` 3 == 0) [1..100]
//Output
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, ...]
public class MathOps{
public ArrayList<Integer> multipleOf5(ArrayList<Integer> arr1){
ArrayList<Integer> result = new ArrayList<Integer>();
for(int i : arr1){
if(i % 5 == 0){
result.add(i);
}
}
return result;
}
}
scala> (1 to 100).toList.filter(x => x % 5 == 0)
λ>filter (\x -> x `mod` 5 == 0) [1..100]
//Output
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, ...]
But, what is Functional Programming anyway?
All this is funky and cool!
Functional Programming
- Programing with pure functions
- Functions are first class citizens
- No state (read Immutability)
- Referential transparency
object PureFPEx {
def strLength (str: String): Int = {
str.length
}
def findLength(f: String => Int, str : String): Int = {
f(str) + 1
}
def main(args: Array[String]): Unit = {
println(findLength(strLength, "hello"))
}
}
Pure Function
object PureFPEx {
def strLength (str: String): Int = {
str.length
}
def strLengthBy2(str: String): Int = {
str.length / 2
}
def findLength(f: String => Int, str : String): Int = {
f(str) + 1
}
def main(args: Array[String]): Unit = {
println(findLength(strLength, "hello"))
println(findLength(strLengthBy2, "hello"))
}
}
Pure Function
val x = “Hello, World”
x:java.lang.String = Hello, World
val r1 = x.reverse
r1:String = dlroW ,olleH
val r2 = x.reverse
r2:String = dlroW ,olleH
scala> val r1 = “Hello, World”.reverse
r1:String = dlroW ,olleH
scala> val r2 = “Hello, World”.reverse
r1:String = dlroW ,olleH
Substitute "x" with its value
Refential Transparency
- "x" is referentially transparent
- No side effects after substitution
Refential Transparency
val x = new StringBuilder(“Hello”)
x: java.lang.StringBuilder = Hello
val r1 = x.append(“, World”).toString
r1:java.lang.String = Hello, World
val r2 = x.append(“, World”).toString
r2:java.lang.String = Hello, World, World
- x is not referentially transparent
- After substitution, the output is different - “side effects”
def countPrimesImpure(lim: Int) = {
var count = 0
val l = (1 to lim).toList.par
l.map(x => if (isPrime(x)) count = count + 1)
count
}
//Calling code
countPrimesImpure(1000000)
State: Mutability
def countPrimesPure(lim: ParSeq[Int]) = {
lim.filter(isPrime).length
}
//Calling code
val s = countPrimesPure(Stream.from(1).takeWhile(p => p < 1000000).par)
println(s)
State: Immutability
- "count" is the source of problem
- holds state
- leads to race conditions - shared by threads
Mutability: not a good idea
Immutability: rocks!
- No state
- Implicit locking - translates to no mutexes
- Concurrency for free!
-
functor
-
applicative functors
-
monads
functor
λ>:t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
functor: map
map is an instance of functor typeclass
λ>:t map
map :: (a -> b) -> [a] -> [b]
λ>map (\x -> x + 1) [1,2,3]
[2,3,4]
scala> List(1,2,3) map (x => x + 1)
List[Int] = List(2, 3, 4)
applicative functor
-
applicative functor is also a functor
λ>:t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
λ>pure (*) <*> [1,2,3] <*> [4,5,6]
[4,5,6,8,10,12,12,15,18]
public ArrayList<Integer> carteseanProduct(ArrayList<Integer> arr1,
ArrayList<Integer> arr2) {
ArrayList<Integer> res = new ArrayList<Integer>();
for (Integer in1 : arr1) {
for (Integer in2 : arr2) {
res.add(in1 * in2);
}
}
return res;
}
ArrayList<Integer> l1 = new ArrayList<Integer>();
ArrayList<Integer> l2 = new ArrayList<Integer>();
l1.add(1);
l1.add(2);
l1.add(3);
l2.add(4);
l2.add(5);
l2.add(6);
System.out.println(new MathOps().carteseanProduct(l1, l2));
monads
- a lifetime isn't enough to learn about monads
- can find more articles on monads than the number of stars in the galaxy
- ALL OF THAT IS HYPE!
object Monads {
def square(ls: List[Int]) : List[Int] = {
ls.map(x => x * x)
}
def filterMultiple4(ls: List[Int]) : List[Int] = {
ls.filter(x => x % 4 == 0)
}
def divideBy2(ls: List[Int]): List[Int] = {
ls.map(x => x / 2)
}
def main(args: Array[String]): Unit = {
val myList = (1 to 100).toList
val aa = square(myList)
val bb = filterMultiple4(aa)
val cc = divideBy2(bb)
println(cc)
}
}
- square every element in the list
- pick only mutilples of 4 from step (1)
- divide by 2 every element from step (2)
Non-monadic
object Monads2 {
def square(ls: List[Int]): List[Int] = {
ls.map(x => x * x)
}
def filterMultiple4(ls: List[Int]): List[Int] = {
ls.filter(x => x % 4 == 0)
}
def divideBy2(ls: List[Int]): List[Int] = {
ls.map(x => x / 2)
}
def main(args: Array[String]): Unit = {
val transformed = for {
a <- Some(square(myList))
b <- Some(filterMultiple4(a))
c <- Some(divideBy2(b))
} yield c
println(transformed)
}
}
- square every element in the list
- pick only mutilples of 4 from step (1)
- divide by 2 every element from step (2)
monadic
REAL WORLD λ Programming
By surajatreya
REAL WORLD λ Programming
- 891