why do you want to know about functional programming?ats/talks/linq-ieee/linq-ieee.pdf · 04/23/07...
TRANSCRIPT
04/23/07 linq-
Why do you want to know about functional programming?
A look at LinQ in C# and (perhaps) Java
Axel T. SchreinerRIT — Computer Science
Eric Meijer
1
http://www.cs.rit.edu/~ats/talks/linq-ieee/http://www.cs.rit.edu/~ats/cs-2006-1/14_linq.pdf
04/23/07 linq-
Principles
Patterns
Examples
Implementation
Conclusions
2
cs-2006-1 10/30/06 linq-
Principles
Map a query language to cascading method calls.
Implement the necessary methods for IEnumerable, XML- and database-access.
Sugar syntax liberally.
3
cs-2006-1 10/30/06 linq-
What if...
Syntactic sugar patterned after SQL.
4
struct Person { string first, last; int phone; }IContainer<Person> staff = ...Console.WriteLine( from x in staff where x.phone % 2 == 0 orderby x.last select new { x.first, x.phone });
cs-2006-1 10/30/06 linq-
What if...
Syntactic sugar patterned after SQL.
Actions converted into messages,Expressions converted into functions.
5
struct Person { string first, last; int phone; }IContainer<Person> staff = ...Console.WriteLine( from x in staff where x.phone % 2 == 0 orderby x.last select new { x.first, x.phone });
cs-2006-1 10/30/06 linq-
What if...
Functional style [Eric Meijer]:
function as arguments,function composition for actions.
Anonymous class new { field ,... }.6
struct Person { string first, last; int phone; }IContainer<Person> staff = ...Console.WriteLine( staff .Where(x => x.phone % 2 == 0) .OrderBy(x => x.last) .Select(x => new { x.first, x.phone }));
➦
cs-2006-1 10/30/06 linq-
Typing
7
struct Person { string first, last; int phone; }IContainer<Person> staff = ...Console.WriteLine( staff .Where(x => x.phone % 2 == 0) .OrderBy(x => x.last) .Select(x => new { x.first, x.phone }));
class C<T> { delegate R Func<R, T> (T arg); C<T> Where (Func<bool, T> predicate); C<T> OrderBy<K> (Func<K, T> keySelector); C<U> Select<U> (Func<U, T> selector);}
cs-2006-1 10/30/06 linq-
Typing
8
class C<T> { delegate R Func<R, T> (T arg); C<T> Where (Func<bool, T> predicate); C<T> OrderBy<K> (Func<K, T> keySelector); C<U> Select<U> (Func<U, T> selector);}
struct Person { string first, last; int phone; }IContainer<Person> staff = ...Console.WriteLine( staff .Where(x => x.phone % 2 == 0) .OrderBy(x => x.last) .Select(x => new { x.first, x.phone }));
cs-2006-1 10/30/06 linq-
Typing
9
class C<T> { delegate R Func<R, T> (T arg); C<T> Where (Func<bool, T> predicate); C<T> OrderBy<K> (Func<K, T> keySelector); C<U> Select<U> (Func<U, T> selector);}
struct Person { string first, last; int phone; }IContainer<Person> staff = ...Console.WriteLine( staff .Where(x => x.phone % 2 == 0) .OrderBy(x => x.last) .Select(x => new { x.first, x.phone }));
cs-2006-1 10/30/06 linq-
Typing Pattern
10
class C<T> { delegate R Func<R, T> (T arg); C<T> Where (Func<bool, T> predicate); C<T> OrderBy<K> (Func<K, T> keySelector); C<U> Select<U> (Func<U, T> selector);}
struct Person { string first, last; int phone; }IContainer<Person> staff = ...Console.WriteLine( staff .Where(x => x.phone % 2 == 0) .OrderBy(x => x.last) .Select(x => new { x.first, x.phone }));
cs-2006-1 10/30/06 linq-
Query Expression Pattern
11
from join... introduce iteration variable(s)
fromlet ...where
introduces iteration variable(s)introduces variablefilters
orderby rearranges sequence
selectgroup by
produces flat resultproduces structured result
into join...
produces iteration variable(s) to start over
cs-2006-1 10/30/06 linq-
Query Class Pattern
12
from join...
class C<T> { C<V> Join (...) C<V> GroupJoin (...)
fromlet ...where
C<T> Where (...)
orderby
O<T> OrderBy[Descending] (...) class O<T> : C<T> { O<T>ThenBy[Descending] (...) }
selectgroup by
C<U> Select[Many] (...) C<G<Key,E>> GroupBy (...) class G<Key,E> : C<E> {...}
into join...
➦
04/23/07 linq-
Exampleshttp://www.cs.rit.edu/~ats/cs-2006-1/code/adt/query/
http://www.cs.rit.edu/~ats/talks/linq-ieee/linq/
13
cs-2006-1 10/30/06 linq-
from let where ... / Where
14
from x in xs where f
xs.Where(x => f)
retains only records satisfying a condition.
let x = e
defines name for value.
04/23/07 linq-
delegate R Func<R,A> (A a);
IEnumerable<T> Where<T> (IEnumerable<T> container, Func<bool,T> predicate) { foreach (var c in container) if (predicate(c)) yield return c;}
Implementation
15
04/23/07 linq-
public interface Func<R,A> { R f (A a); }public<T> Iterable<T> where (Iterable<T> container, Func<Boolean,T> predicate) { List<T> result = newList(); for (T c: container) if (predicate.f(c)) result.add(c); return result;}
delegate R Func<R,A> (A a);
IEnumerable<T> Where<T> (IEnumerable<T> container, Func<bool,T> predicate) { foreach (var c in container) if (predicate(c)) yield return c;}
Implementation
15
04/23/07 linq-
Lazy Evaluation
16
public<T> IterableImpl<T> where (final Func<Boolean,T> predicate) { return new IterableImpl<T>(this) { public Iterator<T> iterator () { return new IteratorImpl<T> () { final Iterator<T> c = delegate.iterator(); protected void getNext () { while (c.hasNext()) if (predicate.f(next = c.next())) { hasNext = true; return; } hasNext = false; eof = true;} };} };}
04/23/07 linq-
int[] xs = { 1, 2, 3, 4, 5 };
from x in xs where x % 2 == 0 select x
Where(xs, x => x % 2 == 0)
Use
17
04/23/07 linq-
List<Integer> xs = Arrays.asList(new Integer[]{ 1, 2, 3, 4, 5});where(xs, new Func<Boolean,Integer>() { public Boolean f (Integer x) { return x % 2 == 0; }})
int[] xs = { 1, 2, 3, 4, 5 };
from x in xs where x % 2 == 0 select x
Where(xs, x => x % 2 == 0)
Arrays are not Iterable.
Use
17
cs-2006-1 10/30/06 linq-
Sugar: Extension Methods
A static class can define (static) extension methods.
If the class is imported, the methods can be called as instance methods:
18
static class X { static R method (this A parm, ...) { ... }}
A a;a.method(...)
cs-2006-1 10/30/06 linq-
Sugar: Lambda Syntax
An anonymous method definition can be significantly simplified.
Parameter and result types can be inferred.
Proposed for Java 7.
19
parameter => expression(type parameter, ...) => { body }
cs-2006-1 10/30/06 linq-
select / Select
20
from x in xs select f
xs.Select(x => f)
creates new records.
04/23/07 linq-
delegate R Func<R,A> (A a);
IEnumerable<U> Select<U,T> (IEnumerable<T> container, Func<U,T> selector) { foreach (var c in container) yield return selector(c);}
Implementation
21
04/23/07 linq-
public interface Func<R,A> { R f (A a); }public<U,T> Iterable<U> select (Iterable<T> container, Func<U,T> selector) { List<U> result = newList(); for (T c: container) result.add(selector.f(c)); return result;
}
delegate R Func<R,A> (A a);
IEnumerable<U> Select<U,T> (IEnumerable<T> container, Func<U,T> selector) { foreach (var c in container) yield return selector(c);}
Implementation
21
04/23/07 linq-
Lazy Evaluation
22
public<U,T> IterableImpl<U> select (final Func<U,T> selector) { return new IterableImpl<U>(this) { public Iterator<U> iterator () { return new IteratorImpl<U> () { final Iterator<T> c = delegate.iterator(); protected void getNext () { if (hasNext = c.hasNext()) next = selector.f(c.next()); else eof = true;} };} };}
cs-2006-1 10/30/06 linq-
select / Select[Many]
23
from x in xs select f
xs.Select(x => f)
creates new records.
from x in xs from y in ys select f
xs.SelectMany(x => ys.Select(y => f))
creates new records — notice scoping.
04/23/07 linq-
delegate R Func<R,A> (A a);
IEnumerable<U> SelectMany<U,T> (IEnumerable<T> container, Func<IEnumerable<U>,T> selector) { foreach (var c in container) foreach (var u in selector(c)) yield return u;}
Implementation➦
24
04/23/07 linq-
public interface Func<R,A> { R f (A a); }public<U,T> Iterable<U> selectMany (Iterable<T> container, Func<Iterable<U>,T> selector) { List<U> result = newList(); for (T c: container) for (U u: selector.f(c)) result.add(u); return result;
}
delegate R Func<R,A> (A a);
IEnumerable<U> SelectMany<U,T> (IEnumerable<T> container, Func<IEnumerable<U>,T> selector) { foreach (var c in container) foreach (var u in selector(c)) yield return u;}
Implementation➦
24
04/23/07 linq-
int[] xs = { 1, 2, 3, 4, 5 };double[] ys = { 6.0, 7.0, 8.0, 9.0, 10.0 };
from x in xs where x > 3 from y in ys where y < 8.0 select new { y, x }
SelectMany(Where(xs, x => x > 3), x => Select(Where(ys, y => y < 8.0), y => new { y, x }))
Use
25
cs-2006-1 10/30/06 linq-
Sugar: Tuple Types
A type can be created on the fly.
It has a read/write property for each field (and ToString).
The field types (and names) are inferred.
26
new { name = expression, ... }
04/23/07 linq-
int[] xs = { 1, 2, 3, 4, 5 };double[] ys = { 6.0, 7.0, 8.0, 9.0, 10.0 };
from x in xs where x > 3 from y in ys where y < 8.0 select new { y, x }
SelectMany(Where(xs, x => x > 3), x => Select(Where(ys, y => y < 8.0), y => new { y, x }))
Review: Use
27
04/23/07 linq-28
List<Integer> xs = Arrays.asList(new Integer[]{ 1, 2, 3, 4, 5});final List<Double> ys = Arrays.asList(new Double[]{ 6.0, 7.0, 8.0, 9.0, 10.0 });
selectMany( where(xs, new Func<Boolean,Integer>() { public Boolean f (Integer x) { return x > 3; } }), new Func<Iterable<HashMap<String,Object>>,Integer>() { public Iterable<HashMap<String,Object>> f (final Integer x) { return select( where(ys, new Func<Boolean,Double>() { public Boolean f (Double y) { return y < 8.0; } }), new Func<HashMap<String,Object>,Double>() { public HashMap<String,Object> f (Double y) { HashMap<String,Object> result = new HashMap<String,Object>(); result.put("y", y); result.put("x", x); return result; } }); } })
cs-2006-1 10/30/06 linq-
orderby
29
e.OrderBy(x => f) // .ThenBy(x => g) ...
from x in e orderby f [ascending|descending] // , g ,...
defines sort key[s] and direction.
04/23/07 linq-
public<K extends Comparable<K>,T> Ordered<T> orderBy (Iterable<T> container, final Func<K,T> key) { // need a copied list for sorting List<T> values = newList(); for (T c: container) values.add(c);
return new Ordered<T>(values, new Comparator<T>() { public int compare (T a, T b) { return key.f(a).compareTo(key.f(b)); } } );}
Implementation:primary key
Comparator is composed from key
30
04/23/07 linq-31
public static class Ordered<T> extends Base<T> { protected final Comparator<T> order; protected boolean ordered; // true once sorted
public Ordered (List<T> values, Comparator<T> order) { super(values); this.order = order; }
public<K extends Comparable<K>> Ordered<T> thenBy (final Func<K,T> key) { // add to order return new Ordered<T>(super.getValues(), new Comparator<T>() { public int compare (T a, T b) { int c = order.compare(a, b); return c != 0 ? c : key.f(a).compareTo(key.f(b)); } } );}
next Comparator is composed from order and key
Implementation:secondary keys
04/23/07 linq-32
protected static class Base<T> extends AbstractList<T> { private final List<T> values; protected List<T> getValues () { return values; }
public Base (List<T> values) { this.values = values; }
public void add (int index, T element) { getValues().add(index, element); } // ...
protected List<T> getValues () { // use order List<T> values = super.getValues(); if (!ordered) { Collections.sort(values, order); ordered = true; } return values; }
Implementation:sort
get, remove, set, and size are also delegated; any use of values can be overridden:
04/23/07 linq-
Use
sorts in dictionary order
33
public static void main (String... _args) { List<String> args = Arrays.asList(_args); orderBy(args, new Func<String,String>() { // s => s.toLowerCase public String f (String s) { return s.toLowerCase(); }}) .thenBy(new Func<String,String>() { // s => s public String f (String s) { return s; } })
04/23/07 linq-
joincomputes for pairs: inner record with same key as outer record
group-joincomputes for group of inner records with same key as outer record
group bygroups values computed from elements with equal key values
34
etc.➦
cs-2006-1 10/30/06 linq-
from join...
35
from x in e join y in f on g equals h into i // ... z
e.GroupJoin(f, x => g, y => h, (x,i) => z)
defines anonymous iteration over groups.
from x in e join y in f on g equals h // ... z
e.Join(f, x => g, y => h, (x,y) => z)
defines anonymous iteration over pairs.
from x in e
defines iteration variable.
cs-2006-1 10/30/06 linq-
Join
36
delegate R F<R,A> (A a);delegate R F<R,A,B> (A a, B b);
C<V> Join<U,K,V,T> (C<U> inner, F<K,T> outerKey, F<K,U> innerKey, F<V,T,U> selector) { var result = new C<V>(); foreach (var t in this) // from's container foreach (var i in inner) if (outerKey(t).Equals(innerKey(i))) result.Add(selector(t, i)); return result;}
selector combines records with matching keys.
cs-2006-1 10/30/06 linq-
GroupJoin
37
C<V> GroupJoin<U,K,V,T> (C<U> inner, F<K,T> outerKey, F<K,U> innerKey, F<V,T,C<U>> selector) { var result = new C<V>(); foreach (var t in this) { var group = new C<U>(); foreach (var i in inner) if (outerKey(t).Equals(innerKey(i))) group.Add(i); result.Add(selector(t, group)); } return result;}
selector combines outer record with group of inner records and matching keys.
cs-2006-1 10/30/06 linq-
group by
38
from x in e group x by g
e.GroupBy(x => g)
groups elements by key value.
from x in e group f by g
e.GroupBy(x => g, x => f)
groups new values by key value.
cs-2006-1 10/30/06 linq-
GroupBy
39
C<Group<K,T>> GroupBy<K,T> (F<K,T> key) { return GroupBy(key, (F<T,T>)delegate (T t) { return t; });}
C<Group<K,E>> GroupBy<K,E,T> (F<K,T> key, F<E,T> selector) { var dictionary = new Dictionary<K,Group<K,E>>(); var result = new C<Group<K,E>>(); foreach (var t in this) { var k = key(t); Group<K,E> group; try { group = dictionary[k]; } catch { group = new Group<K,E>(k); result.Add(group); dictionary[k] = group; } group.Add(selector(t)); } return result; }}
cs-2006-1 10/30/06 linq-
Group
40
class Group<K,T> : C<T> { readonly K key;
public Group (K key) { this.key = key; }
public K Key { get { return key; } }}
Group preserves the common key value.
04/23/07 linq-
Think functional!
A computer scientist invents this...
Action sequence: compositionCondition/selection: lambdas as argumentsNested selections: application of lambda Sorting: compose Comparator based on lambda arguments
No chance to see this in Java [56]...
41
04/23/07 linq-
Think functional!
A computer scientist invents this...
Action sequence: composition, lazy evaluationCondition/selection: lambdas as argumentsNested selections: application of lambda Sorting: compose Comparator based on lambda arguments
No chance to see this in Java [56]...
42
04/23/07 linq-
Think functional!
A computer scientist invents this...
Action sequence: composition, lazy evaluationCondition/selection: lambdas as argumentsNested selections: application of lambda Sorting: compose Comparator based on lambda arguments
No chance to see this in Java [56]...
43
04/23/07 linq-
Think functional!
A computer scientist invents this...
Action sequence: composition, lazy evaluationCondition/selection: lambdas as argumentsNested selections: application of lambda Sorting: compose Comparator based on lambda arguments
No chance to see this in Java [56]...
44
04/23/07 linq-
Think functional!
A computer scientist invents this...
Action sequence: composition, lazy evaluationCondition/selection: lambdas as argumentsNested selections: application of lambda Sorting: compose Comparator based on lambda arguments
No chance to see this in Java [56]...
45
04/23/07 linq-
Think functional!
A computer scientist invents this...
Action sequence: compositionCondition/selection: lambdas as argumentsNested selections: application of lambda Sorting: compose Comparator based on lambda arguments
No chance to see this in Java [56]...
46
04/23/07 linq-
References
Erik Meijerhttp://research.microsoft.com/~emeijer/
C#: LinQhttp://msdn.microsoft.com/netframework/future/linq/
C# 3.0http://msdn2.microsoft.com/en-us/vcsharp/aa336745.aspx
Java 7: Closureshttp://www.javac.info/closures-v03.html
47