1
+ object Test {
2
+
3
+ trait Effect
4
+
5
+ // Type X => Y
6
+ abstract class Fun [- X , Y ] {
7
+ type Eff <: Effect
8
+ def apply (x : X ): implicit Eff => Y
9
+ }
10
+
11
+ // Type X -> Y
12
+ type PureFun [- X , Y ] = Fun [X , Y ] { type Eff = Effect }
13
+
14
+ // def map(f: A => B)(xs: List[A]): List[B]
15
+ def map [A , B , E <: Effect ](f : Fun [A , B ] { type Eff = E })(xs : List [A ])
16
+ : implicit E => List [B ] =
17
+ xs.map(f.apply)
18
+
19
+ // def mapFn[A, B]: (A => B) -> List[A] -> List[B]
20
+ def mapFn [A , B , E <: Effect ]:
21
+ PureFun [
22
+ Fun [A , B ] { type Eff = E },
23
+ Fun [List [A ], List [B ]] { type Eff = E }
24
+ ] =
25
+ new Fun [ // would like to write new PureFun here
26
+ // or, even better, drop everything
27
+ Fun [A , B ] { type Eff = E },
28
+ Fun [List [A ], List [B ]] { type Eff = E }
29
+ ] {
30
+ type Eff = Effect
31
+ def apply (f : Fun [A , B ] { type Eff = E }) =
32
+ new Fun [List [A ], List [B ]] {
33
+ type Eff = E
34
+ def apply (xs : List [A ]): implicit Eff => List [B ] =
35
+ map(f)(xs)
36
+ }
37
+ }
38
+
39
+ implicit def combine [E1 <: Effect , E2 <: Effect ](implicit x : E1 , y : E2 ): E1 & E2 = ???
40
+
41
+ // def compose(f: A => B)(g: B => C)(x: A): C
42
+ def compose [A , B , C , E1 <: Effect , E2 <: Effect ]
43
+ (f : Fun [A , B ] { type Eff = E1 })
44
+ (g : Fun [B , C ] { type Eff = E2 })
45
+ (x : A ):
46
+ implicit E1 & E2 => C = g(f(x))
47
+
48
+ // def composeFn: (A => B) -> (B => C) -> A -> C
49
+ def composeFn [A , B , C , E1 <: Effect , E2 <: Effect ]:
50
+ PureFun [
51
+ Fun [A , B ] { type Eff = E1 },
52
+ PureFun [
53
+ Fun [B , C ] { type Eff = E2 },
54
+ Fun [A , C ] { type Eff = E1 & E2 }
55
+ ]
56
+ ] =
57
+ new Fun [
58
+ Fun [A , B ] { type Eff = E1 },
59
+ PureFun [
60
+ Fun [B , C ] { type Eff = E2 },
61
+ Fun [A , C ] { type Eff = E1 & E2 }
62
+ ]
63
+ ] {
64
+ type Eff = Effect
65
+ def apply (f : Fun [A , B ] { type Eff = E1 }) =
66
+ new Fun [
67
+ Fun [B , C ] { type Eff = E2 },
68
+ Fun [A , C ] { type Eff = E1 & E2 }
69
+ ] {
70
+ type Eff = Effect
71
+ def apply (g : Fun [B , C ] { type Eff = E2 }) =
72
+ new Fun [A , C ] {
73
+ type Eff = E1 & E2
74
+ def apply (x : A ) = compose(f)(g)(x)
75
+ }
76
+ }
77
+ }
78
+ }
0 commit comments