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