KoreanFoodie's Study

Scala 8 - Parametric Polymorphism 본문

Tutorials/Scala

Scala 8 - Parametric Polymorphism

GoldGiver 2019. 4. 23. 19:05

스칼라 튜토리얼, scala의 parametric polymophism에 대해 알아보자


Parametric Polymorphism: Functions

  • Problem
def id1(x: Int): Int = x
def id2(x: Double): Double = x

Can we avoid DRY(Do not Reapeat Yourself)?

  • Parametric Polymorphism(a.k.a. For-all Types)
def id[A](x: A): A = x    // type for definition
val f = (x:Int) => x    // type for value

The type of id is [A](x: A)A.

id is a parametric expression. Only definition can have parametric type(value doesn't allow this, except record typed).

id[T] _ is a value of type T=>T for any type T.


Example

What would be the result of the below code?

def id[A](x: A) = x

id(3)        // Q1
id("abc")    // Q2

def applyn[A](f: A => A, n: Int, x: A): A =
    n match {
        case 0 => x
        case _ => f(applyn(f, n - 1, x))
    }

applyn((x:Int)=>x+1,100,3)                 // Q3
applyn((x:String)=>x+"!", 10, "gil")    // Q4
applyn(id[String], 10, "hur")            // Q5

def foo[A,B](f: A=>A, x: (A,B)) : (A,B) =
    (applyn[A](f, 10, x._1), x._2)

foo[String,Int]((x:String)=>x+"!",("abc",10))    // Q6

Answer would be :

//Q1 : 3
//Q2 : abc
//Q3 : 103
//Q4 : gil!!!!!!!!!!
//Q5 : hur
//Q6 : (abc!!!!!!!!!!, 10)

Full Polymorphism using Scala's trick

type Applyn = {def apply[A](f: A=>A, n: Int, x: A): A}

object applyn {        // val applyn = new {
    def apply[A](f: A=>A, n: Int, x: A): A =
        n match {
            case 0 => x
            case _ => f(apply(f, n-1, x))
        }
}
applyn((x: String)=> x+"!", 10, "gil")
// applyn.apply[String]((x: String)=> x+"!", 10, "gil")

def foo(f: Applyn): String = {
    val a: String = f[String]((x: String)=> x+"!", 10, "gil")
    val b: Int = f[Int]((x: Int) => x+2, 10, 5)
    a+b.toString()
}

foo(applyn)

Record type has def part.

When you use def, every function value is encoded as type ... = {}

f(A=>B) is actually g = {def apply(x: A)=> B}!


Function types vs. Record types

val f = (x: Int)=> x
val g = new {
    def apply(x: Int): Int = x
}
f(10)
g(10)
// It automatically interpret as
// g.apply(10)!

def foo(func:Int => Int): Int = func(10)

foo(f)
// foo(g)
// -> It gives error, since g is not function,
// it is record type!
foo(g.apply) // It works well

Parametric Polymorphism: Datatypes

sealed abstract class MyOption[A]
case class MyNone[A]() extends MyOption[A]
case class MySome[A](some: A) extends MyOption[A]

sealed abstract class MyList[A]
case class MyNil[A]() extends MyList[A]
case class MyCons[A](hd: A, tl: MyList[A]) extends MyList[A]

sealed abstract class BTree[A]
case class Leaf[A]() extends BTree[A]
case class Node[A](value: A, left: BTree[A], right: BTree[A]) 
extends BTree[A]

def x: MyList[Int] = MyCons(3, MyNil())
def y: MyList[String] = MyCons("abc", MyNil())    
  • Excercise :
/*
BSTree[A] = Leaf
| Node of Int * A * BSTree[A] * BSTree[A]
*/

def lookup[A](t: BSTree[A], k: Int) : MyOption[A] =
    ???
def t : BSTree[String] = 
    Node(5,"My5",
        Node(4,"My4",Node(2,"My2",Leaf(),Leaf()),Leaf()),
        Node(7,"My7",Node(6,"My6",Leaf(),Leaf()),Leaf()))

lookup(t, 7)
lookup(t, 3)
  • Solution :
sealed abstract class BSTree[A]
case class Leaf[A]() extends BSTree[A]
case class Node[A](key: Int, value: A, left: BSTree[A], right: 
BSTree[A]) extends BSTree[A]

def lookup[A](t: BSTree[A], key: Int) : MyOption[A] =
t match {
    case Leaf() => MyNone()
    case Node(k,v,lt,rt) =>
        k match {
            case _ if key == k => MySome(v)
            case _ if key < k => lookup(lt,key)
            case _ => lookup(rt, key)
        }
    }

def t : BSTree[String] =
    Node(5,"My5",
        Node(4,"My4",Node(2,"My2",Leaf(),Leaf()),Leaf()),
        Node(7,"My7",Node(6,"My6",Leaf(),Leaf()),Leaf()))

lookup(t, 7)
lookup(t, 3)
  • Exercise 2:
sealed abstract class BTree[A]
case class Leaf[A]() extends BTree[A]
case class Node[A](value: A, left: BTree[A], right: BTree[A])
    extends BTree[A]

type BSTree[A] = BTree[(Int,A)]

def lookup[A](t: BSTree[A], k: Int) : MyOption[A] =
    ???

def t : BSTree[String] =
    Node((5,"My5"),
        Node((4,"My4"),Node((2,"My2"),Leaf(),Leaf()),Leaf()),
        Node((7,"My7"),Node((6,"My6"),Leaf(),Leaf()),Leaf()))

lookup(t, 7)
  • Solution :
type BSTree[A] = BTree[(Int,A)]

def lookup[A](t: BSTree[A], key: Int) : MyOption[A] =
    t match {
        case Leaf() => MyNone()
        case Node((k,v),lt,rt) =>
            k match {
                case _ if key == k => MySome(v)
                case _ if key < k => lookup(lt,key)
                case _ => lookup(rt, key)
            }
    }

def t : BSTree[String] =
    Node((5,"My5"),
        Node((4,"My4"),Node((2,"My2"),Leaf(),Leaf()),Leaf()),
        Node((7,"My7"),Node((6,"My6"),Leaf(),Leaf()),Leaf()))
lookup(t, 7)
lookup(t, 3)

'Tutorials > Scala' 카테고리의 다른 글

Scala 10 - Class  (0) 2019.04.23
Scala 9 - Sub Types  (0) 2019.04.23
Scala 7 - Datatypes2  (0) 2019.04.23
Scala 6 - Datatypes  (0) 2019.04.23
Scala 5 - Currying  (0) 2019.04.23
Comments