[scala] 스칼라에서 이름으로 전화 및 값으로 전화, 설명 필요

내가 알기로, 스칼라에서 함수는

  • 값별 또는
  • 이름으로

예를 들어, 다음과 같은 선언에서 함수가 어떻게 호출되는지 알고 있습니까?

선언:

def  f (x:Int, y:Int) = x;

요구

f (1,2)
f (23+55,5)
f (12+3, 44*11)

규칙은 무엇입니까?



답변

제시 한 예제는 값별 호출 만 사용하므로 차이점을 보여주는 새롭고 간단한 예제를 제공합니다.

먼저 부작용이있는 함수가 있다고 가정 해 봅시다. 이 함수는 무언가를 출력 한 다음를 반환합니다 Int.

def something() = {
  println("calling something")
  1 // return value
}

이제 우리는 Int하나의 값을 호출하는 스타일 ( x: Int)로, 다른 하나는 이름을 부르는 스타일 ( )로 인수를 취하는 것을 제외하고는 정확히 동일한 인수 를 받아들이는 두 함수를 정의 할 것입니다 x: => Int.

def callByValue(x: Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

def callByName(x: => Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

이제 부작용 기능으로 호출하면 어떻게됩니까?

scala> callByValue(something())
calling something
x1=1
x2=1

scala> callByName(something())
calling something
x1=1
calling something
x2=1

따라서 값별 호출 버전에서는 전달 된 함수 호출 ( something()) 의 부작용 이 한 번만 발생 했음을 알 수 있습니다 . 그러나 이름 별 통화 버전에서는 부작용이 두 번 발생했습니다.

값별 호출 함수는 함수를 호출하기 전에 전달 된 표현식의 값을 계산하므로 매번 동일한 값에 액세스하기 때문입니다. 대신, 이름 별 호출 함수 는 전달 될 때마다 전달 된 표현식의 값을 재 계산 합니다.


답변

다음은 Martin Odersky의 예입니다.

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

다음과 같은 조건에서 평가 전략을 검토하고 어느 단계가 더 빠른지 (더 적은 단계) 결정합니다.

test (2,3)

값으로 호출 : test (2,3)-> 2 * 2-> 4
이름으로 호출 : test (2,3)-> 2 * 2-> 4
여기서 동일한 단계 수로 결과에 도달합니다.

test (3+4,8)

값으로 전화 : test (7,8)-> 7 * 7-> 49
이름으로 전화 : (3 + 4) (3 + 4)-> 7 (3 + 4)-> 7 * 7-> 49
여기에 전화 값이 빠릅니다.

test (7,2*4)

값으로 전화 : test (7,8)-> 7 * 7-> 49
이름으로 전화 : 7 * 7-> 49
여기에서 이름으로 전화하는 것이 더 빠릅니다

test (3+4, 2*4) 

값으로 호출 : test (7,2 * 4)-> test (7, 8)-> 7 * 7-> 49
이름으로 호출 : (3 + 4) (3 + 4)-> 7 (3 + 4) -> 7 * 7-> 49
같은 단계에서 결과에 도달합니다.


답변

예제의 경우 모든 매개 변수는 value 로만 정의 하기 때문에 함수에서 호출 되기 전에 평가 됩니다 . 이름으로 매개 변수를 정의 하려면 코드 블록을 전달해야합니다.

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

이런 식으로 매개 변수 x는 함수에서 호출 될 때까지 평가되지 않습니다 .

여기 의이 작은 포스트 는 이것도 잘 설명해줍니다.


답변

위의 의견에서 @Ben의 요점을 반복하려면 “이름 별 전화”를 구문 설탕으로 생각하는 것이 가장 좋습니다. 파서는 표현식을 익명 함수로 래핑하여 나중에 사용될 때 호출 할 수 있도록합니다.

사실상, 정의하는 대신

def callByName(x: => Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

그리고 달리기 :

scala> callByName(something())
calling something
x1=1
calling something
x2=1

당신은 또한 쓸 수 있습니다 :

def callAlsoByName(x: () => Int) = {
  println("x1=" + x())
  println("x2=" + x())
}

같은 효과를 얻으려면 다음과 같이 실행하십시오.

callAlsoByName(() => {something()})

calling something
x1=1
calling something
x2=1


답변

예제를 제공하는 것이 아니라 간단한 사용 사례로 설명하려고합니다.

시간이 지날수록 매번 잔소리 되는 “비틀 거림 앱” 을 만들고 싶다고 상상해보십시오 .

다음 구현을 조사하십시오.

object main  {

    def main(args: Array[String]) {

        def onTime(time: Long) {
            while(time != time) println("Time to Nag!")
            println("no nags for you!")
        }

        def onRealtime(time: => Long) {
            while(time != time) println("Realtime Nagging executed!")
        }

        onTime(System.nanoTime())
        onRealtime(System.nanoTime())
    }
}

위의 구현에서 Nagger는 이름으로 전달할 때만 작동합니다. 이유는 값으로 전달할 때 다시 사용되므로 이름으로 전달할 때마다 값이 다시 평가되지 않고 값이 다시 평가되지 않기 때문입니다. 변수에 액세스 한 시간


답변

일반적으로 함수에 대한 매개 변수는 값별 매개 변수입니다. 즉, 매개 변수 값은 함수에 전달되기 전에 결정됩니다. 그러나 함수 내에서 호출 될 때까지 평가하고 싶지 않은 표현식을 매개 변수로 받아들이는 함수를 작성해야하는 경우 어떻게해야합니까? 이러한 상황에서 Scala는 이름 별 호출 매개 변수를 제공합니다.

이름 별 호출 메커니즘은 코드 블록을 수신자에게 전달하고 수신자가 매개 변수에 액세스 할 때마다 코드 블록이 실행되고 값이 계산됩니다.

object Test {
def main(args: Array[String]) {
    delayed(time());
}

def time() = {
  println("Getting time in nano seconds")
  System.nanoTime
}
def delayed( t: => Long ) = {
  println("In delayed method")
  println("Param: " + t)
  t
}
}
 1. C : /> scalac Test.scala
 2. 스칼라 테스트
 3. 지연된 방법
 4. 나노초로 시간 얻기
 5. 매개 변수 : 81303808765843
 6. 나노초로 시간 얻기


답변

내가 가정 call-by-value한 것처럼 위에서 설명한 함수는 값을 함수에 전달합니다. 에 따르면 Martin Odersky이 기능 평가에서 중요한 역할을 스칼라에 의한 평가 전략의 후속이다. 그러나 간단하게하십시오 call-by-name. 그것과 마찬가지로 함수를 메소드의 인수로 전달하는 것으로도 알려져 Higher-Order-Functions있습니다. 메소드가 전달 된 매개 변수의 값에 액세스 할 때 전달 된 함수의 구현을 호출합니다. 아래:

@dhg 예제에 따르면, 먼저 다음과 같이 메소드를 작성하십시오.

def something() = {
 println("calling something")
 1 // return value
}  

이 함수는 하나의 println명령문을 포함 하고 정수 값을 리턴합니다. 다음과 같은 인수를 가진 함수를 작성하십시오 call-by-name.

def callByName(x: => Int) = {
 println("x1=" + x)
 println("x2=" + x)
}

이 함수 매개 변수는 하나의 정수 값을 반환하는 익명 함수를 정의합니다. 여기 x에는0 인수를 전달했지만 반환 int값과 something함수에 동일한 서명 포함됩니다. 함수를 호출하면에 함수를 인수로 전달합니다 callByName. 그러나 call-by-value그것 의 경우 정수 값을 함수에 전달합니다. 다음과 같이 함수를 호출합니다.

scala> callByName(something())
 calling something
 x1=1
 calling something
 x2=1 

이 우리에서 something우리의 가치를 액세스 할 때 때문에, 두 번 호출 방법 xcallByName방법의 (고화질)과의 전화,something 방법.