Scala에서 여러 매개 변수 목록과 목록 당 여러 매개 변수의 차이점은 무엇입니까?


81

Scala에서는 다음과 같은 함수를 작성할 수 있습니다.

def curriedFunc(arg1: Int) (arg2: String) = { ... }

curriedFunc두 매개 변수 목록이 있는 위의 함수 정의와 단일 매개 변수 목록에 여러 매개 변수가있는 함수 의 차이점은 무엇입니까?

def curriedFunc(arg1: Int, arg2: String) = { ... }

수학적 관점에서 이것은 (curriedFunc(x))(y)그리고 curriedFunc(x,y)그러나 나는 쓸 수 def sum(x) (y) = x + y있고 같은 것입니다def sum2(x, y) = x + y

한 가지 차이점 만 알고 있습니다. 이것은 부분적으로 적용된 기능입니다. 그러나 두 가지 방법은 모두 동일합니다.

다른 차이점이 있습니까?

답변:


88

엄밀히 말하면 이것은 카레 함수가 아니라 여러 인수 목록이있는 메서드입니다. 물론 함수처럼 보입니다.

말했듯이 다중 인수 목록을 사용하면 부분적으로 적용된 함수 대신 메서드를 사용할 수 있습니다. (내가 사용하는 일반적으로 어리석은 예에 대해 죄송합니다)

object NonCurr {
  def tabulate[A](n: Int, fun: Int => A) = IndexedSeq.tabulate(n)(fun)
}

NonCurr.tabulate[Double](10, _)            // not possible
val x = IndexedSeq.tabulate[Double](10) _  // possible. x is Function1 now
x(math.exp(_))                             // complete the application

또 다른 이점은 두 번째 인수 목록이 단일 함수 또는 썽 크로 구성되어있는 경우 멋지게 보이는 괄호 대신 중괄호를 사용할 수 있다는 것입니다. 예

NonCurr.tabulate(10, { i => val j = util.Random.nextInt(i + 1); i - i % 2 })

IndexedSeq.tabulate(10) { i =>
  val j = util.Random.nextInt(i + 1)
  i - i % 2
}

또는 썽크를 위해 :

IndexedSeq.fill(10) {
  println("debug: operating the random number generator")
  util.Random.nextInt(99)
}

또 다른 장점은 기본 인수 값을 정의하기 위해 이전 인수 목록의 인수를 참조 할 수 있다는 것입니다 (단일 목록에서이를 수행 할 수 없다는 단점이 있다고 말할 수도 있지만 :).

// again I'm not very creative with the example, so forgive me
def doSomething(f: java.io.File)(modDate: Long = f.lastModified) = ???

마지막으로 관련 게시물에 대한 답변에는 세 가지 다른 응용 프로그램이 있습니다. 왜 스칼라가 여러 매개 변수 목록과 목록 당 여러 매개 변수를 모두 제공합니까? . 여기에 복사 할 것이지만 크레딧은 Knut Arne Vedaa, Kevin Wright 및 extempore에게 있습니다.

첫째 : 여러 개의 변수 인수를 가질 수 있습니다.

def foo(as: Int*)(bs: Int*)(cs: Int*) = as.sum * bs.sum * cs.sum

... 단일 인수 목록에서는 불가능합니다.

둘째, 유형 추론을 지원합니다.

def foo[T](a: T, b: T)(op: (T,T) => T) = op(a, b)
foo(1, 2){_ + _}   // compiler can infer the type of the op function

def foo2[T](a: T, b: T, op: (T,T) => T) = op(a, b)
foo2(1, 2, _ + _)  // compiler too stupid, unfortunately

마지막 implicit으로 전체 인수 목록에 대한 수정 자 와 마찬가지로 암시 적 및 비암 시적 인수를 가질 수있는 유일한 방법입니다 .

def gaga [A](x: A)(implicit mf: Manifest[A]) = ???   // ok
def gaga2[A](x: A, implicit mf: Manifest[A]) = ???   // not possible

2
가장 많이 득표 한 답변이므로 질문의 제목이 더 이상 답변과 일치하지 않는 것 같습니다. 제목을 "Scala가 여러 매개 변수 목록과 목록 당 여러 매개 변수를 모두 제공하는 이유는 무엇입니까?"로 변경해야한다고 생각합니다. 즉, 이미 stackoverflow.com/questions/4684185/… 와 함께 샘플에 병합되었습니다 .
Jacek Laskowski 2013

42

0__의 훌륭한 대답으로 다루지 않은 또 다른 차이점이 있습니다 : 기본 매개 변수. 한 매개 변수 목록의 매개 변수는 다른 매개 변수 목록에서 기본값을 계산할 때 사용할 수 있지만 동일한 목록에서는 사용할 수 없습니다.

예를 들면 :

def f(x: Int, y: Int = x * 2) = x + y // not valid
def g(x: Int)(y: Int = x * 2) = x + y // valid

이를 위해 간단한 예제를 사용했습니다. 실제로 기본 매개 변수를 훨씬 더 유용하게 만듭니다. 감사!
Mike McFarland

: 좋은 예를 제외하고는 나는 그것을 호출하는 방법을 알아 내기 위해 5 분 소요 g(1)()3. 반환 g(1)(2)반환 (5)
지혜

19

요점은 카레와 카레를 넣지 않은 형태가 동등하다는 것입니다! 다른 사람들이 지적했듯이 상황에 따라 하나 또는 다른 형식을 사용하는 것이 구문 적으로 더 편리 할 수 있으며, 이것이 다른 형식 보다 선호하는 유일한 이유입니다.

Scala에 curried 함수를 선언하기위한 특별한 구문이 없더라도 여전히 그것들을 구성 할 수 있다는 것을 이해하는 것이 중요합니다. 이것은 함수를 반환하는 함수를 생성 할 수있는 능력이 있으면 수학적 불가피성 일뿐입니다.

이를 증명하기 위해 def foo(a)(b)(c) = {...}구문이 존재하지 않는다고 상상해보십시오 . 그러면 다음과 같이 똑같은 결과를 얻을 수 있습니다 def foo(a) = (b) => (c) => {...}..

Scala의 많은 기능과 마찬가지로 이것은 어쨌든 가능하지만 약간 더 자세한 작업을 수행하기위한 구문상의 편의 일뿐입니다.


4

두 가지 형태는 동형입니다. 주요 차이점은 curried 함수는 부분적으로 적용하기가 더 쉽고, non-curried 함수는 적어도 Scala에서 약간 더 좋은 구문을 가지고 있다는 것입니다.


2
예를 들어 카레 기능 이 아니라고 말하지 않았 습니까? curried 함수에는 단일 인수 만 있고 모든 인수가 닫힌 본문이있을 때까지 단일 인수가있는 함수 등을 반환 할 수 있음을 이해합니다. 내가 잘못?
Jacek Laskowski 2013
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.