๐Ÿš€ Scala์˜ ํƒ€์ž… ๋žŒ๋‹ค: ๊ณ ์ฐจ ํƒ€์ž… ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์„ธ๊ณ„๋กœ ํ’๋ฉ! ๐ŸŒŠ

์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ Scala์˜ ํƒ€์ž… ๋žŒ๋‹ค: ๊ณ ์ฐจ ํƒ€์ž… ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์„ธ๊ณ„๋กœ ํ’๋ฉ! ๐ŸŒŠ

 

 

์•ˆ๋…•ํ•˜์„ธ์š”, ์—ฌ๋Ÿฌ๋ถ„! ์˜ค๋Š˜์€ ์ •๋ง ํฅ๋ฏธ์ง„์ง„ํ•œ ์ฃผ์ œ๋กœ ์—ฌ๋Ÿฌ๋ถ„๊ณผ ํ•จ๊ป˜ ํ•  ๊ฑฐ์˜ˆ์š”. ๋ฐ”๋กœ Scala์˜ ํƒ€์ž… ๋žŒ๋‹ค์™€ ๊ณ ์ฐจ ํƒ€์ž… ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๋Œ€ํ•ด ๊นŠ์ด ํŒŒ๊ณ ๋“ค์–ด๋ณผ ๊ฑฐ๋ž๋‹ˆ๋‹ค. ์–ด๋จธ, ๋ฒŒ์จ๋ถ€ํ„ฐ ๋จธ๋ฆฌ๊ฐ€ ์ง€๋ˆ๊ฑฐ๋ฆฌ๋‚˜์š”? ใ…‹ใ…‹ใ…‹ ๊ฑฑ์ • ๋งˆ์„ธ์š”! ์šฐ๋ฆฌ ํ•จ๊ป˜ ์ฐจ๊ทผ์ฐจ๊ทผ ์•Œ์•„๊ฐ€ ๋ณด์ฃ !

์ด ์ฃผ์ œ๋Š” 'ํ”„๋กœ๊ทธ๋žจ๊ฐœ๋ฐœ' ์นดํ…Œ๊ณ ๋ฆฌ์˜ '๊ธฐํƒ€ํ”„๋กœ๊ทธ๋žจ๊ฐœ๋ฐœ'์— ์†ํ•˜๋Š” ๋‚ด์šฉ์ด์—์š”. ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์„ธ๊ณ„์—์„œ ์•„์ฃผ ์ค‘์š”ํ•œ ๊ฐœ๋…์ด์ฃ . ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ์„ ๊ฑฐ๋ž˜ํ•˜๋“ฏ์ด, ์šฐ๋ฆฌ๋„ ์˜ค๋Š˜ ๋‹ค์–‘ํ•œ ํƒ€์ž…๊ณผ ๋žŒ๋‹ค์˜ ์„ธ๊ณ„๋ฅผ ํƒํ—˜ํ•ด๋ณผ ๊ฑฐ์˜ˆ์š”!

๐ŸŽ“ ์ž ๊น! ์•Œ๊ณ  ๊ฐ€์„ธ์š”: Scala๋Š” Java Virtual Machine(JVM) ์œ„์—์„œ ๋™์ž‘ํ•˜๋Š” ๋‹ค์ค‘ ํŒจ๋Ÿฌ๋‹ค์ž„ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์˜ˆ์š”. ๊ฐ์ฒด ์ง€ํ–ฅ์  ํŠน์„ฑ๊ณผ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํŠน์„ฑ์„ ๋ชจ๋‘ ๊ฐ€์ง€๊ณ  ์žˆ์ฃ . ๊ทธ๋ž˜์„œ Scala๋กœ ์ฝ”๋”ฉํ•˜๋ฉด ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์—ฌ๋Ÿฌ ์žฌ๋Šฅ์„ ํ•œ ๋ฒˆ์— ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋‹ค์–‘ํ•œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์Šคํƒ€์ผ์„ ๊ตฌ์‚ฌํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค!

์ž, ์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์‹œ์ž‘ํ•ด๋ณผ๊นŒ์š”? ์šฐ๋ฆฌ์˜ ์—ฌ์ •์€ ๊ธธ๊ณ ๋„ ํ—˜๋‚œํ•  ์ˆ˜ ์žˆ์–ด์š”. ํ•˜์ง€๋งŒ ๊ฑฑ์ • ๋งˆ์„ธ์š”! ์ œ๊ฐ€ ์—ฌ๋Ÿฌ๋ถ„์˜ ๋“ ๋“ ํ•œ ๊ฐ€์ด๋“œ๊ฐ€ ๋˜์–ด ๋“œ๋ฆด๊ฒŒ์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ „๋ฌธ๊ฐ€์˜ ๋„์›€์„ ๋ฐ›๋“ฏ์ด ๋ง์ด์ฃ ! ๐Ÿ˜‰

์šฐ๋ฆฌ์˜ ์—ฌ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ˆœ์„œ๋กœ ์ง„ํ–‰๋  ๊ฑฐ์˜ˆ์š”:

  • ํƒ€์ž… ์‹œ์Šคํ…œ์˜ ๊ธฐ์ดˆ
  • ๋žŒ๋‹ค์˜ ๊ฐœ๋…๊ณผ ํ™œ์šฉ
  • ๊ณ ์ฐจ ํƒ€์ž…์˜ ์„ธ๊ณ„
  • ํƒ€์ž… ๋žŒ๋‹ค์˜ ๋งˆ๋ฒ•
  • ์‹ค์ „ ์˜ˆ์ œ์™€ ํ™œ์šฉ

์ค€๋น„๋˜์…จ๋‚˜์š”? ๊ทธ๋Ÿผ ์ถœ๋ฐœ~! ๐Ÿš—๐Ÿ’จ

๐Ÿงฑ ํƒ€์ž… ์‹œ์Šคํ…œ์˜ ๊ธฐ์ดˆ: ์šฐ๋ฆฌ์˜ ์—ฌ์ •์˜ ์‹œ์ž‘์ 

์ž, ์—ฌ๋Ÿฌ๋ถ„! ํƒ€์ž… ์‹œ์Šคํ…œ์ด๋ผ๊ณ  ํ•˜๋ฉด ๋ญ๊ฐ€ ์ œ์ผ ๋จผ์ € ๋– ์˜ค๋ฅด์‹œ๋‚˜์š”? ํ˜น์‹œ "์•„, ๊ทธ๊ฑฐ Int๋ž‘ String ๊ฐ™์€ ๊ฑฐ ์•„๋ƒ?"๋ผ๊ณ  ์ƒ๊ฐํ•˜์…จ๋‹ค๋ฉด... ์Œ, ๋งž์•„์š”! ํ•˜์ง€๋งŒ ๊ทธ๊ฒŒ ์ „๋ถ€๋Š” ์•„๋‹ˆ๋ž๋‹ˆ๋‹ค. ใ…‹ใ…‹ใ…‹

ํƒ€์ž… ์‹œ์Šคํ…œ์€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์˜ ํ•ต์‹ฌ ์š”์†Œ์˜ˆ์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๊ฐ ์žฌ๋Šฅ๋“ค์ด ๋ถ„๋ฅ˜๋˜์–ด ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ๋„ ๋ฐ์ดํ„ฐ์™€ ์—ฐ์‚ฐ์„ ๋ถ„๋ฅ˜ํ•˜๊ณ  ์กฐ์งํ™”ํ•˜๋Š” ์—ญํ• ์„ ํ•˜์ฃ . ๊ทธ๋Ÿผ Scala์˜ ํƒ€์ž… ์‹œ์Šคํ…œ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณผ๊นŒ์š”?

๐ŸŒŸ Scala์˜ ํƒ€์ž… ์‹œ์Šคํ…œ ํŠน์ง•:

  • ์ •์  ํƒ€์ž… ์‹œ์Šคํ…œ (์ปดํŒŒ์ผ ์‹œ์ ์— ํƒ€์ž… ์ฒดํฌ)
  • ํƒ€์ž… ์ถ”๋ก  (๋ณ€์ˆ˜์˜ ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ ์„ ์–ธํ•˜์ง€ ์•Š์•„๋„ ๋จ)
  • ์ œ๋„ค๋ฆญ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ง€์›
  • ๋Œ€์ˆ˜์  ๋ฐ์ดํ„ฐ ํƒ€์ž… (ADT) ์ง€์›
  • ๊ณ ์ฐจ ํƒ€์ž… (Higher-kinded types) ์ง€์›

์™€์šฐ! ๋ฒŒ์จ๋ถ€ํ„ฐ ๋Œ€๋‹จํ•ด ๋ณด์ด์ฃ ? ใ…‹ใ…‹ใ…‹ ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ณผ๊ฒŒ์š”!

1. ์ •์  ํƒ€์ž… ์‹œ์Šคํ…œ ๐Ÿ’ช

Scala๋Š” ์ •์  ํƒ€์ž… ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•ด์š”. ์ด๊ฒŒ ๋ฌด์Šจ ๋ง์ด๋ƒ๊ณ ์š”? ๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ, ์ปดํŒŒ์ผ ์‹œ์ ์— ๋ชจ๋“  ํ‘œํ˜„์‹์˜ ํƒ€์ž…์„ ๊ฒ€์‚ฌํ•œ๋‹ค๋Š” ๊ฑฐ์˜ˆ์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๋ฅผ ๋งŽ์ด ์ค„์ผ ์ˆ˜ ์žˆ์ฃ !

์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ์š”?


val x: Int = 5
val y: String = "Hello"
val z: Int = x + y  // ์ปดํŒŒ์ผ ์—๋Ÿฌ!

์œ„ ์ฝ”๋“œ์—์„œ z๋ฅผ ์ •์˜ํ•  ๋•Œ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ "์ž ๊น๋งŒ์š”! Int์™€ String์„ ๋”ํ•  ์ˆœ ์—†์–ด์š”!"๋ผ๊ณ  ๋งํ•ด์ค„ ๊ฑฐ์˜ˆ์š”. ์ด๋ ‡๊ฒŒ ๋ฏธ๋ฆฌ ์˜ค๋ฅ˜๋ฅผ ์žก์•„์ฃผ๋‹ˆ ์–ผ๋งˆ๋‚˜ ํŽธ๋ฆฌํ•œ๊ฐ€์š”? ๐Ÿ˜„

2. ํƒ€์ž… ์ถ”๋ก  ๐Ÿ•ต๏ธโ€โ™€๏ธ

