Skip to content

Commit 0bae8a3

Browse files
committed
New test exercising implicit function types
1 parent 9c1d942 commit 0bae8a3

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

tests/run/config.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Some(Person(Name(John,Doe),Age(20)))
2+
None

tests/run/config.scala

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
case class Name(first: String, last: String)
2+
case class Age(age: Int)
3+
case class Person(name: Name, age: Age)
4+
case class Config(name: String, age: Int)
5+
6+
7+
8+
object Imperative {
9+
import Configs._
10+
import Exceptions._
11+
12+
// Algebraic Effects
13+
14+
def readName: Possibly[Configured[Name]] = {
15+
val parts = config.name.split(" ")
16+
require(parts.length >= 2)
17+
Name(parts(0), parts.tail.mkString(" "))
18+
}
19+
20+
def readAge: Configured[Possibly[Age]] = {
21+
val age = config.age
22+
require(1 <= age && age <= 150)
23+
Age(age)
24+
}
25+
26+
def readPerson: Configured[Option[Person]] =
27+
attempt(
28+
Some(Person(readName, readAge))
29+
).onError(None)
30+
31+
def main(args: Array[String]) = {
32+
println(readPerson(Config("John Doe", 20)))
33+
println(readPerson(Config("Incognito", 99)))
34+
}
35+
}
36+
37+
object Configs {
38+
type Configured[T] = implicit Config => T
39+
def config: Configured[Config] = implicitly[Config]
40+
}
41+
42+
object Exceptions {
43+
44+
private class E extends Exception
45+
46+
class CanThrow private[Exceptions] () {
47+
private[Exceptions] def throwE() = throw new E
48+
}
49+
50+
type Possibly[T] = implicit CanThrow => T
51+
52+
def require(p: Boolean)(implicit ct: CanThrow): Unit =
53+
if (!p) ct.throwE()
54+
55+
def attempt[T](op: Possibly[T]) = new OnError(op)
56+
57+
class OnError[T](op: Possibly[T]) {
58+
def onError(fallback: => T): T =
59+
try op(new CanThrow)
60+
catch { case ex: E => fallback }
61+
}
62+
}
63+
64+
object Test extends App {
65+
import Configs._
66+
import Exceptions._
67+
68+
type PC[T] = Possibly[Configured[T]]
69+
70+
val names: PC[List[Name]] = readName :: Nil
71+
val firstNames: PC[List[String]] = names.map(_.first)
72+
val longest: PC[String] = firstNames.maxBy(_.length)
73+
74+
def readName: Configured[Possibly[Name]] = {
75+
val parts = config.name.split(" ")
76+
require(parts.length >= 2)
77+
Name(parts(0), parts.tail.mkString(" "))
78+
}
79+
80+
def readAge: Possibly[Configured[Age]] = {
81+
val age = config.age
82+
require(1 <= age && age <= 150)
83+
Age(age)
84+
}
85+
86+
def readPerson: Configured[Option[Person]] =
87+
attempt(
88+
Some(Person(readName, readAge))
89+
).onError(None)
90+
91+
val config1 = Config("John Doe", 20)
92+
val config2 = Config("Incognito", 99)
93+
94+
println(readPerson(config1))
95+
println(readPerson(config2))
96+
}
97+
98+
object OptionTest extends App {
99+
100+
def readName(config: Config): Option[Name] = {
101+
val parts = config.name.split(" ")
102+
if (parts.length >= 2) Some(Name(parts(0), parts.tail.mkString(" ")))
103+
else None
104+
}
105+
106+
def readAge(config: Config): Option[Age] = {
107+
val age = config.age
108+
if (1 <= age && age <= 150) Some(Age(age)) else None
109+
}
110+
111+
def readPerson(config: Config): Option[Person] =
112+
for {
113+
name <- readName(config)
114+
age <- readAge(config)
115+
}
116+
yield Person(name, age)
117+
118+
val config1 = Config("John Doe", 20)
119+
val config2 = Config("Incognito", 99)
120+
121+
println(readPerson(config1))
122+
println(readPerson(config2))
123+
}

0 commit comments

Comments
 (0)