수색…


통사론

  • aFunction (10) _ // '_'사용 컴파일러에서 나머지 매개 변수 그룹의 모든 매개 변수가 카레트되도록 지시합니다.
  • nArityFunction.curried // n-arity 함수를 동등한 카레 버전으로 변환합니다.
  • anotherFunction (x) (_ : String) (z) // 임의의 파라미터를 카레합니다. 명시 적으로 명시된 유형이 필요합니다.

카레 함수로서 구성 가능한 승수

def multiply(factor: Int)(numberToBeMultiplied: Int): Int = factor * numberToBeMultiplied

val multiplyBy3 = multiply(3)_     // resulting function signature Int => Int
val multiplyBy10 = multiply(10)_ // resulting function signature Int => Int

val sixFromCurriedCall = multiplyBy3(2) //6
val sixFromFullCall = multiply(3)(2)    //6

val fortyFromCurriedCall = multiplyBy10(4) //40
val fortyFromFullCall = multiply(10)(4)    //40

여러 유형의 여러 매개 변수 그룹, 임의 위치의 매개 변수 카싱

def numberOrCharacterSwitch(toggleNumber: Boolean)(number: Int)(character: Char): String = 
  if (toggleNumber) number.toString else character.toString

// need to explicitly specify the type of the parameter to be curried
// resulting function signature Boolean => String
val switchBetween3AndE = numberOrCharacterSwitch(_: Boolean)(3)('E') 

switchBetween3AndE(true) // "3"
switchBetween3AndE(false) // "E"

단일 매개 변수 그룹을 사용하여 함수 숨기기

def minus(left: Int, right: Int) = left - right

val numberMinus5 = minus(_: Int, 5)
val fiveMinusNumber = minus(5, _: Int)

numberMinus5(7)    //  2
fiveMinusNumber(7) // -2

커링

2 개의 인자의 함수를 정의합시다.

def add: (Int, Int) => Int = (x,y) => x + y
val three = add(1,2) 

커링의 add 하나 개 취하는 함수로 변환 Int (하나 개의 함수를 리턴 Int 내지 An Int )

val addCurried: (Int) => (Int => Int) = add2.curried
//               ^~~ take *one* Int
//                        ^~~~ return a *function* from Int to Int

val add1: Int => Int = addCurried(1)
val three: Int = add1(2)
val allInOneGo: Int = addCurried(1)(2)

이 개념을 여러 인수를 취하는 모든 함수에 적용 할 수 있습니다. 여러 인자를 취하는 함수를 currying하는 것은 하나의 인자를 취하는 일련의 함수 응용으로 변환합니다 :

def add3: (Int, Int, Int) => Int = (a,b,c) => a + b + c + d
def add3Curr: Int => (Int => (Int => Int)) = add3.curried

val x = add3Curr(1)(2)(42)

커링

위키 피 디아 (Wikipedia )에 따르면,

여러 인수를 사용하는 함수의 평가를 함수의 순서를 평가하는 것으로 변환하는 기술입니다.

구체적으로, 스칼라 유형의 관점에서 두 가지 인수를 취하는 함수의 맥락에서 (2를 가짐)

val f: (A, B) => C // a function that takes two arguments of type `A` and `B` respectively 
                   // and returns a value of type `C`

val curriedF: A => B => C // a function that take an argument of type `A` 
                          // and returns *a function* 
                          // that takes an argument of type `B` and returns a `C`

따라서 arity-2 함수의 경우 카레 함수를 다음과 같이 작성할 수 있습니다.

def curry[A, B, C](f: (A, B) => C): A => B => C = { 
  (a: A) => (b: B) => f(a, b) 
}

용법:

val f: (String, Int) => Double = {(_, _) => 1.0}
val curriedF: String => Int => Double = curry(f)
f("a", 1)        // => 1.0
curriedF("a")(1) // => 1.0

Scala는 다음과 같은 몇 가지 언어 기능을 제공합니다.

  1. 카레 함수를 메소드로 작성할 수 있습니다. 그래서 curriedF 는 다음과 같이 쓸 수 있습니다 :
def curriedFAsAMethod(str: String)(int: Int): Double = 1.0
val curriedF = curriedFAsAMethod _
  1. 표준 라이브러리 방법을 사용하여 카레를 제거 할 수 있습니다 (예 : A => B => C 에서 (A, B) => C ) : Function.uncurried