Scala์˜ ๋˜ ๋‹ค๋ฅธ ๋ฉ‹์ง„ ๊ธฐ๋Šฅ์€ ํƒ€์ž… ์ถ”๋ก ์ด์—์š”. ์ด๊ฒŒ ๋ญ๋ƒ๊ณ ์š”? ์Œ... ์—ฌ๋Ÿฌ๋ถ„์ด ์žฌ๋Šฅ๋„ท์—์„œ ์žฌ๋Šฅ์„ ๋“ฑ๋กํ•  ๋•Œ, ์‹œ์Šคํ…œ์ด ์ž๋™์œผ๋กœ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ถ”์ฒœํ•ด์ฃผ๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ผ์š”!

์ฝ”๋“œ๋กœ ๋ณด๋ฉด ์ด๋ ‡๋‹ต๋‹ˆ๋‹ค:


val x = 5  // Int๋กœ ์ถ”๋ก ๋จ
val y = "Hello"  // String์œผ๋กœ ์ถ”๋ก ๋จ
val z = x * 2  // Int๋กœ ์ถ”๋ก ๋จ

๋ณด์„ธ์š”! ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ ์ ์ง€ ์•Š์•„๋„ Scala๊ฐ€ ์•Œ์•„์„œ ์ถ”๋ก ํ•ด์ฃผ๋„ค์š”. ์ •๋ง ๋˜‘๋˜‘ํ•˜์ฃ ? ใ…‹ใ…‹ใ…‹

3. ์ œ๋„ค๋ฆญ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๐Ÿงฌ

์ œ๋„ค๋ฆญ์ด๋ผ๋Š” ๋ง, ๋“ค์–ด๋ณด์…จ๋‚˜์š”? ์•„๋‹ˆ๋ผ๊ณ ์š”? ๊ดœ์ฐฎ์•„์š”! ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•ด๋“œ๋ฆด๊ฒŒ์š”.

์ œ๋„ค๋ฆญ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ํƒ€์ž…์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์ด์—์š”. ์Œ... ๋ญ”๊ฐ€ ์–ด๋ ค์›Œ ๋ณด์ด์ฃ ? ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ์•„์ฃผ ์œ ์šฉํ•˜๋‹ต๋‹ˆ๋‹ค!

์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊ฒŒ์š”:


def printBox[T](content: T): Unit = {
  println(s"๋ฐ•์Šค ์•ˆ์—๋Š” $content ๊ฐ€ ๋“ค์–ด์žˆ์–ด์š”!")
}

printBox(5)  // "๋ฐ•์Šค ์•ˆ์—๋Š” 5 ๊ฐ€ ๋“ค์–ด์žˆ์–ด์š”!" ์ถœ๋ ฅ
printBox("Hello")  // "๋ฐ•์Šค ์•ˆ์—๋Š” Hello ๊ฐ€ ๋“ค์–ด์žˆ์–ด์š”!" ์ถœ๋ ฅ

์—ฌ๊ธฐ์„œ [T]๋Š” ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ์˜ˆ์š”. ์ด ํ•จ์ˆ˜๋Š” ์–ด๋–ค ํƒ€์ž…์˜ ๊ฐ’์ด๋“  ๋ฐ›์•„์„œ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ์ฃ . ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ์„ ํ•œ ๊ณณ์—์„œ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ์š”! ๐Ÿ˜‰

4. ๋Œ€์ˆ˜์  ๋ฐ์ดํ„ฐ ํƒ€์ž… (ADT) ๐Ÿงฎ

๋Œ€์ˆ˜์  ๋ฐ์ดํ„ฐ ํƒ€์ž…... ์œผ์•…! ์ˆ˜ํ•™ ๊ฐ™์•„ ๋ณด์ด๋Š” ์ด๋ฆ„์ด์ฃ ? ใ…‹ใ…‹ใ…‹ ํ•˜์ง€๋งŒ ๊ฑฑ์ • ๋งˆ์„ธ์š”. ์ƒ๊ฐ๋ณด๋‹ค ์–ด๋ ต์ง€ ์•Š์•„์š”!

ADT๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ํƒ€์ž…์„ ์กฐํ•ฉํ•ด์„œ ์ƒˆ๋กœ์šด ํƒ€์ž…์„ ๋งŒ๋“œ๋Š” ๋ฐฉ์‹์ด์—์š”. Scala์—์„œ๋Š” ์ฃผ๋กœ case class์™€ sealed trait๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ตฌํ˜„ํ•˜์ฃ .

์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ์š”?


sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(width: Double, height: Double) extends Shape

def area(shape: Shape): Double = shape match {
  case Circle(r) => Math.PI * r * r
  case Rectangle(w, h) => w * h
}

val myCircle = Circle(5)
val myRectangle = Rectangle(3, 4)

println(area(myCircle))  // 78.53981633974483
println(area(myRectangle))  // 12.0

์™€์šฐ! ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‹ค์–‘ํ•œ ๋„ํ˜•์˜ ๋ฉด์ ์„ ์‰ฝ๊ฒŒ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ์–ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ์„ ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ !

5. ๊ณ ์ฐจ ํƒ€์ž… (Higher-kinded types) ๐Ÿš€

์ž, ์ด์ œ ๋Œ€๋ง์˜ ๊ณ ์ฐจ ํƒ€์ž…์ด์—์š”! ์ด๊ฑด ๋ญ๋ƒ๊ณ ์š”? ์Œ... ์ผ๋‹จ "์™€, ์ด๊ฑฐ ์ง„์งœ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ์ด๊ตฌ๋‚˜!"๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ใ…‹ใ…‹ใ…‹

๊ณ ์ฐจ ํƒ€์ž…์€ ํƒ€์ž…์„ ์ธ์ž๋กœ ๋ฐ›๋Š” ํƒ€์ž…์ด์—์š”. ๋ญ”๊ฐ€ ๋ณต์žกํ•ด ๋ณด์ด์ฃ ? ๊ฑฑ์ • ๋งˆ์„ธ์š”. ์ฒœ์ฒœํžˆ ์„ค๋ช…ํ•ด๋“œ๋ฆด๊ฒŒ์š”!

์˜ˆ๋ฅผ ๋“ค์–ด, List๋‚˜ Option ๊ฐ™์€ ํƒ€์ž…๋“ค์€ ๋‹ค๋ฅธ ํƒ€์ž…์„ ์ธ์ž๋กœ ๋ฐ›์•„์š”. List[Int], Option[String] ์ด๋Ÿฐ ์‹์œผ๋กœ์š”. ์ด๋Ÿฐ ํƒ€์ž…๋“ค์„ ๊ณ ์ฐจ ํƒ€์ž…์ด๋ผ๊ณ  ํ•ด์š”.

Scala์—์„œ๋Š” ์ด๋Ÿฐ ๊ณ ์ฐจ ํƒ€์ž…์„ ์ง์ ‘ ์ •์˜ํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”. ์˜ˆ๋ฅผ ๋“ค๋ฉด:


trait Functor[F[_]] {
  def map[A, B](fa: F[A])(f: A => B): F[B]
}

implicit val listFunctor: Functor[List] = new Functor[List] {
  def map[A, B](fa: List[A])(f: A => B): List[B] = fa.map(f)
}

implicit val optionFunctor: Functor[Option] = new Functor[Option] {
  def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
}

์šฐ์™€! ์ด๊ฒŒ ๋ฐ”๋กœ ๊ณ ์ฐจ ํƒ€์ž…์˜ ํž˜์ด์—์š”. Functor๋ผ๋Š” ํ•˜๋‚˜์˜ ํŠธ๋ ˆ์ดํŠธ๋กœ List์™€ Option ๋ชจ๋‘๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์ฃ . ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ํ•˜๋‚˜์˜ ํ”Œ๋žซํผ์œผ๋กœ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ์š”! ๐Ÿ˜Ž

์ž, ์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ Scala ํƒ€์ž… ์‹œ์Šคํ…œ์˜ ๊ธฐ์ดˆ์˜€์–ด์š”. ์–ด๋– ์‹ ๊ฐ€์š”? ์กฐ๊ธˆ์€ ๊ฐ์ด ์˜ค์‹œ๋‚˜์š”? ใ…‹ใ…‹ใ…‹ ์•„์ง ์™„์ „ํžˆ ์ดํ•ด๊ฐ€ ์•ˆ ๊ฐ€๋„ ๊ดœ์ฐฎ์•„์š”. ์šฐ๋ฆฌ๋Š” ์ด์ œ ์‹œ์ž‘์ผ ๋ฟ์ด๋‹ˆ๊นŒ์š”!

๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ๋žŒ๋‹ค์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฑฐ์˜ˆ์š”. ๋žŒ๋‹ค๋ผ... ๋ญ”๊ฐ€ ๋ฉ‹์ง„ ์ด๋ฆ„ ๊ฐ™์ฃ ? ๊ธฐ๋Œ€๋˜์ง€ ์•Š๋‚˜์š”? ์ €๋Š” ์ •๋ง ์‹ ๋‚˜์š”! ๐ŸŽ‰

๐Ÿšจ ์ฃผ์˜์‚ฌํ•ญ: Scala์˜ ํƒ€์ž… ์‹œ์Šคํ…œ์€ ์ •๋ง ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ๊ทธ๋งŒํผ ๋ณต์žกํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ฒ˜์Œ์—๋Š” ์–ด๋ ค์›Œ ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ฐจ๊ทผ์ฐจ๊ทผ ๋ฐฐ์›Œ๋‚˜๊ฐ€๋ฉด ๋ฐ˜๋“œ์‹œ ๋งˆ์Šคํ„ฐํ•  ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”! ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ƒˆ๋กœ์šด ์žฌ๋Šฅ์„ ๋ฐฐ์šฐ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ . ํž˜๋‚ด์„ธ์š”! ๐Ÿ’ช

๐ŸŽญ ๋žŒ๋‹ค์˜ ๊ฐœ๋…๊ณผ ํ™œ์šฉ: ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ

์ž, ์ด์ œ ๋žŒ๋‹ค์˜ ์„ธ๊ณ„๋กœ ๋“ค์–ด๊ฐ€๋ณผ ์‹œ๊ฐ„์ด์—์š”! ๋žŒ๋‹ค๋ผ... ๋ญ”๊ฐ€ ๊ทธ๋ฆฌ์Šค ๋ฌธ์ž ๊ฐ™์€ ๋Š๋‚Œ์ด ๋‚˜์ง€ ์•Š๋‚˜์š”? ใ…‹ใ…‹ใ…‹ ์‚ฌ์‹ค ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ์˜ ๋žŒ๋‹ค๋Š” ๊ทธ๋ฆฌ์Šค ๋ฌธ์ž์™€๋Š” ์•„๋ฌด ์ƒ๊ด€์ด ์—†์–ด์š”. ๊ทธ๋Ÿผ ๋Œ€์ฒด ๋ญ˜๊นŒ์š”?

๐Ÿฏ ๊ฟ€ํŒ: ๋žŒ๋‹ค๋Š” ๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ ์ด๋ฆ„ ์—†๋Š” ํ•จ์ˆ˜์˜ˆ์š”. "์ต๋ช… ํ•จ์ˆ˜"๋ผ๊ณ ๋„ ๋ถˆ๋Ÿฌ์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ต๋ช…์œผ๋กœ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ๋„ ์ด๋ฆ„ ์—†์ด ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค!

1. ๋žŒ๋‹ค์˜ ๊ธฐ๋ณธ ๋ฌธ๋ฒ• ๐Ÿ“

Scala์—์„œ ๋žŒ๋‹ค์˜ ๊ธฐ๋ณธ ๋ฌธ๋ฒ•์€ ์•„์ฃผ ๊ฐ„๋‹จํ•ด์š”. ํŒŒ๋ผ๋ฏธํ„ฐ, ํ™”์‚ดํ‘œ, ๊ทธ๋ฆฌ๊ณ  ํ•จ์ˆ˜ ๋ณธ๋ฌธ์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์ฃ . ์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ์š”?


val add = (x: Int, y: Int) => x + y

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด add๋ผ๋Š” ์ด๋ฆ„์˜ ํ•จ์ˆ˜๊ฐ€ ๋งŒ๋“ค์–ด์ ธ์š”. ์ด ํ•จ์ˆ˜๋Š” ๋‘ ๊ฐœ์˜ Int๋ฅผ ๋ฐ›์•„์„œ ๋”ํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•ด์š”. ์‚ฌ์šฉ๋ฒ•์€ ์ด๋ ‡๋‹ต๋‹ˆ๋‹ค:


println(add(3, 4))  // 7 ์ถœ๋ ฅ

์™€! ์ •๋ง ๊ฐ„๋‹จํ•˜์ฃ ? ใ…‹ใ…‹ใ…‹

2. ๋žŒ๋‹ค์˜ ํ™œ์šฉ ๐Ÿ› ๏ธ

๋žŒ๋‹ค๋Š” ์ •๋ง ๋‹ค์–‘ํ•œ ๊ณณ์—์„œ ํ™œ์šฉ๋  ์ˆ˜ ์žˆ์–ด์š”. ํŠนํžˆ ์ปฌ๋ ‰์…˜์„ ๋‹ค๋ฃฐ ๋•Œ ์•„์ฃผ ์œ ์šฉํ•˜๋‹ต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ์š”?


val numbers = List(1, 2, 3, 4, 5)

// ๋ชจ๋“  ์ˆซ์ž๋ฅผ ๋‘ ๋ฐฐ๋กœ ๋งŒ๋“ค๊ธฐ
val doubled = numbers.map(x => x * 2)
println(doubled)  // List(2, 4, 6, 8, 10)

// ์ง์ˆ˜๋งŒ ๊ณจ๋ผ๋‚ด๊ธฐ
val evens = numbers.filter(x => x % 2 == 0)
println(evens)  // List(2, 4)

// ๋ชจ๋“  ์ˆซ์ž์˜ ํ•ฉ ๊ตฌํ•˜๊ธฐ
val sum = numbers.reduce((x, y) => x + y)
println(sum)  // 15

์šฐ์™€! ์ด๋ ‡๊ฒŒ ๋žŒ๋‹ค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ์ •๋ง ๊ฐ„๊ฒฐํ•ด์ง€๊ณ  ์ฝ๊ธฐ ์‰ฌ์›Œ์ ธ์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์›ํ•˜๋Š” ์žฌ๋Šฅ์„ ์‰ฝ๊ฒŒ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ ! ๐Ÿ˜‰

3. ํด๋กœ์ €(Closure) ๐Ÿšช

๋žŒ๋‹ค๋ฅผ ์ด์•ผ๊ธฐํ•  ๋•Œ ๋นผ๋†“์„ ์ˆ˜ ์—†๋Š” ๊ฒŒ ๋ฐ”๋กœ ํด๋กœ์ €์˜ˆ์š”. ํด๋กœ์ €๋Š” ๋ญ˜๊นŒ์š”? ์Œ... ์‰ฝ๊ฒŒ ๋งํ•ด์„œ ์ž์‹ ์˜ ํ™˜๊ฒฝ์„ ๊ธฐ์–ตํ•˜๋Š” ํ•จ์ˆ˜๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์–ด์š”.

์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊ฒŒ์š”:


def makeAdder(x: Int) = (y: Int) => x + y

val add5 = makeAdder(5)
println(add5(3))  // 8 ์ถœ๋ ฅ
println(add5(7))  // 12 ์ถœ๋ ฅ

์—ฌ๊ธฐ์„œ makeAdder ํ•จ์ˆ˜๋Š” ํด๋กœ์ €๋ฅผ ๋ฐ˜ํ™˜ํ•ด์š”. ์ด ํด๋กœ์ €๋Š” x์˜ ๊ฐ’์„ "๊ธฐ์–ต"ํ•˜๊ณ  ์žˆ์ฃ . ๊ทธ๋ž˜์„œ add5๋Š” ํ•ญ์ƒ 5๋ฅผ ๋”ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ๋˜๋Š” ๊ฑฐ์˜ˆ์š”. ์‹ ๊ธฐํ•˜์ฃ ? ใ…‹ใ…‹ใ…‹

4. ๋ถ€๋ถ„ ์ ์šฉ ํ•จ์ˆ˜ (Partially Applied Functions) ๐Ÿงฉ

Scala์—์„œ๋Š” ํ•จ์ˆ˜์˜ ์ผ๋ถ€ ์ธ์ž๋งŒ ์ ์šฉํ•œ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”. ์ด๊ฑธ ๋ถ€๋ถ„ ์ ์šฉ ํ•จ์ˆ˜๋ผ๊ณ  ํ•ด์š”. ์–ด๋ ต๊ฒŒ ๋“ค๋ฆฌ๋‚˜์š”? ๊ฑฑ์ • ๋งˆ์„ธ์š”, ์˜ˆ์ œ๋ฅผ ๋ณด๋ฉด ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”!


def multiply(x: Int, y: Int) = x * y

val double = multiply(2, _: Int)
println(double(4))  // 8 ์ถœ๋ ฅ
println(double(7))  // 14 ์ถœ๋ ฅ

์—ฌ๊ธฐ์„œ double์€ multiply ํ•จ์ˆ˜์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋ฅผ 2๋กœ ๊ณ ์ •ํ•œ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜์˜ˆ์š”. _๋Š” "๋‚˜์ค‘์— ์ฑ„์›Œ ๋„ฃ์„ ๊ฐ’"์„ ์˜๋ฏธํ•ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ผ๋ถ€ ์กฐ๊ฑด๋งŒ ์ •ํ•ด๋†“๊ณ  ๋‚˜๋จธ์ง€๋Š” ๋‚˜์ค‘์— ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ์š”! ๐Ÿ˜„

5. ํ•จ์ˆ˜ ํ•ฉ์„ฑ (Function Composition) ๐ŸŽผ

ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๋˜ ๋‹ค๋ฅธ ๋ฉ‹์ง„ ํŠน์ง•์€ ํ•จ์ˆ˜๋ฅผ ํ•ฉ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑฐ์˜ˆ์š”. ๋งˆ์น˜ ๋ ˆ๊ณ  ๋ธ”๋ก์„ ์กฐ๋ฆฝํ•˜๋“ฏ์ด, ์—ฌ๋Ÿฌ ํ•จ์ˆ˜๋ฅผ ์กฐํ•ฉํ•ด์„œ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค!


val double = (x: Int) => x * 2
val addOne = (x: Int) => x + 1

val doubleThenAddOne = double andThen addOne
val addOneThenDouble = double compose addOne

println(doubleThenAddOne(3))  // 7 ์ถœ๋ ฅ (3 * 2 + 1)
println(addOneThenDouble(3))  // 8 ์ถœ๋ ฅ ((3 + 1) * 2)

andThen๊ณผ compose๋Š” ํ•จ์ˆ˜๋ฅผ ํ•ฉ์„ฑํ•˜๋Š” ๋ฉ”์„œ๋“œ์˜ˆ์š”. andThen์€ "์ด ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•œ ๋‹ค์Œ์— ์ € ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ด", compose๋Š” "์ € ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•œ ๋‹ค์Œ์— ์ด ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ด"๋ผ๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ€์ ธ์š”. ์ •๋ง ์ง๊ด€์ ์ด์ฃ ? ใ…‹ใ…‹ใ…‹

6. ์ปค๋ง (Currying) ๐Ÿ›

์ปค๋ง์ด๋ผ๋Š” ๋ง, ๋“ค์–ด๋ณด์…จ๋‚˜์š”? ์•„, ์ปค๋ฆฌ ์š”๋ฆฌ ์–˜๊ธฐ๊ฐ€ ์•„๋‹ˆ์—์š”! ใ…‹ใ…‹ใ…‹ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ์ปค๋ง์€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ธ์ž๋ฅผ ๋ฐ›๋Š” ํ•จ์ˆ˜๋ฅผ ๋‹จ์ผ ์ธ์ž๋ฅผ ๋ฐ›๋Š” ํ•จ์ˆ˜๋“ค์˜ ์ฒด์ธ์œผ๋กœ ๋ฐ”๊พธ๋Š” ๊ธฐ๋ฒ•์ด์—์š”.

์Œ... ๋ญ”๊ฐ€ ๋ณต์žกํ•ด ๋ณด์ด์ฃ ? ์˜ˆ์ œ๋ฅผ ๋ณด๋ฉด ๋” ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”:


def add(x: Int)(y: Int) = x + y

val add5 = add(5)_
println(add5(3))  // 8 ์ถœ๋ ฅ

// ์ด๋ ‡๊ฒŒ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”
println(add(2)(3))  // 5 ์ถœ๋ ฅ

์—ฌ๊ธฐ์„œ add ํ•จ์ˆ˜๋Š” ์ปค๋ง๋œ ํ˜•ํƒœ์˜ˆ์š”. ๋‘ ๊ฐœ์˜ ์ธ์ž๋ฅผ ๋”ฐ๋กœ๋”ฐ๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ์ฃ . ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ•จ์ˆ˜์˜ ์ผ๋ถ€๋ถ„๋งŒ ์ ์šฉํ•ด์„œ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ํ•˜๋‚˜์˜ ์žฌ๋Šฅ์„ ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋กœ ๋‚˜๋ˆ„์–ด ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ์š”! ๐Ÿ˜‰

7. ๊ณ ์ฐจ ํ•จ์ˆ˜ (Higher-Order Functions) ๐Ÿš€

๊ณ ์ฐจ ํ•จ์ˆ˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ๋ฐ›๊ฑฐ๋‚˜ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งํ•ด์š”. Scala์—์„œ๋Š” ํ•จ์ˆ˜๋„ ์ผ๊ธ‰ ์‹œ๋ฏผ(first-class citizen)์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋Ÿฐ ๊ณ ์ฐจ ํ•จ์ˆ˜๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ์š”?


def applyTwice(f: Int => Int, x: Int) = f(f(x))

val addOne = (x: Int) => x + 1
println(applyTwice(addOne, 3))  // 5 ์ถœ๋ ฅ (3 + 1 + 1)

val double = (x: Int) => x * 2
println(applyTwice(double, 3))  // 12 ์ถœ๋ ฅ ((3 * 2) * 2)

์—ฌ๊ธฐ์„œ applyTwice๋Š” ๊ณ ์ฐจ ํ•จ์ˆ˜์˜ˆ์š”. ํ•จ์ˆ˜ f์™€ ์ •์ˆ˜ x๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„์„œ, f๋ฅผ x์— ๋‘ ๋ฒˆ ์ ์šฉํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ฃ . ์ •๋ง ๊ฐ•๋ ฅํ•˜๊ณ  ์œ ์—ฐํ•œ ๊ธฐ๋Šฅ์ด์ฃ ? ใ…‹ใ…‹ใ…‹

๐Ÿ’ก ์•Œ์•„๋‘์„ธ์š”: ๋žŒ๋‹ค์™€ ๊ณ ์ฐจ ํ•จ์ˆ˜๋Š” ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ์ด์—์š”. ์ด๋ฅผ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ๋” ๊ฐ„๊ฒฐํ•˜๊ณ , ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ์„ ์กฐํ•ฉํ•ด์„œ ์ƒˆ๋กœ์šด ๊ฐ€์น˜๋ฅผ ๋งŒ๋“ค์–ด๋‚ด๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ !

์ž, ์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ ๋žŒ๋‹ค์™€ ๊ด€๋ จ๋œ ๊ฐœ๋…๋“ค์ด์—ˆ์–ด์š”. ์–ด๋– ์‹ ๊ฐ€์š”? ์กฐ๊ธˆ์€ ๊ฐ์ด ์˜ค์‹œ๋‚˜์š”? ใ…‹ใ…‹ใ…‹ ์ฒ˜์Œ์—๋Š” ์–ด๋ ค์›Œ ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•ด๋ณด๋ฉด ์ •๋ง ํŽธ๋ฆฌํ•˜๊ณ  ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๋ผ๋Š” ๊ฑธ ๋Š๋ผ์‹ค ๊ฑฐ์˜ˆ์š”!

๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ๊ณ ์ฐจ ํƒ€์ž…์˜ ์„ธ๊ณ„๋กœ ๋” ๊นŠ์ด ๋“ค์–ด๊ฐ€๋ณผ ๊ฑฐ์˜ˆ์š”. ๊ณ ์ฐจ ํƒ€์ž…์ด๋ผ... ๋ญ”๊ฐ€ ์ •๋ง ๊ณ ๊ธ‰์ง„ ๋Š๋‚Œ์ด ๋‚˜์ง€ ์•Š๋‚˜์š”? ๊ธฐ๋Œ€๋˜์ง€ ์•Š๋‚˜์š”? ์ €๋Š” ์ •๋ง ์‹ ๋‚˜์š”! ๐ŸŽ‰

๐Ÿšจ ์ฃผ์˜์‚ฌํ•ญ: ๋žŒ๋‹ค์™€ ๊ณ ์ฐจ ํ•จ์ˆ˜๋Š” ์ •๋ง ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์ง€๋งŒ, ๋‚จ์šฉํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ์˜คํžˆ๋ ค ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์–ด์š”. ํ•ญ์ƒ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๊ณ ๋ คํ•ด์„œ ์ ์ ˆํžˆ ์‚ฌ์šฉํ•ด์•ผ ํ•ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋„ˆ๋ฌด ๋งŽ์€ ์žฌ๋Šฅ์„ ํ•œ๊บผ๋ฒˆ์— ์ œ๊ณตํ•˜๋ ค๋‹ค ์˜คํžˆ๋ ค ํ˜ผ๋ž€์„ ์ค„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ . ๊ท ํ˜•์ด ์ค‘์š”ํ•ด์š”! โš–๏ธ

๐ŸŒŒ ๊ณ ์ฐจ ํƒ€์ž…์˜ ์„ธ๊ณ„: ํƒ€์ž…์˜ ์ฐจ์›์„ ๋„˜์–ด์„œ

์ž, ์ด์ œ ์ •๋ง ํฅ๋ฏธ์ง„์ง„ํ•œ ๋ถ€๋ถ„์ด ์™”์–ด์š”! ๊ณ ์ฐจ ํƒ€์ž…์˜ ์„ธ๊ณ„๋กœ ๋“ค์–ด๊ฐ€๋ณผ ์‹œ๊ฐ„์ด์—์š”. ๊ณ ์ฐจ ํƒ€์ž…์ด๋ผ... ๋ญ”๊ฐ€ ์ •๋ง ๊ณ ์ฐจ์›์ ์ธ ๋Š๋‚Œ์ด ๋“ค์ง€ ์•Š๋‚˜์š”? ใ…‹ใ…‹ใ…‹ ๊ฑฑ์ • ๋งˆ์„ธ์š”, ์ฒœ์ฒœํžˆ ์„ค๋ช…ํ•ด๋“œ๋ฆด๊ฒŒ์š”!

๐ŸŒ  ์•Œ์•„๋‘์„ธ์š”: ๊ณ ์ฐจ ํƒ€์ž…(Higher-kinded types)์€ ํƒ€์ž… ์ƒ์„ฑ์ž๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š” ํƒ€์ž…์„ ๋งํ•ด์š”. ์Œ... ๋ญ”๊ฐ€ ๋ณต์žกํ•ด ๋ณด์ด์ฃ ? ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ด๋ฏธ ์•Œ๊ณ  ์žˆ๋Š” ๊ฐœ๋…์˜ ํ™•์žฅ์ผ ๋ฟ์ด์—์š”!

1. ํƒ€์ž… ์ƒ์„ฑ์ž (Type Constructors) ๐Ÿ—๏ธ

๊ณ ์ฐจ ํƒ€์ž…์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋จผ์ € ํƒ€์ž… ์ƒ์„ฑ์ž์— ๋Œ€ํ•ด ์•Œ์•„์•ผ ํ•ด์š”. ํƒ€์ž… ์ƒ์„ฑ์ž๋Š” ๋‹ค๋ฅธ ํƒ€์ž…์„ ์ธ์ž๋กœ ๋ฐ›์•„ ์ƒˆ๋กœ์šด ํƒ€์ž…์„ ๋งŒ๋“œ๋Š” 'ํ•จ์ˆ˜'๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ผ์š”.

์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ์š”?


List[A]
Option[A]
Map[K, V]

์—ฌ๊ธฐ์„œ List, Option, Map์€ ๋ชจ๋‘ ํƒ€์ž… ์ƒ์„ฑ์ž์˜ˆ์š”. ์ด๋“ค์€ ๋‹ค๋ฅธ ํƒ€์ž…(A, K, V ๋“ฑ)์„ ๋ฐ›์•„์„œ ๊ตฌ์ฒด์ ์ธ ํƒ€์ž…์„ ๋งŒ๋“ค์–ด๋‚ด์ฃ .

2. ๊ณ ์ฐจ ํƒ€์ž…์˜ ๊ธฐ๋ณธ ๊ฐœ๋… ๐Ÿš€

์ž, ์ด์ œ ๊ณ ์ฐจ ํƒ€์ž…์œผ๋กœ ๋„˜์–ด๊ฐ€๋ณผ๊นŒ์š”? ๊ณ ์ฐจ ํƒ€์ž…์€ ์ด๋Ÿฐ ํƒ€์ž… ์ƒ์„ฑ์ž๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š” ํƒ€์ž…์ด์—์š”. Scala์—์„œ๋Š” ์ด๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ‘œํ˜„ํ•ด์š”:


trait HigherKinded[F[_]]

์—ฌ๊ธฐ์„œ F[_]๋Š” ์ž„์˜์˜ ํƒ€์ž… ์ƒ์„ฑ์ž๋ฅผ ๋‚˜ํƒ€๋‚ด์š”. ๋ฐ‘์ค„(_)์€ "์•„์ง ์ •ํ•ด์ง€์ง€ ์•Š์€ ํƒ€์ž…"์„ ์˜๋ฏธํ•˜์ฃ .

์‹ค์ œ ์˜ˆ์ œ๋ฅผ ๋ณผ๊นŒ์š”?


trait Functor[F[_]] {
  def map[A, B](fa: F[A])(f: A => B): F[B]
}

// List์— ๋Œ€ํ•œ Functor ๊ตฌํ˜„
implicit val listFunctor: Functor[List] = new Functor[List] {
  def map[A, B](fa: List[A])(f: A => B): List[B] = fa.map(f)
}

// Option์— ๋Œ€ํ•œ Functor ๊ตฌํ˜„
implicit val optionFunctor: Functor[Option] = new Functor[Option] {
  def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
}

์™€์šฐ! ์ด๊ฒŒ ๋ฐ”๋กœ ๊ณ ์ฐจ ํƒ€์ž…์˜ ํž˜์ด์—์š”. Functor๋ผ๋Š” ํ•˜๋‚˜์˜ ํŠธ๋ ˆ์ดํŠธ๋กœ List์™€ Option ๋ชจ๋‘๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์ฃ . ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ํ•˜๋‚˜์˜ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ์š”! ๐Ÿ˜Ž

3. ๊ณ ์ฐจ ํƒ€์ž…์˜ ํ™œ์šฉ ๐Ÿ› ๏ธ

๊ณ ์ฐจ ํƒ€์ž…์„ ํ™œ์šฉํ•˜๋ฉด ์ •๋ง ๊ฐ•๋ ฅํ•œ ์ถ”์ƒํ™”๋ฅผ ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ชจ๋‚˜๋“œ(Monad)๋ผ๋Š” ๊ฐœ๋…์„ ๊ตฌํ˜„ํ•  ๋•Œ ๊ณ ์ฐจ ํƒ€์ž…์ด ์‚ฌ์šฉ๋ผ์š”.


trait Monad[F[_]] extends Functor[F] {
  def pure[A](a: A): F[A]
  def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
}

// List์— ๋Œ€ํ•œ Monad ๊ตฌํ˜„
implicit val listMonad: Monad[List] = new Monad[List] {
  def pure[A](a: A): List[A] = List(a)
  def flatMap[A, B](fa: List[A])(f: A => List[B]): List[B] = fa.flatMap(f)
  def map[A, B](fa: List[A])(f: A => B): List[B] = fa.map(f)
}

// Option์— ๋Œ€ํ•œ Monad ๊ตฌํ˜„
implicit val optionMonad: Monad[Option] = new Monad[Option] {
  def pure[A](a: A): Option[A] = Some(a)
  def flatMap[A, B](fa: Option[A])(f: A => Option[B]): Option[B] = fa.flatMap(f)
  def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด List์™€ Option์— ๋Œ€ํ•ด ๋™์ผํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ •๋ง ๋ฉ‹์ง€์ง€ ์•Š๋‚˜์š”? ใ…‹ใ…‹ใ…‹

4. ํƒ€์ž… ๋žŒ๋‹ค (Type Lambdas) ๐ŸŽญ

Scala์—์„œ๋Š” ํƒ€์ž… ์ˆ˜์ค€์—์„œ๋„ ๋žŒ๋‹ค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ด๋ฅผ ํƒ€์ž… ๋žŒ๋‹ค๋ผ๊ณ  ํ•ด์š”. ํƒ€์ž… ๋žŒ๋‹ค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋” ๋ณต์žกํ•œ ํƒ€์ž… ๊ตฌ์กฐ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์ฃ .

์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ์š”?


type Compose[F[_], G[_]] = ({type ฮป[ฮฑ] = F[G[ฮฑ]]})#ฮป

// ์‚ฌ์šฉ ์˜ˆ
val listOption: Compose[List, Option] = List(Some(1), None, Some(2))

์—ฌ๊ธฐ์„œ Compose๋Š” ๋‘ ๊ฐœ์˜ ํƒ€์ž… ์ƒ์„ฑ์ž๋ฅผ ๋ฐ›์•„์„œ ์ƒˆ๋กœ์šด ํƒ€์ž… ์ƒ์„ฑ์ž๋ฅผ ๋งŒ๋“ค์–ด๋‚ด์š”. ๋งˆ์น˜ ํ•จ์ˆ˜๋ฅผ ํ•ฉ์„ฑํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ํƒ€์ž…์„ ํ•ฉ์„ฑํ•˜๋Š” ๊ฑฐ์ฃ !

5. ์ข…์† ํƒ€์ž… (Dependent Types) ๐Ÿ”—

Scala์—์„œ๋Š” ํƒ€์ž…์ด ๊ฐ’์— ์˜์กดํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ด๋ฅผ ์ข…์† ํƒ€์ž…์ด๋ผ๊ณ  ํ•ด์š”. ์ด ๊ฐœ๋…์€ ์ •๋ง ๊ฐ•๋ ฅํ•œ ํƒ€์ž… ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ์ฃ .

๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ๋ณผ๊นŒ์š”?


trait Vec {
  type T
  def length: Int
  def apply(i: Int): T
}

object Vec {
  def apply[A](xs: A*): Vec = new Vec {
    type T = A
    def length: Int = xs.length
    def apply(i: Int): A = xs(i)
  }
}

val v = Vec(1, 2, 3)
println(v.length)  // 3
println(v(1))      // 2

์—ฌ๊ธฐ์„œ Vec์˜ T ํƒ€์ž…์€ ์ƒ์„ฑ ์‹œ์ ์— ๊ฒฐ์ •๋ผ์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ์ฃ !

6. ํƒ€์ž… ํด๋ž˜์Šค (Type Classes) ๐Ÿ“š

ํƒ€์ž… ํด๋ž˜์Šค๋Š” Scala์—์„œ ๊ณ ์ฐจ ํƒ€์ž…์„ ํ™œ์šฉํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด์—์š”. ํƒ€์ž… ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ธฐ์กด ํƒ€์ž…์— ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์ฃ .

์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ์š”?


trait Show[A] {
  def show(a: A): String
}

implicit val intShow: Show[Int] = new Show[Int] {
  def show(a: Int): String = a.toString
}

implicit val stringShow: Show[String] = new Show[String] {
  def show(a: String): String = a
}

def showOff[A](a: A)(implicit s: Show[A]): String = s.show(a)

println(showOff(123))       // "123"
println(showOff("Hello"))   // "Hello"

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Int์™€ String์— ๋Œ€ํ•ด show ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์€ ํšจ๊ณผ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ์–ด์š”. ์ •๋ง ์œ ์—ฐํ•˜์ฃ ? ใ…‹ใ…‹ใ…‹

๐Ÿ’ก Pro Tip: ๊ณ ์ฐจ ํƒ€์ž…๊ณผ ํƒ€์ž… ํด๋ž˜์Šค๋ฅผ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ํ™•์žฅ์„ฑ์„ ํฌ๊ฒŒ ๋†’์ผ ์ˆ˜ ์žˆ์–ด์š”. ํ•˜์ง€๋งŒ ๋„ˆ๋ฌด ๋ณต์žกํ•œ ํƒ€์ž… ๊ตฌ์กฐ๋Š” ์˜คํžˆ๋ ค ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์„ ํ•ด์น  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฃผ์˜ํ•ด์•ผ ํ•ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋„ˆ๋ฌด ๋ณต์žกํ•œ ์„œ๋น„์Šค ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ !

์ž, ์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ ๊ณ ์ฐจ ํƒ€์ž…์˜ ์„ธ๊ณ„์˜€์–ด์š”. ์–ด๋– ์‹ ๊ฐ€์š”? ์กฐ๊ธˆ์€ ๋จธ๋ฆฌ๊ฐ€ ์•„ํ”„์‹ ๊ฐ€์š”? ใ…‹ใ…‹ใ…‹ ๊ฑฑ์ • ๋งˆ์„ธ์š”. ์ด๋Ÿฐ ๊ฐœ๋…๋“ค์€ ์‹œ๊ฐ„์„ ๋‘๊ณ  ์ฒœ์ฒœํžˆ ์ดํ•ดํ•ด ๋‚˜๊ฐ€๋ฉด ๋ผ์š”. ์ฒ˜์Œ๋ถ€ํ„ฐ ์™„๋ฒฝํ•˜๊ฒŒ ์ดํ•ดํ•˜๋ ค๊ณ  ํ•˜์ง€ ๋งˆ์„ธ์š”!

๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์ด ๋ชจ๋“  ๊ฐœ๋…๋“ค์„ ์ข…ํ•ฉํ•ด์„œ ์‹ค์ œ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณผ ๊ฑฐ์˜ˆ์š”. ๊ธฐ๋Œ€๋˜์ง€ ์•Š๋‚˜์š”? ์ €๋Š” ์ •๋ง ์‹ ๋‚˜์š”! ๐ŸŽ‰

๐Ÿšจ ์ฃผ์˜์‚ฌํ•ญ: ๊ณ ์ฐจ ํƒ€์ž…๊ณผ ๊ด€๋ จ๋œ ๊ฐœ๋…๋“ค์€ ์ •๋ง ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ๊ทธ๋งŒํผ ๋ณต์žกํ•  ์ˆ˜ ์žˆ์–ด์š”. ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•  ๋•Œ๋Š” ํŒ€์›๋“ค๊ณผ ์ถฉ๋ถ„ํžˆ ์ƒ์˜ํ•˜๊ณ , ์ฝ”๋“œ์˜ ๋ณต์žก์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ์ž˜ ๊ณ ๋ คํ•ด์•ผ ํ•ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ๋„์ž…ํ•  ๋•Œ ์‚ฌ์šฉ์ž์˜ ํŽธ์˜์„ฑ๊ณผ ์‹œ์Šคํ…œ์˜ ๋ณต์žก์„ฑ์„ ์ž˜ ๊ท ํ˜• ์žก์•„์•ผ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ ! ๐Ÿ’ช

๐ŸŽฉ ํƒ€์ž… ๋žŒ๋‹ค์˜ ๋งˆ๋ฒ•: ๊ณ ๊ธ‰ ํƒ€์ž… ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์ •์ˆ˜

์ž, ์ด์ œ ์ •๋ง ํฅ๋ฏธ์ง„์ง„ํ•œ ๋ถ€๋ถ„์ด ์™”์–ด์š”! ํƒ€์ž… ๋žŒ๋‹ค์˜ ์„ธ๊ณ„๋กœ ๋“ค์–ด๊ฐ€๋ณผ ์‹œ๊ฐ„์ด์—์š”. ํƒ€์ž… ๋žŒ๋‹ค๋ผ... ๋ญ”๊ฐ€ ์ •๋ง ๋งˆ๋ฒ• ๊ฐ™์€ ๋Š๋‚Œ์ด ๋“ค์ง€ ์•Š๋‚˜์š”? ใ…‹ใ…‹ใ…‹ ๊ฑฑ์ • ๋งˆ์„ธ์š”, ์ฒœ์ฒœํžˆ ์„ค๋ช…ํ•ด๋“œ๋ฆด๊ฒŒ์š”!

๐ŸŽญ ์•Œ์•„๋‘์„ธ์š”: ํƒ€์ž… ๋žŒ๋‹ค๋Š” ํƒ€์ž… ์ˆ˜์ค€์—์„œ์˜ ์ต๋ช… ํ•จ์ˆ˜์˜ˆ์š”. ๊ฐ’ ์ˆ˜์ค€์˜ ๋žŒ๋‹ค์™€ ๋น„์Šทํ•˜์ง€๋งŒ, ํƒ€์ž…์„ ๋‹ค๋ฃจ๋Š” ๋ฐ ์‚ฌ์šฉ๋ผ์š”. ์ •๋ง ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์ฃ !

1. ํƒ€์ž… ๋žŒ๋‹ค์˜ ๊ธฐ๋ณธ ๋ฌธ๋ฒ• ๐Ÿ“

Scala์—์„œ ํƒ€์ž… ๋žŒ๋‹ค์˜ ๊ธฐ๋ณธ ๋ฌธ๋ฒ•์€ ์กฐ๊ธˆ ํŠน์ดํ•ด์š”. ์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ์š”?


type Lambda[A] = ({type L[X] = Either[A, X]})#L

์ด๊ฒŒ ๋ฐ”๋กœ ํƒ€์ž… ๋žŒ๋‹ค์˜ˆ์š”! Either[A, X]๋ฅผ X์— ๋Œ€ํ•œ ํ•จ์ˆ˜๋กœ ํ‘œํ˜„ํ•œ ๊ฑฐ์ฃ . ์Œ... ์กฐ๊ธˆ ๋ณต์žกํ•ด ๋ณด์ด๋‚˜์š”? ใ…‹ใ…‹ใ…‹ ๊ฑฑ์ • ๋งˆ์„ธ์š”, ์‚ฌ์šฉ ์˜ˆ์ œ๋ฅผ ๋ณด๋ฉด ๋” ์ดํ•ด๊ฐ€ ์ž˜ ๋  ๊ฑฐ์˜ˆ์š”!

2. ํƒ€์ž… ๋žŒ๋‹ค์˜ ํ™œ์šฉ ๐Ÿ› ๏ธ

ํƒ€์ž… ๋žŒ๋‹ค๋Š” ์ฃผ๋กœ ๊ณ ์ฐจ ํƒ€์ž…์„ ๋‹ค๋ฃฐ ๋•Œ ์‚ฌ์šฉ๋ผ์š”. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์„ ์ƒ๊ฐํ•ด๋ณผ๊นŒ์š”?


trait Functor[F[_]] {
  def map[A, B](fa: F[A])(f: A => B): F[B]
}

// Either[String, ?]์— ๋Œ€ํ•œ Functor ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๋ฉด?
implicit val eitherStringFunctor: Functor[({type L[X] = Either[String, X]})#L] =
  new Functor[({type L[X] = Either[String, X]})#L] {
    def map[A, B](fa: Either[String, A])(f: A => B): Either[String, B] = fa.map(f)
  }

์™€์šฐ! ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Either[String, ?]์— ๋Œ€ํ•œ Functor ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”. ํƒ€์ž… ๋žŒ๋‹ค์˜ ๋งˆ๋ฒ•์ด์ฃ ! ใ…‹ใ…‹ใ…‹

3. ํƒ€์ž… ํ”„๋กœ์ ์…˜ (Type Projection) ๐ŸŽฅ

Scala์—์„œ๋Š” ํƒ€์ž… ํ”„๋กœ์ ์…˜์ด๋ผ๋Š” ๊ธฐ๋Šฅ๋„ ์ œ๊ณตํ•ด์š”. ์ด๋ฅผ ์ด์šฉํ•˜๋ฉด ํƒ€์ž… ๋žŒ๋‹ค๋ฅผ ์กฐ๊ธˆ ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์ฃ .


trait Foo {
  type T
  def value: T
}

object Foo {
  type Aux[A] = Foo { type T = A }
  
  def apply[A](a: A): Aux[A] = new Foo {
    type T = A
    def value: A = a
  }
}

val foo: Foo.Aux[Int] = Foo(42)
println(foo.value)  // 42

์—ฌ๊ธฐ์„œ Foo.Aux[A]๋Š” T๊ฐ€ A๋กœ ๊ณ ์ •๋œ Foo๋ฅผ ๋‚˜ํƒ€๋‚ด์š”. ์ด๋Ÿฐ ์‹์œผ๋กœ ํƒ€์ž…์„ ์ •๊ตํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค!

4. ํƒ€์ž… ๋žŒ๋‹ค์™€ ์•”์‹œ์  ๋ณ€ํ™˜ (Implicit Conversion) ๐Ÿ”„

ํƒ€์ž… ๋žŒ๋‹ค๋Š” ์•”์‹œ์  ๋ณ€ํ™˜๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ๋”์šฑ ๊ฐ•๋ ฅํ•ด์ ธ์š”. ์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ์š”?


trait Monoid[A] {
  def empty: A
  def combine(x: A, y: A): A
}

implicit def eitherMonoid[A, B](implicit ma: Monoid[A], mb: Monoid[B]): Monoid[Either[A, B]] =
  new Monoid[Either[A, B]] {
    def empty: Either[A, B] = Left(ma.empty)
    def combine(x: Either[A, B], y: Either[A, B]): Either[A, B] =
      (x, y) match {
        case (Left(a1), Left(a2)) => Left(ma.combine(a1, a2))
        case (Right(b1), Right(b2)) => Right(mb.combine(b1, b2))
        case (Left(_), Right(b)) => Right(b)
        case (Right(b), Left(_)) => Right(b)
      }
  }

// ์‚ฌ์šฉ ์˜ˆ
implicit val intMonoid: Monoid[Int] = new Monoid[Int] {
  def empty: Int = 0
  def combine(x: Int, y: Int): Int = x + y
}

implicit val stringMonoid: Monoid[String] = new Monoid[String] {
  def empty: String = ""
  def combine(x: String, y: String): String = x + y
}

val result = implicitly[Monoid[Either[Int, String]]].combine(Left(10), Right("Hello"))
println(result)  // Right("Hello")

์™€! ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Either[Int, String]์— ๋Œ€ํ•œ Monoid ์ธ์Šคํ„ด์Šค๋ฅผ ์ž๋™์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”. ์ •๋ง ๊ฐ•๋ ฅํ•˜์ฃ ? ใ…‹ใ…‹ใ…‹

5. ํƒ€์ž… ๋žŒ๋‹ค์™€ ํƒ€์ž… ํด๋ž˜์Šค (Type Classes) ๐Ÿ“š

ํƒ€์ž… ๋žŒ๋‹ค๋Š” ํƒ€์ž… ํด๋ž˜์Šค์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ๋”์šฑ ์œ ์—ฐํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด์š”. ์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ์š”?


trait Applicative[F[_]] extends Functor[F] {
  def pure[A](a: A): F[A]
  def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
}

// Either์— ๋Œ€ํ•œ Applicative ์ธ์Šคํ„ด์Šค
implicit def eitherApplicative[E]: Applicative[({type L[A] = Either[E, A]})#L] =
  new Applicative[({type L[A] = Either[E, A]})#L] {
    def pure[A](a: A): Either[E, A] = Right(a)
    def ap[A, B](ff: Either[E, A => B])(fa: Either[E, A]): Either[E, B] =
      (ff, fa) match {
        case (Right(f), Right(a)) => Right(f(a))
        case (Left(e), _) => Left(e)
        case (_, Left(e)) => Left(e)
      }
    def map[A, B](fa: Either[E, A])(f: A => B): Either[E, B] = fa.map(f)
  }

// ์‚ฌ์šฉ ์˜ˆ
val result = eitherApplicative[String].pure(5).map(_ * 2)
println(result)  // Right(10)

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Either[E, ?]์— ๋Œ€ํ•œ Applicative ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”. ํƒ€์ž… ๋žŒ๋‹ค์™€ ํƒ€์ž… ํด๋ž˜์Šค์˜ ํ™˜์ƒ์ ์ธ ์กฐํ•ฉ์ด์ฃ ! ใ…‹ใ…‹ใ…‹

๐Ÿ’ก Pro Tip: ํƒ€์ž… ๋žŒ๋‹ค๋Š” ์ •๋ง ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์ง€๋งŒ, ๋‚จ์šฉํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์–ด์š”. ํ•ญ์ƒ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๊ณ ๋ คํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋„ˆ๋ฌด ๋ณต์žกํ•œ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ !

์ž, ์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ ํƒ€์ž… ๋žŒ๋‹ค์˜ ๋งˆ๋ฒ•์ด์—ˆ์–ด์š”. ์–ด๋– ์‹ ๊ฐ€์š”? ์กฐ๊ธˆ์€ ํ˜„๊ธฐ์ฆ์ด ๋‚˜์‹œ๋‚˜์š”? ใ…‹ใ…‹ใ…‹ ๊ฑฑ์ • ๋งˆ์„ธ์š”. ์ด๋Ÿฐ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์€ ์‹œ๊ฐ„์„ ๋‘๊ณ  ์ฒœ์ฒœํžˆ ์ตํ˜€๋‚˜๊ฐ€๋ฉด ๋ผ์š”. ์ฒ˜์Œ๋ถ€ํ„ฐ ์™„๋ฒฝํ•˜๊ฒŒ ์ดํ•ดํ•˜๋ ค๊ณ  ํ•˜์ง€ ๋งˆ์„ธ์š”!

๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์ด ๋ชจ๋“  ๊ฐœ๋…๋“ค์„ ์ข…ํ•ฉํ•ด์„œ ์‹ค์ „ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณผ ๊ฑฐ์˜ˆ์š”. ๊ธฐ๋Œ€๋˜์ง€ ์•Š๋‚˜์š”? ์ €๋Š” ์ •๋ง ์‹ ๋‚˜์š”! ๐ŸŽ‰

๐Ÿšจ ์ฃผ์˜์‚ฌํ•ญ: ํƒ€์ž… ๋žŒ๋‹ค์™€ ๊ด€๋ จ๋œ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์€ ์ •๋ง ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ๊ทธ๋งŒํผ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์–ด์š”. ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•  ๋•Œ๋Š” ํŒ€์›๋“ค๊ณผ ์ถฉ๋ถ„ํžˆ ์ƒ์˜ํ•˜๊ณ , ์ฝ”๋“œ์˜ ๋ณต์žก์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ์ž˜ ๊ณ ๋ คํ•ด์•ผ ํ•ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ƒˆ๋กœ์šด ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ์„ ๋„์ž…ํ•  ๋•Œ ์‚ฌ์šฉ์ž์˜ ํŽธ์˜์„ฑ๊ณผ ์‹œ์Šคํ…œ์˜ ๋ณต์žก์„ฑ์„ ์ž˜ ๊ท ํ˜• ์žก์•„์•ผ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ ! ๐Ÿ’ช

๐Ÿš€ ์‹ค์ „ ์˜ˆ์ œ์™€ ํ™œ์šฉ: ์ด๋ก ์„ ํ˜„์‹ค๋กœ!

์ž, ์ด์ œ ์šฐ๋ฆฌ๊ฐ€ ๋ฐฐ์šด ๋ชจ๋“  ๊ฐœ๋…๋“ค์„ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณผ ์‹œ๊ฐ„์ด์—์š”! ํฅ๋ฏธ์ง„์ง„ํ•˜์ง€ ์•Š๋‚˜์š”? ใ…‹ใ…‹ใ…‹ ์ œ ์‹ฌ์žฅ์ด ๋ฒŒ์จ๋ถ€ํ„ฐ ๋‘๊ทผ๋‘๊ทผ๊ฑฐ๋ ค์š”!

๐ŸŒฑ ์•Œ์•„๋‘์„ธ์š”: ์‹ค์ „ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ๋ฐฐ์šฐ๋Š” ๊ฒƒ๋งŒํผ ํšจ๊ณผ์ ์ธ ํ•™์Šต ๋ฐฉ๋ฒ•์€ ์—†์–ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์‹ค์ œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด์„œ ์‹ค๋ ฅ์ด ๋Š˜์–ด๋‚˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ !

1. ํƒ€์ž… ์•ˆ์ „ํ•œ HTTP ํด๋ผ์ด์–ธํŠธ ๋งŒ๋“ค๊ธฐ ๐ŸŒ

๋จผ์ €, ํƒ€์ž… ๋žŒ๋‹ค์™€ ๊ณ ์ฐจ ํƒ€์ž…์„ ํ™œ์šฉํ•ด์„œ ํƒ€์ž… ์•ˆ์ „ํ•œ HTTP ํด๋ผ์ด์–ธํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊นŒ์š”?


import scala.concurrent.Future

// HTTP ๋ฉ”์„œ๋“œ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” sealed trait
sealed trait HttpMethod
case object GET extends HttpMethod
case object POST extends HttpMethod

// HTTP ์‘๋‹ต์„ ํ‘œํ˜„ํ•˜๋Š” case class
case class HttpResponse[A](statusCode: Int, body: A)

// HTTP ํด๋ผ์ด์–ธํŠธ ํŠธ๋ ˆ์ดํŠธ
trait HttpClient {
  def request[A](method: HttpMethod, url: String, body: Option[String] = None): Future[HttpResponse[A]]
}

// ํƒ€์ž… ์•ˆ์ „ํ•œ API ์ •์˜
trait Api {
  type Result[A]
  
  def get[A](url: String): Result[A]
  def post[A](url: String, body: String): Result[A]
}

// HttpClient๋ฅผ ์ด์šฉํ•œ Api ๊ตฌํ˜„
class HttpApi(client: HttpClient) extends Api {
  type Result[A] = Future[HttpResponse[A]]
  
  def get[A](url: String): Result[A] = client.request[A](GET, url)
  def post[A](url: String, body: String): Result[A] = client.request[A](POST, url, Some(body))
}

// ์‚ฌ์šฉ ์˜ˆ
import scala.concurrent.ExecutionContext.Implicits.global

val api: Api = new HttpApi(new HttpClient {
  def request[A](method: HttpMethod, url: String, body: Option[String]): Future[HttpResponse[A]] =
    Future.successful(HttpResponse(200, "Response body".asInstanceOf[A]))
})

api.get[String]("https://example.com").foreach(println)
api.post[String]("https://example.com", "Hello, World!").foreach(println)

์™€์šฐ! ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํƒ€์ž… ์•ˆ์ „ํ•œ HTTP ํด๋ผ์ด์–ธํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”. Result[A]๋ฅผ ์ถ”์ƒ ํƒ€์ž… ๋ฉค๋ฒ„๋กœ ์ •์˜ํ•จ์œผ๋กœ์จ, ๊ตฌ์ฒด์ ์ธ ๊ตฌํ˜„์„ ๋‚˜์ค‘์— ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ์ฃ . ์ •๋ง ์œ ์—ฐํ•˜๊ณ  ๊ฐ•๋ ฅํ•˜์ง€ ์•Š๋‚˜์š”? ใ…‹ใ…‹ใ…‹

2. ํƒ€์ž… ํด๋ž˜์Šค๋ฅผ ํ™œ์šฉํ•œ JSON ์ธ์ฝ”๋”ฉ/๋””์ฝ”๋”ฉ ๐Ÿ”„

์ด๋ฒˆ์—๋Š” ํƒ€์ž… ํด๋ž˜์Šค๋ฅผ ํ™œ์šฉํ•ด์„œ JSON ์ธ์ฝ”๋”ฉ/๋””์ฝ”๋”ฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊นŒ์š”?


// JSON ๊ฐ’์„ ํ‘œํ˜„ํ•˜๋Š” sealed trait
sealed trait Json
case class JString(value: String) extends Json
case class JNumber(value: Double) extends Json
case class JBoolean(value: Boolean) extends Json
case class JObject(value: Map[String, Json]) extends Json
case class JArray(value: List[Json]) extends Json
case object JNull extends Json

// JSON ์ธ์ฝ”๋”ฉ์„ ์œ„ํ•œ ํƒ€์ž… ํด๋ž˜์Šค
trait JsonEncoder[A] {
  def encode(value: A): Json
}

// JSON ๋””์ฝ”๋”ฉ์„ ์œ„ํ•œ ํƒ€์ž… ํด๋ž˜์Šค
trait JsonDecoder[A] {
  def decode(json: Json): Either[String, A]
}

// ํƒ€์ž… ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋“ค
object JsonInstances {
  implicit val stringEncoder: JsonEncoder[String] = new JsonEncoder[String] {
    def encode(value: String): Json = JString(value)
  }
  
  implicit val intEncoder: JsonEncoder[Int] = new JsonEncoder[Int] {
    def encode(value: Int): Json = JNumber(value.toDouble)
  }
  
  implicit val stringDecoder: JsonDecoder[String] = new JsonDecoder[String] {
    def decode(json: Json): Either[String, String] = json match {
      case JString(value) => Right(value)
      case _ => Left("Not a string")
    }
  }
  
  implicit val intDecoder: JsonDecoder[Int] = new JsonDecoder[Int] {
    def decode(json: Json): Either[String, Int] = json match {
      case JNumber(value) => Right(value.toInt)
      case _ => Left("Not a number")
    }
  }
}

// ์‚ฌ์šฉ์„ ์œ„ํ•œ Syntax
object JsonSyntax {
  implicit class JsonEncoderOps[A](value: A) {
    def toJson(implicit encoder: JsonEncoder[A]): Json = encoder.encode(value)
  }
  
  implicit class JsonDecoderOps(json: Json) {
    def as[A](implicit decoder: JsonDecoder[A]): Either[String, A] = decoder.decode(json)
  }
}

// ์‚ฌ์šฉ ์˜ˆ
import JsonInstances._
import JsonSyntax._

val jsonString = "Hello, World!".toJson
println(jsonString)  // JString("Hello, World!")

val decodedString = jsonString.as[  String]
println(decodedString)  // Right("Hello, World!")

val jsonInt = 42.toJson
println(jsonInt)  // JNumber(42.0)

val decodedInt = jsonInt.as[Int]
println(decodedInt)  // Right(42)

์™€! ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํƒ€์ž… ์•ˆ์ „ํ•œ JSON ์ธ์ฝ”๋”ฉ/๋””์ฝ”๋”ฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”. ํƒ€์ž… ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ๊ธฐ์กด ํƒ€์ž…์— ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์ฃ . ์ •๋ง ๋ฉ‹์ง€์ง€ ์•Š๋‚˜์š”? ใ…‹ใ…‹ใ…‹

3. ๊ณ ์ฐจ ํƒ€์ž…์„ ํ™œ์šฉํ•œ ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜ ํŒŒ์ดํ”„๋ผ์ธ ๐Ÿšฐ

์ด๋ฒˆ์—๋Š” ๊ณ ์ฐจ ํƒ€์ž…์„ ํ™œ์šฉํ•ด์„œ ์œ ์—ฐํ•œ ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜ ํŒŒ์ดํ”„๋ผ์ธ์„ ๋งŒ๋“ค์–ด๋ณผ๊นŒ์š”?


// ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜์„ ์œ„ํ•œ ํƒ€์ž… ํด๋ž˜์Šค
trait Transformer[F[_]] {
  def transform[A, B](fa: F[A])(f: A => B): F[B]
}

// Option์— ๋Œ€ํ•œ Transformer ์ธ์Šคํ„ด์Šค
implicit val optionTransformer: Transformer[Option] = new Transformer[Option] {
  def transform[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
}

// List์— ๋Œ€ํ•œ Transformer ์ธ์Šคํ„ด์Šค
implicit val listTransformer: Transformer[List] = new Transformer[List] {
  def transform[A, B](fa: List[A])(f: A => B): List[B] = fa.map(f)
}

// Either์— ๋Œ€ํ•œ Transformer ์ธ์Šคํ„ด์Šค
implicit def eitherTransformer[E]: Transformer[({type L[A] = Either[E, A]})#L] =
  new Transformer[({type L[A] = Either[E, A]})#L] {
    def transform[A, B](fa: Either[E, A])(f: A => B): Either[E, B] = fa.map(f)
  }

// ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜ ํŒŒ์ดํ”„๋ผ์ธ
class Pipeline[F[_]: Transformer, A] private (val data: F[A]) {
  def map[B](f: A => B): Pipeline[F, B] = {
    val transformer = implicitly[Transformer[F]]
    new Pipeline(transformer.transform(data)(f))
  }
}

object Pipeline {
  def apply[F[_]: Transformer, A](data: F[A]): Pipeline[F, A] = new Pipeline(data)
}

// ์‚ฌ์šฉ ์˜ˆ
val optionPipeline = Pipeline(Option("Hello, World!"))
  .map(_.toUpperCase)
  .map(_.length)

println(optionPipeline.data)  // Some(13)

val listPipeline = Pipeline(List(1, 2, 3, 4, 5))
  .map(_ * 2)
  .map(_.toString)

println(listPipeline.data)  // List("2", "4", "6", "8", "10")

val eitherPipeline = Pipeline[({type L[A] = Either[String, A]})#L, Int](Right(10))
  .map(_ + 5)
  .map(_ * 2)

println(eitherPipeline.data)  // Right(30)

์™€์šฐ! ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‹ค์–‘ํ•œ ์ปจํ…Œ์ด๋„ˆ ํƒ€์ž…(Option, List, Either ๋“ฑ)์— ๋Œ€ํ•ด ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ํŒŒ์ดํ”„๋ผ์ธ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”. ๊ณ ์ฐจ ํƒ€์ž…๊ณผ ํƒ€์ž… ํด๋ž˜์Šค์˜ ํž˜์„ ์ œ๋Œ€๋กœ ๋ณด์—ฌ์ฃผ๋Š” ์˜ˆ์ œ์ฃ ! ใ…‹ใ…‹ใ…‹

4. ํƒ€์ž… ๋žŒ๋‹ค๋ฅผ ํ™œ์šฉํ•œ ์˜์กด์„ฑ ์ฃผ์ž… ๐Ÿ’‰

๋งˆ์ง€๋ง‰์œผ๋กœ, ํƒ€์ž… ๋žŒ๋‹ค๋ฅผ ํ™œ์šฉํ•ด์„œ ํƒ€์ž… ์•ˆ์ „ํ•œ ์˜์กด์„ฑ ์ฃผ์ž… ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค์–ด๋ณผ๊นŒ์š”?


// ์˜์กด์„ฑ์„ ํ‘œํ˜„ํ•˜๋Š” ํƒ€์ž…
trait Dependency[A] {
  def get: A
}

// ์˜์กด์„ฑ ์ฃผ์ž… ์ปจํ…์ŠคํŠธ
trait Context {
  type M[A] = Dependency[A]
  
  def provide[A](a: => A): M[A] = new Dependency[A] {
    lazy val get: A = a
  }
}

// ์„œ๋น„์Šค ์ •์˜
trait UserService {
  def getUser(id: Int): String
}

trait EmailService {
  def sendEmail(to: String, body: String): Unit
}

// ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ •์˜
trait Application { self: Context =>
  val userService: M[UserService]
  val emailService: M[EmailService]
  
  def run(): Unit = {
    val user = userService.get.getUser(1)
    emailService.get.sendEmail(user, "Hello!")
  }
}

// ์‹ค์ œ ๊ตฌํ˜„
object RealContext extends Context {
  val userService: M[UserService] = provide(new UserService {
    def getUser(id: Int): String = s"User$id"
  })
  
  val emailService: M[EmailService] = provide(new EmailService {
    def sendEmail(to: String, body: String): Unit =
      println(s"Sending email to $to: $body")
  })
}

// ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰
object MyApp extends Application with RealContext

MyApp.run()

์™€! ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํƒ€์ž… ์•ˆ์ „ํ•œ ์˜์กด์„ฑ ์ฃผ์ž… ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”. M[A]๋ผ๋Š” ํƒ€์ž… ๋žŒ๋‹ค๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์˜์กด์„ฑ์„ ํ‘œํ˜„ํ•˜๊ณ , ์ปจํ…์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์˜์กด์„ฑ์„ ์ œ๊ณตํ•˜์ฃ . ์ •๋ง ์šฐ์•„ํ•˜์ง€ ์•Š๋‚˜์š”? ใ…‹ใ…‹ใ…‹

๐Ÿ’ก Pro Tip: ์ด๋Ÿฐ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํ•ญ์ƒ ํŒ€์˜ ์—ญ๋Ÿ‰๊ณผ ํ”„๋กœ์ ํŠธ์˜ ๋ณต์žก์„ฑ์„ ๊ณ ๋ คํ•ด์•ผ ํ•ด์š”. ๋•Œ๋กœ๋Š” ๊ฐ„๋‹จํ•œ ํ•ด๊ฒฐ์ฑ…์ด ๋” ๋‚˜์„ ์ˆ˜ ์žˆ์ฃ . ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋„ˆ๋ฌด ๋ณต์žกํ•œ ๊ธฐ๋Šฅ๋ณด๋‹ค๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์‰ฝ๊ฒŒ ์ดํ•ดํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด ๋” ์ค‘์š”ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์—์š”!

์ž, ์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ ์‹ค์ „ ์˜ˆ์ œ์˜€์–ด์š”. ์–ด๋– ์…จ๋‚˜์š”? ์กฐ๊ธˆ์€ ๋จธ๋ฆฌ๊ฐ€ ์•„ํ”„์…จ๋‚˜์š”? ใ…‹ใ…‹ใ…‹ ๊ฑฑ์ • ๋งˆ์„ธ์š”. ์ด๋Ÿฐ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์€ ์‹œ๊ฐ„์„ ๋‘๊ณ  ์ฒœ์ฒœํžˆ ์ตํ˜€๋‚˜๊ฐ€๋ฉด ๋ผ์š”. ์ฒ˜์Œ๋ถ€ํ„ฐ ์™„๋ฒฝํ•˜๊ฒŒ ์ดํ•ดํ•˜๋ ค๊ณ  ํ•˜์ง€ ๋งˆ์„ธ์š”!

์ด์ œ ์šฐ๋ฆฌ์˜ ์—ฌ์ •์ด ๊ฑฐ์˜ ๋๋‚˜๊ฐ€๊ณ  ์žˆ์–ด์š”. ๋งˆ์ง€๋ง‰์œผ๋กœ ์ •๋ฆฌ๋ฅผ ํ•ด๋ณผ๊นŒ์š”?

๐Ÿšจ ์ฃผ์˜์‚ฌํ•ญ: ์ด๋Ÿฐ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์€ ์ •๋ง ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ๊ทธ๋งŒํผ ์˜ค์šฉํ•˜๊ธฐ ์‰ฌ์›Œ์š”. ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•  ๋•Œ๋Š” ํ•ญ์ƒ ํŒ€์›๋“ค๊ณผ ์ถฉ๋ถ„ํžˆ ์ƒ์˜ํ•˜๊ณ , ์ฝ”๋“œ์˜ ๋ณต์žก์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ์ž˜ ๊ณ ๋ คํ•ด์•ผ ํ•ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ƒˆ๋กœ์šด ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ์„ ๋„์ž…ํ•  ๋•Œ ์‚ฌ์šฉ์ž์˜ ํŽธ์˜์„ฑ๊ณผ ์‹œ์Šคํ…œ์˜ ๋ณต์žก์„ฑ์„ ์ž˜ ๊ท ํ˜• ์žก์•„์•ผ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ ! ๐Ÿ’ช

๐ŸŽ“ ๋งˆ๋ฌด๋ฆฌ: ์šฐ๋ฆฌ์˜ ์—ฌ์ •์„ ๋˜๋Œ์•„๋ณด๋ฉฐ

์™€์šฐ! ์ •๋ง ๊ธด ์—ฌ์ •์ด์—ˆ์ฃ ? ์šฐ๋ฆฌ๋Š” Scala์˜ ํƒ€์ž… ์‹œ์Šคํ…œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ ๋žŒ๋‹ค, ๊ณ ์ฐจ ํƒ€์ž…, ๊ทธ๋ฆฌ๊ณ  ํƒ€์ž… ๋žŒ๋‹ค๊นŒ์ง€ ์ •๋ง ๊นŠ์ด ์žˆ๋Š” ๋‚ด์šฉ๋“ค์„ ๋‹ค๋ค˜์–ด์š”. ์—ฌ๋Ÿฌ๋ถ„์˜ ๋‘๋‡Œ๋Š” ์•„์ง ๋ฉ€์ฉกํ•œ๊ฐ€์š”? ใ…‹ใ…‹ใ…‹

์šฐ๋ฆฌ๊ฐ€ ๋ฐฐ์šด ๋‚ด์šฉ๋“ค์„ ๊ฐ„๋‹จํžˆ ์ •๋ฆฌํ•ด๋ณผ๊นŒ์š”?

  1. Scala์˜ ๊ฐ•๋ ฅํ•œ ํƒ€์ž… ์‹œ์Šคํ…œ
  2. ๋žŒ๋‹ค์™€ ๊ณ ์ฐจ ํ•จ์ˆ˜์˜ ๊ฐœ๋…๊ณผ ํ™œ์šฉ
  3. ๊ณ ์ฐจ ํƒ€์ž…๊ณผ ๊ทธ ํ™œ์šฉ
  4. ํƒ€์ž… ๋žŒ๋‹ค์˜ ๋งˆ๋ฒ• ๊ฐ™์€ ํž˜
  5. ์ด ๋ชจ๋“  ๊ฐœ๋…๋“ค์„ ํ™œ์šฉํ•œ ์‹ค์ „ ์˜ˆ์ œ๋“ค

์ด ๋ชจ๋“  ๊ฐœ๋…๋“ค์ด ์ฒ˜์Œ์—๋Š” ์ •๋ง ์–ด๋ ต๊ณ  ๋ณต์žกํ•ด ๋ณด์˜€์„ ๊ฑฐ์˜ˆ์š”. ํ•˜์ง€๋งŒ ์ฐจ๊ทผ์ฐจ๊ทผ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ์‚ดํŽด๋ณด๋‹ˆ ์กฐ๊ธˆ์€ ๊ฐ์ด ์˜ค์‹œ์ง€ ์•Š๋‚˜์š”? ใ…‹ใ…‹ใ…‹

Scala์˜ ์ด๋Ÿฐ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์€ ์ •๋ง ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์˜ˆ์š”. ํ•˜์ง€๋งŒ ๊ฐ•๋ ฅํ•œ ๋งŒํผ ์ฃผ์˜ํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ์„ ๋„์ž…ํ•  ๋•Œ ์‹ ์ค‘ํ•˜๊ฒŒ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ !

๐ŸŒŸ ๊ธฐ์–ตํ•˜์„ธ์š”: ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ๊ฒฐ๊ตญ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋„๊ตฌ์ผ ๋ฟ์ด์—์š”. ๊ฐ€์žฅ ๋ณต์žกํ•˜๊ณ  ๊ณ ๊ธ‰์ง„ ํ•ด๊ฒฐ์ฑ…์ด ํ•ญ์ƒ ์ตœ์„ ์€ ์•„๋‹ˆ์—์š”. ๋•Œ๋กœ๋Š” ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ ์ธ ์ฝ”๋“œ๊ฐ€ ๋” ๋‚˜์„ ์ˆ˜ ์žˆ์ฃ . ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์‚ฌ์šฉ์ž์˜ ๋‹ˆ์ฆˆ๋ฅผ ์ •ํ™•ํžˆ ํŒŒ์•…ํ•˜๊ณ  ๊ทธ์— ๋งž๋Š” ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์—์š”!

์—ฌ๋Ÿฌ๋ถ„, ์ •๋ง ์ˆ˜๊ณ  ๋งŽ์œผ์…จ์–ด์š”! ์ด๋ ‡๊ฒŒ ๊ธด ์—ฌ์ •์„ ํ•จ๊ป˜ ํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธ€์„ ์ฝ์œผ์‹  ์—ฌ๋Ÿฌ๋ถ„์€ ์ด์ œ Scala์˜ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์— ๋Œ€ํ•ด ๊ธฐ๋ณธ์ ์ธ ์ดํ•ด๋ฅผ ๊ฐ–์ถ”์…จ์„ ๊ฑฐ์˜ˆ์š”. ์•ž์œผ๋กœ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์ด๋Ÿฐ ๊ฐœ๋…๋“ค์„ ๋งŒ๋‚˜๊ฒŒ ๋˜๋ฉด, "์•„, ์ด๊ฑฐ ์–ด๋””์„œ ๋ณธ ๊ฒƒ ๊ฐ™์€๋ฐ?" ํ•˜๊ณ  ๋– ์˜ฌ๋ฆฌ์‹ค ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”. ใ…‹ใ…‹ใ…‹

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์„ธ๊ณ„๋Š” ์ •๋ง ๋„“๊ณ  ๊นŠ์–ด์š”. ์šฐ๋ฆฌ๊ฐ€ ์˜ค๋Š˜ ๋‹ค๋ฃฌ ๋‚ด์šฉ์€ ๊ทธ ์ค‘ ์•„์ฃผ ์ž‘์€ ๋ถ€๋ถ„์— ๋ถˆ๊ณผํ•ด์š”. ํ•˜์ง€๋งŒ ์ด๋Ÿฐ ์ž‘์€ ์‹œ์ž‘์ด ์—ฌ๋Ÿฌ๋ถ„์„ ๋” ๋„“์€ ์„ธ๊ณ„๋กœ ์ด๋Œ์–ด์ค„ ๊ฑฐ์˜ˆ์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ž‘์€ ์žฌ๋Šฅ ํ•˜๋‚˜๋กœ ์‹œ์ž‘ํ•ด์„œ ์ ์  ๋” ๋‹ค์–‘ํ•œ ๋ถ„์•ผ๋กœ ํ™•์žฅํ•ด ๋‚˜๊ฐ€๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ !

์ž, ์ด์ œ ์ •๋ง ๋์ด์—์š”. ์—ฌ๋Ÿฌ๋ถ„์˜ Scala ์—ฌ์ •์— ํ–‰์šด์ด ํ•จ๊ป˜ํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ž„๊ฒŒ์š”. ํ™”์ดํŒ…! ๐Ÿš€โœจ