Skip to content

Commit 556181d

Browse files
committed
moved files in the wrong chapter, and fixed ch4 exercises
1 parent 91c3296 commit 556181d

File tree

4 files changed

+39
-90
lines changed

4 files changed

+39
-90
lines changed
File renamed without changes.
File renamed without changes.

Exercises/Chapter04/Exercises.cs

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,52 +5,32 @@
55

66
namespace Exercises.Chapter4
77
{
8-
class Exercises
8+
static class Exercises
99
{
10-
// 1. Without looking at any code or documentation (or intllisense), write the function signatures of
11-
// `OrderByDescending`, `Take` and `Average`, which we used to implement `AverageEarningsOfRichestQuartile`:
12-
decimal AverageEarningsOfRichestQuartile(List<Person> population)
13-
=> population
14-
.OrderByDescending(p => p.Earnings)
15-
.Take(population.Count/4)
16-
.Select(p => p.Earnings)
17-
.Average();
10+
// 1 Implement Map for ISet<T> and IDictionary<K, T>. (Tip: start by writing down
11+
// the signature in arrow notation.)
1812

19-
// 2. Check your answer with the msdn documentation: https://msdn.microsoft.com/en-us/library/system.linq.enumerable(v=vs.110).aspx.
20-
// How is `Average` different?
13+
// 2 Implement Map for Option and IEnumerable in terms of Bind and Return.
2114

22-
// 3. Implement a general purpose `Compose` function that takes two unary functions
23-
// and returns the composition of the two.
15+
// 3 Use Bind and an Option-returning Lookup function (such as the one we defined
16+
// in chapter 3) to implement GetWorkPermit, shown below.
2417

25-
// 4. Implement a `Lookup` extension method on `IDictionary<T>` returning `Option<T>`.
26-
27-
// 5. Use `Bind` and the `Lookup` function from the previous exercise to
28-
// implement `GetWorkPermit` below.Then enrich the implementation so that `GetWorkPermit`
18+
// Then enrich the implementation so that `GetWorkPermit`
2919
// returns `None` if the work permit has expired.
3020

31-
Option<WorkPermit> GetWorkPermit(Dictionary<string, Employee> people, string employeeId)
21+
static Option<WorkPermit> GetWorkPermit(Dictionary<string, Employee> people, string employeeId)
3222
{
3323
throw new NotImplementedException();
3424
}
3525

36-
// 6. Use `Bind` to implement `AverageYearsWorkedAtTheCompany` below(only
26+
// 4 Use Bind to implement AverageYearsWorkedAtTheCompany, shown below (only
3727
// employees who have left should be included).
3828

39-
double AverageYearsWorkedAtTheCompany(List<Employee> employees)
29+
static double AverageYearsWorkedAtTheCompany(List<Employee> employees)
4030
{
4131
// your implementation here...
4232
throw new NotImplementedException();
4333
}
44-
45-
// 7. Write implementations of `Where`, `ForEach` and `Bind` for
46-
// `Container`. Try doing so without looking at the implementations for
47-
// `Option` first, and only check them if needed.
48-
49-
// public static Container<R> Map ...
50-
// public static Container<T> Where ...
51-
// public static Container<R> Bind ...
52-
// public static Unit ForEach ...
53-
5434
}
5535

5636
public struct WorkPermit

Exercises/Chapter04/Solutions.cs

Lines changed: 29 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,74 +2,53 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using LaYumba.Functional;
5+
using static LaYumba.Functional.F;
56

67
namespace Exercises.Chapter4.Solutions
78
{
89
using static F;
910

1011
static class Solutions
1112
{
12-
// 1. Without looking at any code or documentation (or intllisense), write the function signatures of
13-
// `OrderByDescending`, `Take` and `Average`, which we used to implement `AverageEarningsOfRichestQuartile`:
13+
// 1 Implement Map for ISet<T> and IDictionary<K, T>. (Tip: start by writing down
14+
// the signature in arrow notation.)
1415

15-
// decimal AverageEarningsOfRichestQuartile(List<Person> population)
16-
// => population
17-
// .OrderByDescending(p => p.Earnings)
18-
// .Take(population.Count/4)
19-
// .Select(p => p.Earnings)
20-
// .Average();
21-
22-
// OrderByDescending : (IEnumerable<T>, (T -> decimal)) -> IEnumerable<T>
23-
// particularized for this case:
24-
// OrderByDescending : (IEnumerable<Person>, (Person -> decimal)) -> IEnumerable<Person>
25-
26-
// Take : (IEnumerable<T>, int) -> IEnumerable<T>
27-
// particularized for this case:
28-
// Take : (IEnumerable<Person>, int) -> IEnumerable<Person>
29-
30-
// Select : (IEnumerable<T>, (T -> R)) -> IEnumerable<R>
31-
// particularized for this case:
32-
// Select : (IEnumerable<Person>, (Person -> decimal)) -> IEnumerable<decimal>
33-
34-
// Average : IEnumerable<T> -> T
35-
// particularized for this case:
36-
// Average : IEnumerable<decimal> -> decimal
37-
38-
39-
40-
// 2. Check your answer with the msdn documentation: https://msdn.microsoft.com/en-us/library/system.linq.enumerable(v=vs.110).aspx.
41-
// How is `Average` different?
42-
43-
// Average is the only method call that does not return an IEnumerable;
44-
// this also means that Average is the only greedy method and causes all the
45-
// previous ones in the chain to be evaluated
46-
47-
48-
49-
// 3. Implement a general purpose `Compose` function that takes two unary functions
50-
// and returns the composition of the two.
51-
52-
static Func<T1, R> Compose<T1, T2, R>(this Func<T2, R> g, Func<T1, T2> f)
53-
=> x => g(f(x));
16+
// Map : ISet<T> -> (T -> R) -> ISet<R>
17+
static ISet<R> Map<T, R>(this ISet<T> ts, Func<T, R> f)
18+
{
19+
var rs = new HashSet<R>();
20+
foreach (var t in ts)
21+
rs.Add(f(t));
22+
return rs;
23+
}
5424

25+
// Map : IDictionary<K, T> -> (T -> R) -> IDictionary<K, R>
26+
static IDictionary<K, R> Map<K, T, R>
27+
(this IDictionary<K, T> dict, Func<T, R> f)
28+
{
29+
var rs = new Dictionary<K, R>();
30+
foreach (var pair in dict)
31+
rs[pair.Key] = f(pair.Value);
32+
return rs;
33+
}
5534

5635

57-
// 4. Implement a `Lookup` extension method on `IDictionary<T>` returning `Option<T>`.
36+
// 2 Implement Map for Option and IEnumerable in terms of Bind and Return.
5837

59-
static Option<T> Lookup<K, T>(this IDictionary<K, T> dict, K key)
60-
{
61-
T value;
62-
return dict.TryGetValue(key, out value) ? Some(value) : None;
63-
}
38+
public static Option<R> Map<T, R>(this Option<T> opt, Func<T, R> f)
39+
=> opt.Bind(t => Some(f(t)));
6440

41+
public static IEnumerable<R> Map<T, R>(this IEnumerable<T> ts, Func<T, R> f)
42+
=> ts.Bind(t => List(f(t)));
6543

6644

67-
// 5. Use `Bind` and the `Lookup` function from the previous exercise to
68-
// implement `GetWorkPermit` below.
45+
// 3 Use Bind and an Option-returning Lookup function (such as the one we defined
46+
// in chapter 3) to implement GetWorkPermit, shown below.
6947

7048
static Option<WorkPermit> GetWorkPermit(Dictionary<string, Employee> employees, string employeeId)
7149
=> employees.Lookup(employeeId).Bind(e => e.WorkPermit);
7250

51+
7352
// Then enrich the implementation so that `GetWorkPermit`
7453
// returns `None` if the work permit has expired.
7554

@@ -82,8 +61,7 @@ static Option<WorkPermit> GetValidWorkPermit(Dictionary<string, Employee> employ
8261
static Func<WorkPermit, bool> HasExpired => permit => permit.Expiry < DateTime.Now.Date;
8362

8463

85-
86-
// 6. Use `Bind` to implement `AverageYearsWorkedAtTheCompany` below(only
64+
// 4 Use Bind to implement AverageYearsWorkedAtTheCompany, shown below (only
8765
// employees who have left should be included).
8866

8967
static double AverageYearsWorkedAtTheCompany(List<Employee> employees)
@@ -100,14 +78,5 @@ select YearsBetween(e.JoinedOn, leftOn)
10078

10179
static double YearsBetween(DateTime start, DateTime end)
10280
=> (end - start).Days / 365d;
103-
104-
105-
// 7. Write implementations of `Where`, `ForEach` and `Bind` for
106-
// `Container`. Try doing so without looking at the implementations for
107-
// `Option` first, and only check them if needed.
108-
109-
// please see the implementation of Container
110-
// NOTE: `Where` cannot be implemented: since Container contains exactly
111-
// one value, you cannot "filter out" that value
11281
}
11382
}

0 commit comments

Comments
 (0)