본문 바로가기

프로그래밍

coursera 스칼라 2주차

스칼라 2주차

1. Higher-Order Functions

Higher order function이란?

function을 파라미터로 받는 function

anonymous function syntax

    def cube(x: Int): Int = x * x * x
    (x: Int) => x * x * x

2. Currying

  def sum(f: Int => Int): (Int, Int)=> Int = {
      def Sumf(a: Int, b: Int):Int = {
          if (a>b) 0
          else f(a) + Sumf(a+1, b)
      }
      Sumf
  }                                               //> sum: (f: Int => Int)(Int, Int) => Int

  def sum2(f: Int => Int) (a: Int, b: Int):Int = {
      def loop(a: Int, acc:Int):Int = {
          if (a>b) acc
          else loop(a+1, f(a) + acc)
      }
      loop (a, 0)
  }                                               //> sum2: (f: Int => Int)(a: Int, b: Int)Int

  def sum3(f: Int => Int) (a: Int) (b:Int):Int = {
      def loop(a: Int, acc:Int):Int = {
          if (a>b) acc
          else loop(a+1, f(a) + acc)
      }
      loop (a,0)
  }                                               //> sum3: (f: Int => Int)(a: Int)(b: Int)Int

  sum2(x=>x)( 1,2)                                //> res4: Int = 3
  sum3(x=>x)(1)(2)                                //> res5: Int = 3

  val sum2a = sum2(x=>x*x)_                       //> sum2a  : (Int, Int) => Int = <function2>
  sum2a(1,2)                                      //> res6: Int = 5
  sum2a(1)_            //컴파일 에러 뜬다. sum3형태로 하면 뜨지 않으니 무조건 인자를 하나씩 끊는 게 좋을 듯.

과연 sum하고 sum2는 같은 타입일까? sum2는 뒤에 언더바를 붙이지 않으면 f만 넣은 상태에서 컴파일 에러가 뜬다.
sum의 타입이 (Int=>Int)=>((Int, Int)=>Int) 혹은 (Int=>Int)=>(Int=>Int)=>Int (right associativity)
sum2는 (Int=>Int, Int, Int)=>Int 타입과 sum2 타입의 중간 정도라고 생각…??

3. 스칼라 syntax

Language Elements Seen So Far:

We have seen language elements to express types, expressions and
definitions.
Below, we give their context-free syntax in Extended Backus-Naur
form (EBNF), where

\ denotes an alternative,
[…] an option (0 or 1),
{…} a repetition (0 or more).

Types

종류 syntax
Type SimpleType \ FunctionType
FunctionType SimpleType ‘=>’ Type \ ‘(’ [ Types ] ‘)’ ‘=> ’ Type
SimpleType Ident
Types = Type { ‘ , ’ Type }

A type can be:

▶ A numeric type: Int, Double (and Byte, Short, Char, Long,
Float),
▶ The Boolean type with the values true and false,
▶ The String type,
▶ A function type, like Int => Int, (Int, Int) => Int.

Expressions

Expr = InfixExpr | FunctionExpr
| if ‘( ’ Expr ‘) ’ Expr else Expr
InfixExpr = PrefixExpr | InfixExpr Operator InfixExpr
Operator = ident
PrefixExpr = [ ‘+ ’ | ‘-’ | ‘! ’ | ‘~ ’ ] SimpleExpr
SimpleExpr = ident | literal | SimpleExpr ‘. ’ ident
| Block
FunctionExpr = Bindings ‘= > ‘ Expr
Bindings = ident [ ‘: ’ SimpleType ]
| ‘( ’ [ Binding { ‘ , ’ Binding }] ‘) ’
Binding = ident [ ‘: ’ Type ]
Block = ‘{ ’ { Def ‘; ’} Expr ‘} ’

Expressions (2)

An expression can be:

▶ An identifier such as x, isGoodEnough,
▶ A literal, like 0, 1.0, ”abc”,
▶ A function application, like sqrt(x),
▶ An operator application, like -x, y + x,
▶ A selection, like math.abs,
▶ A conditional expression, like if (x < 0) -x else x,
▶ A block, like { val x = math.abs(y) ; x * 2 }
▶ An anonymous function, like x => x + 1.

Definitions

Def = FunDef | ValDef
FunDef = def ident { ‘( ’ [ Parameters ] ‘) ’}
[ ‘: ’ Type ] ‘= ’ Expr
ValDef = val ident [ ‘: ’ Type ] ‘= ’ Expr
Parameter = ident ‘: ’ [ ‘= > ’ ] Type
Parameters = Parameter { ‘ , ’ Parameter }

A definition can be:

▶ A function definition, like def square(x: Int) = x * x
▶ A value definition, like val y = square(2)

A parameter can be:

▶ A call-by-value parameter, like (x: Int),
▶ A call-by-name parameter, like (y: => Double).

4 & 5. Functions and Data

  class Rational(x: Int, y: Int) {
    def numer = x
    def denom = y
    def add(r: Rational) =
    new Rational(numer * r.denom + r.numer * denom, denom * r.denom)
    override def toString = numer.toString + '/' + denom.toString

    def max(that: Rational) = if (this.less(that)) that else this
}

스칼라에서 클래스 정의를 하면 새로운 타입을 정의하고, 그걸 만들 수 있는 생성자 함수를 만들어낸다. 스칼라에서는 types와 values가 다른 공간에 있기 때문에 클래스 이름을 다른 정의에 사용가능하다. ex) def Rational = 1
this로 자기 자신을 refer.

require and assert

둘다 컨디션과 옵셔널한 스트링 메세지로 호출할 수 있는 predefined 함수.
assert는 assertionError를, require은 IllegalArgumentException을 throw한다.

2차 생성자 함수

class Rational(x: Int, y: Int) {
def this(x: Int) = this(x, 1)
...
}

Evaluation and Operators

new Rational(1, 2).less(new Rational(2, 3))

→ [1/x, 2/y] [newRational(2, 3)/that] [new Rational(1, 2)/this]
this.numer * that.denom < that.numer * this.denom

= new Rational(1, 2).numer * new Rational(2, 3).denom < new Rational(2, 3).numer * new Rational(1, 2).denom

→→ 1 * 3 < 2 * 2
→→ true

substitution의 순서는 항상 상관없나? 상관없을 것 같은데… 확실하지 않음.

single parameter method의 경우
r add x <=> r.add(x)

method의 identifier

자바랑 다르게 특수문자 사용가능. 규칙은 다음과 같다.

Alphanumeric: starting with a letter, followed by a sequence of letters or numbers
Symbolic: starting with an operator symbol, followed by otheroperator symbols.
▶ The underscore character ’_’ counts as a letter.
▶ Alphanumeric identifiers can also end in an underscore, followed by some operator symbols.

Examples of identifiers:

x1 * +?%& vector_++ counter_=

우선순위

점수가 높을수록 높다.

점수 기호
1 all letters)
2 ‘or 기호’
3 ^
4 &
5 < >
= !
7 :
8 + -
9 * / %
10 (all other special characters)