val f: (String, Int) => Double = Function.uncurried(curriedF)
f("a", 1) // => 1.0

Currying을 사용하는 경우

currying 은 다중 인수를 취하는 함수의 평가를 하나의 인수를 사용하여 함수 순서를 평가하는 것으로 변환하는 기술입니다 .

일반적으로 다음과 같은 경우에 유용합니다.

  1. 함수의 다른 인수는 다른 시간에 계산 됩니다 . (실시 예 1)
  2. 함수의 다른 인수 는 응용 프로그램의 다른 계층에 의해 계산 됩니다 . (실시 예 2)

예제 1

총 연간 소득은 수입과 보너스로 구성된 함수라고 가정합시다.

val totalYearlyIncome:(Int,Int) => Int =  (income, bonus) => income + bonus

위의 2-arity 함수의 카레 버전은 다음과 같습니다.

val totalYearlyIncomeCurried: Int => Int => Int = totalYearlyIncome.curried

위의 정의에서 유형을 다음과 같이 보거나 작성할 수도 있음에 유의하십시오.

Int => (Int => Int)

연간 소득 부분을 미리 알고 있다고 가정 해 봅시다.

val partialTotalYearlyIncome: Int => Int = totalYearlyIncomeCurried(10000)

그리고 라인의 어떤 지점에서 보너스가 알려져 있습니다 :

partialTotalYearlyIncome(100)

예제 2

자동차 제조에는 자동차 바퀴와 차체의 적용이 필요하다고 가정 해 봅시다.

val carManufacturing:(String,String) => String = (wheels, body) => wheels + body

이 부분은 다른 공장에서 적용됩니다.

class CarWheelsFactory {
  def applyCarWheels(carManufacturing:(String,String) => String): String => String =
          carManufacturing.curried("applied wheels..")
}
    
class CarBodyFactory {
  def applyCarBody(partialCarWithWheels: String => String): String = partialCarWithWheels("applied car body..")
}

위의 CarWheelsFactory 는 자동차 제조 기능을 카레하며 바퀴 만 적용합니다.

자동차 제조 공정은 다음과 같은 형태로 진행됩니다.

val carWheelsFactory = new CarWheelsFactory()
val carBodyFactory   = new CarBodyFactory()

val carManufacturing:(String,String) => String = (wheels, body) => wheels + body
  
val partialCarWheelsApplied: String => String  = carWheelsFactory.applyCarWheels(carManufacturing)
val carCompleted = carBodyFactory.applyCarBody(partialCarWheelsApplied)

Currying의 실제 사용.

우리가 가지고있는 것은 신용 카드 목록이며 우리는 신용 카드 회사가 지불해야하는 모든 카드에 대한 보험료를 계산하고 싶습니다. 보험료 자체는 총 신용 카드 수에 따라 달라 지므로 회사는 이에 맞게 카드를 조정합니다.

우리는 이미 단일 신용 카드에 대한 보험료를 산정하고 회사가 발행 한 총 카드를 고려하는 기능을 가지고 있습니다.

case class CreditCard(creditInfo: CreditCardInfo, issuer: Person, account: Account)

object CreditCard {
  def getPremium(totalCards: Int, creditCard: CreditCard): Double = { ... }
}

이제이 문제에 대한 합리적인 접근법은 각 신용 카드를 프리미엄에 매핑하고이를 합계로 줄이는 것입니다. 이 같은:

val creditCards: List[CreditCard] = getCreditCards()
val allPremiums = creditCards.map(CreditCard.getPremium).sum //type mismatch; found : (Int, CreditCard) ⇒ Double required: CreditCard ⇒ ?

그러나 CreditCard.getPremium 에는 두 개의 매개 변수가 필요하기 때문에 컴파일러는이를 좋아하지 않습니다. 구조에 부분적으로 적용! 부분적으로 신용 카드의 총 개수를 적용하고 그 기능을 사용하여 신용 카드를 보험료로 매핑 할 수 있습니다. 우리가해야 할 일은 getPremium 함수를 여러 매개 변수 목록을 사용하도록 변경하여 카레를 작성하는 것입니다.

결과는 다음과 같아야합니다.

object CreditCard {
  def getPremium(totalCards: Int)(creditCard: CreditCard): Double = { ... }
}

val creditCards: List[CreditCard] = getCreditCards()

val getPremiumWithTotal = CreditCard.getPremium(creditCards.length)_

val allPremiums = creditCards.map(getPremiumWithTotal).sum


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow