Scala Language
커링
수색…
통사론
- 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는 다음과 같은 몇 가지 언어 기능을 제공합니다.
- 카레 함수를 메소드로 작성할 수 있습니다. 그래서
curriedF
는 다음과 같이 쓸 수 있습니다 :
def curriedFAsAMethod(str: String)(int: Int): Double = 1.0
val curriedF = curriedFAsAMethod _
- 표준 라이브러리 방법을 사용하여 카레를 제거 할 수 있습니다 (예 :
A => B => C
에서(A, B) => C
) :Function.uncurried
val f: (String, Int) => Double = Function.uncurried(curriedF)
f("a", 1) // => 1.0
Currying을 사용하는 경우
currying 은 다중 인수를 취하는 함수의 평가를 하나의 인수를 사용하여 함수 순서를 평가하는 것으로 변환하는 기술입니다 .
일반적으로 다음과 같은 경우에 유용합니다.
- 함수의 다른 인수는 다른 시간에 계산 됩니다 . (실시 예 1)
- 함수의 다른 인수 는 응용 프로그램의 다른 계층에 의해 계산 됩니다 . (실시 예 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