In [2]:
import java.time.{Duration, LocalDateTime} // import 몰아쓰기
trait Visitor {
def id: String
def createdAt: LocalDateTime
def age = Duration.between(createdAt, LocalDateTime.now())
}
case class Anonymous(
id: String,
createdAt: LocalDateTime = LocalDateTime.now()
) extends Visitor
case class User(
id: String,
email: String,
createdAt: LocalDateTime = LocalDateTime.now()
) extends Visitor
println("Ok!")
Out[2]:
In [5]:
import java.time.Duration
import java.time.LocalDateTime
trait Visitor {
def id: String
def createdAt: LocalDateTime
def age = java.time.Duration.between(createdAt, LocalDateTime.now())
}
case class Anonymous(
id: String,
createdAt: LocalDateTime = LocalDateTime.now()
) extends Visitor
case class User(
id: String,
email: String,
createdAt: LocalDateTime = LocalDateTime.now()
) extends Visitor
println("Ok!")
Out[5]:
In [6]:
import java.time.{Duration => D, LocalDateTime}
trait Visitor {
def id: String
def createdAt: LocalDateTime
def age = D.between(createdAt, LocalDateTime.now())
}
case class Anonymous(
id: String,
createdAt: LocalDateTime = LocalDateTime.now()
) extends Visitor
case class User(
id: String,
email: String,
createdAt: LocalDateTime = LocalDateTime.now()
) extends Visitor
println("Ok!")
Out[6]:
In [6]:
// 익명인 사람과 아닌 사람을 확인할 때 사용
// 구현 된 method와 안된 method가 존재함. 위에선 구현된 것을 재사용
// extends ~는 상속 받는다는 것을 의미
// Trait : Java의 인터페이스와 유사함
In [7]:
import java.time.{Duration, LocalDateTime}
sealed trait Visitor {
def id: String
def createdAt: LocalDateTime
def age = Duration.between(createdAt, LocalDateTime.now())
}
case class Anonymous(
id: String,
createdAt: LocalDateTime = LocalDateTime.now()
) extends Visitor
case class User(
id: String,
email: String,
createdAt: LocalDateTime = LocalDateTime.now()
) extends Visitor
Out[7]:
In [8]:
def missingCase(v: Visitor) = v match {
case User(_, _, _) => "Got a user"
}
Out[8]:
In [8]:
<pastie>:18: warning: match may not be exhaustive.
It would fail on the following input: Anonymous(_, _)
def missingCase(v: Visitor) = v match {
^
missingCase: (v: Visitor)String
In [9]:
sealed trait Visitor { /* ... */ }
final case class User(/* ... */) extends Visitor
final case class Anonymous(/* ... */) extends Visitor
Out[9]:
In [9]:
case class Foo(a: A, b: B, c: C)
In [ ]:
sealed trait Foo
final case class A() extends Foo
final case class B() extends Foo
final case class C() extends Foo
In [10]:
trait Foo {
def bar: Bar
}
sealed trait Bar
final case class A() extends Bar
final case class B() extends Bar
final case class C() extends Bar
// 이런 방식을 더 선호
Out[10]:
In [11]:
sealed trait Foo
final case class Bar(a: A) extends Foo
final case class Baz(b: B) extends Foo
final case class Qux(c: C) extends Foo
Out[11]:
In [12]:
// FOO IS A, B AND C : with
// 다중 상속!
// trait에서만 다중 상속
// trait만 상속하고 나머지에선 상속을 안하는 것을 추천드립니다
trait A
trait B
trait C
trait Foo extends A with B with C
Out[12]:
In [13]:
trait Foo {
def sound: String
}
trait Bar extends Foo {
override def sound = "Baaaaaaar!"
}
trait Baz extends Foo {
override def sound = "Baaaaaaaaz!"
}
case object Qux extends Bar with Baz
// Bar를 하고 Baz를 덮어씀! 제일 우측에 있는 것이 적용됨
// override : method를 덮어 씌워라!
Out[13]:
In [15]:
Qux.sound
Out[15]:
In [16]:
trait Animal {
def sound: String
}
class Cat extends Animal {
override def sound: String = "mew"
}
class Dog extends Animal {
override def sound: String = "bowwow"
}
Out[16]:
In [17]:
val cat1 = new Cat
Out[17]:
In [18]:
cat1.sound
Out[18]:
In [19]:
sealed trait Integer {
def abs: Int = this match {
case NaturalNumber(n) => n
case Zero => 0
case NegativeInteger(n) => -n
}
}
final case class NaturalNumber(n: Int) extends Integer
final case class NegativeInteger(n: Int) extends Integer
final case object Zero extends Integer
Out[19]:
In [19]:
sealed trait shape{
def sides: Double = this match {
case Circle(r) => 0
case Rectagle(r) => 4
case Square(r) => 4
}
def perimeter: Double = this match {
case Circle(r) =>
case
}
def area: Double = this match {
case Circle(r) =>
case Recta
}
}
In [22]:
sealed trait Shape {
def sides: Int
def perimeter: Double
def area: Double
}
case class Circle(radius: Double) extends Shape{
override val sides = 0
override val perimeter = 2 * math.Pi * radius
override val area = math.Pi * radius * radius
}
case class Rectangle(width: Double, height: Double) extends Shape {
override val sides = 4
override val perimeter = 2 * (width + height)
override val area = width * height
}
case class Square(side: Double) extends Shape {
override val sides = 4
override val perimeter = 4 * side
override val area = side * side
}
println("OK")
Out[22]:
In [23]:
sealed trait Shape {
def sides: Int
def perimeter: Double
def area: Double
}
case class Circle(radius: Double) extends Shape{
override val sides = 0
override val perimeter = 2 * math.Pi * radius
override val area = math.Pi * radius * radius
}
trait Rectangular extends Shape {
def width: Double
def height: Double
override val sides = 4
override val perimeter = 2 * (width + height)
override val area = width * height
}
case class Rectangle(width: Double, height: Double) extends Rectangular
case class Square(side: Double) extends Rectangular {
override val width = side
override val height = side
}
println("OK")
Out[23]:
In [ ]:
Red → Green → Yellow → Red 로 순환되는 method next를 구현해보세요.
메소드를 클래스 외부에 구현해보세요.
In [29]:
sealed trait TrafficLight
case object Red extends TrafficLight
case object Green extends TrafficLight
case object Yellow extends TrafficLight
// 파라미터가 필요하지 않기 떄문에 case object로!!!!
def next(current: TrafficLight): TrafficLight = current match {
case Red => Green
case Green => Yellow
case Yellow => Red
}
assert(next(Red) == Green)
assert(next(Green) == Yellow)
assert(next(Yellow) == Red)
println("OK")
Out[29]:
In [26]:
next(Red)
Out[26]:
In [27]:
next(Green)
Out[27]:
In [28]:
next(Yellow)
Out[28]:
In [36]:
sealed trait TrafficLight {
def next: TrafficLight
}
case object Red extends TrafficLight {
override lazy val next: TrafficLight = Green
}
case object Green extends TrafficLight {
override lazy val next: TrafficLight = Yellow
}
case object Yellow extends TrafficLight {
override lazy val next: TrafficLight = Red
}
assert(Red.next == Green)
assert(Green.next == Yellow)
assert(Yellow.next == Red)
Out[36]:
In [41]:
sealed trait TrafficLight {
def next: TrafficLight = this match {
case Red => Green
case Green => Yellow
case Yellow => Red
}
}
case object Red extends TrafficLight
case object Green extends TrafficLight
case object Yellow extends TrafficLight
assert(Red.next == Green)
assert(Green.next == Yellow)
assert(Yellow.next == Red)
println("OK")
Out[41]:
In [42]:
sealed trait PeanoNumber {
def toInt: Int = this match {
case Zero => 0
case Succ(prev) => 1 + prev.toInt
}
}
final case object Zero extends PeanoNumber
final case class Succ(prev: PeanoNumber) extends PeanoNumber
Out[42]:
In [43]:
Zero.toInt
Out[43]:
In [44]:
Succ(Succ(Succ(Zero))).toInt
Out[44]:
In [45]:
Succ(Succ(Zero)).toInt
Out[45]:
In [46]:
// 구조만 있는 Tree 저장은 없어용
sealed trait Tree
final case object Leaf extends Tree
final case class Node(left: Tree, right: Tree) extends Tree
// 이건 Tail Recurson을 만들 수는 없음! 그러나 StackOverflow Error를 방지하기 위해 Heap을 사용함
Out[46]:
In [47]:
def height(tree: Tree): Int = tree match {
case Leaf => 0
case Node(left, right) => 1 + (height(left) max height(right))
}
Out[47]:
(height(left) max height(right)) : 둘 중 큰거를 해라!
In [48]:
height(Node(Node(Node(Leaf, Leaf), Leaf), Leaf))
Out[48]:
In [50]:
sealed trait PeanoNumber {
@annotation.tailrec
def toInt(acc: Int = 0): Int = this match {
case Zero => acc
case Succ(prev) => prev.toInt(acc + 1)
}
}
final case object Zero extends PeanoNumber
final case class Succ(prev: PeanoNumber) extends PeanoNumber
Out[50]:
In [53]:
Zero.toInt()
// 괄호가 있어야 함!! acc가 있어서!
Out[53]:
In [52]:
Succ(Succ(Succ(Zero))).toInt()
Out[52]:
In [65]:
sealed trait IntList {
def length: Int = this match {
case End => 0
case Pair(head, tail) => tail.length + 1
}
}
final case object End extends IntList
final case class Pair(head: Int, tail: IntList) extends IntList
val example = Pair(1, Pair(2, Pair(3, End)))
assert(example.length == 3)
assert(example.tail.length == 2)
assert(End.length == 0)
println("OK")
Out[65]:
In [66]:
sealed trait IntList {
def length: Int = {
@annotation.tailrec
def loop(current: IntList, acc: Int = 0): Int = current match {
case End => acc
case Pair(head, tail) => loop(tail, acc + 1)
}
loop(this)
}
}
final case object End extends IntList
final case class Pair(head: Int, tail: IntList) extends IntList
val example = Pair(1, Pair(2, Pair(3, End)))
assert(example.length == 3)
assert(example.tail.length == 2)
assert(End.length == 0)
println("Ok")
Out[66]:
Expression을 실제로 계산해서 Double로 바꿔주는 eval 메소드를 구현
실패할 수 있는 계산도 있습니다.
Double에는 NaN이라는 값이 이를 나타내긴 합니다만, 계산 실패와 그 이유를 명시적으로 나타내면 더 좋을 겁니다.
적절한 데이터 타입 Success, Failure을 구현하시고 eval을 그에 맞추어 수정
Division과 SquareRoot 연산을 추가해보세요. 다음을 통과할 수 있어야 합니다
In [74]:
sealed trait Expression
final case class Addition(left: Expression, right: Expression) extends Expression
final case class Substraction(left: Expression, right: Expression) extends Expression
final case class Number(value: Double) extends Expression
println("OK")
Out[74]:
In [74]:
// eval method 구현
In [75]:
sealed trait Expression {
def eval: Double = this match{
case Number(v) => v
case Addition(l, r) => l.eval + r.eval
case Substraction(l, r) => l.eval - r.eval
}
}
final case class Addition(left: Expression, right: Expression) extends Expression
final case class Substraction(left: Expression, right: Expression) extends Expression
final case class Number(value: Double) extends Expression
println("OK")
Out[75]:
In [75]:
// 실패 계산
// data type을 success, failure
In [76]:
sealed trait Expression {
def eval: Result = this match{
case Number(v) => Success(v)
case Addition(l, r) => (l.eval, r.eval) match {
case (Success(v1), Success(v2)) => Success(v1 + v2)
case (Failure(m), _) => Failure(m)
case (_, Failure(m)) => Failure(m)
}
case Substraction(l, r) => (l.eval, r.eval) match {
case (Success(v1), Success(v2)) => Success(v1 - v2)
case (Failure(m), _) => Failure(m)
case (_, Failure(m)) => Failure(m)
}
}
}
final case class Addition(left: Expression, right: Expression) extends Expression
final case class Substraction(left: Expression, right: Expression) extends Expression
final case class Number(value: Double) extends Expression
sealed trait Result
final case class Success(value: Double) extends Result
final case class Failure(msg: String) extends Result
println("OK")
Out[76]:
In [1]:
sealed trait Expression {
def eval: Result = this match {
case Number(v) => Success(v)
case Addition(l, r) => l.eval match {
case Success(lv) => r.eval match {
case Success(rv) => Success(lv + rv)
case Failure(msg) => Failure(msg)
}
case Failure(msg) => Failure(msg)
}
case Subtraction(l, r) => l.eval match {
case Success(lv) => r.eval match {
case Success(rv) => Success(lv - rv)
case Failure(msg) => Failure(msg)
}
case Failure(msg) => Failure(msg)
}
}
}
final case class Addition(left: Expression, right: Expression) extends Expression
final case class Subtraction(left: Expression, right: Expression) extends Expression
final case class Number(value: Double) extends Expression
sealed trait Result
final case class Success(value: Double) extends Result
final case class Failure(msg: String) extends Result
println("Ok")
Out[1]:
In [ ]: