복붙노트

[SCALA] 스칼라 함수의 일부인가 대 무두질

SCALA

스칼라 함수의 일부인가 대 무두질

여기 태닝 부분적으로 적용되는 기능이 무엇인지에 대한 여러 질문이 있다는 것을 알지만 나는 그들이 다른 방법에 대해 부탁 해요. 간단한 예를 들어, 여기에 짝수를 찾기위한 카레 기능은 다음과 같습니다

def filter(xs: List[Int], p: Int => Boolean): List[Int] =
   if (xs.isEmpty) xs
   else if (p(xs.head)) xs.head :: filter(xs.tail, p)
   else filter(xs.tail, p)

def modN(n: Int)(x: Int) = ((x % n) == 0)

그래서 당신은이를 사용하려면 다음을 작성할 수 있습니다 :

val nums = List(1,2,3,4,5,6,7,8)
println(filter(nums, modN(2))

이는 반환 목록 (2,4,6,8). 하지만 내가 같은 일이 방법을 수행 할 수 있음을 발견했습니다 :

def modN(n: Int, x: Int) = ((x % n) == 0)

val p = modN(2, _: Int)
println(filter(nums, p))

이는 또한 반환 목록 (2,4,6,8).

그래서 내 질문은 무엇 둘 사이의 주요 차이점은, 그리고 때 다른 이상을 사용하는 것입니까? 하나가 다른 걸쳐 사용되는 이유는 예 너무 단순한인가를 보여?

해결법

  1. ==============================

    1.의미 론적 차이는 스티 그 로브에 의해 연결이 질문에 대해 꽤 잘 설명하고있다.

    의미 론적 차이는 스티 그 로브에 의해 연결이 질문에 대해 꽤 잘 설명하고있다.

    기능면에서,하지만 큰 차이가 보이지 않는다. 의은을 확인하기 위해 몇 가지 예를 살펴 보자. 첫째, 정상적인 기능 :

    scala> def modN(n: Int, x: Int) = ((x % n) == 0)
    scala> modN(5, _ : Int)
    res0: Int => Boolean = <function1>
    

    그래서 우리가 얻을 부분적으로 적용 <기능 1> 우리는 이미 그것을 첫 번째 정수를 부여했기 때문에, int를 걸립니다. 여태까지는 그런대로 잘됐다. 이제 무두질로 :

    scala> def modNCurried(n: Int)(x: Int) = ((x % n) == 0)
    

    이 표기법으로, 당신은 순진 작업에 다음을 기대 :

    scala> modNCurried(5)
    <console>:9: error: missing arguments for method modN;
    follow this method with `_' if you want to treat it as a partially applied function
              modNCurried(5)
    

    그래서 여러 매개 변수 목록 표기법 정말 당장 카레 함수를 작성하지 않는 것 (가정하여 불필요한 오버 헤드를 피하기 위해)하지만 당신은 명시 적으로는 (표기뿐만 아니라 다른 장점이 있습니다) 카레 원하는 상태로 기다립니다 :

    scala> modNCurried(5) _
    res24: Int => Boolean = <function1>
    

    어떤 우리가 전에 가지고 정확히 같은 일 때문에 표기를 제외하고 여기에 차이점이다. 또 다른 예:

    scala> modN _
    res35: (Int, Int) => Boolean = <function2>
    
    scala> modNCurried _
    res36: Int => (Int => Boolean) = <function1>
    

    이것은 부분적으로 다수의 파라미터리스트를 가진 함수를 적용하는 함수의 체인 모두가 새로운 기능을 리턴 파라미터리스트 하나씩 생성 반면 부분적으로 모든 파라미터를 취하는 함수에 "정상"기능의 결과를 적용하는 방법을 보여

    scala> def foo(a:Int, b:Int)(x:Int)(y:Int) = a * b + x - y
    scala> foo _
    res42: (Int, Int) => Int => (Int => Int) = <function2>
    
    scala> res42(5)
    <console>:10: error: not enough arguments for method apply: (v1: Int, v2: Int)Int => (Int => Int) in trait Function2.
    Unspecified value parameter v2.
    

    당신이 볼 수 있듯이 foo는의 첫 번째 매개 변수 목록은 두 개의 매개 변수를 가지고 있기 때문에,의 카레 체인의 첫 번째 함수는 두 개의 매개 변수가 있습니다.

    요약하면, 부분적으로 적용된 기능은 기능면에서 다른 형태의 카레 기능은 정말 없습니다. 이것은 쉽게 커리 하나에 모든 기능을 변환 할 수 있습니다 주어진 확인 :

    scala> (modN _).curried
    res45: Int => (Int => Boolean) = <function1
    
    scala> modNCurried _
    res46: Int => (Int => Boolean) = <function1>
    

    참고 : modN (2) 스칼라 컴파일러는 단순히 프로그래머의 편의를 강조하는 가정 것 같다 후 예에 println (필터 (nums, modN (2)) 밑줄없이 작동하는 이유를.

    추가 @asflierl 지적 제대로 바와 같이, 스칼라는 부분적으로 "정상"기능을 적용 할 때 유형을 추론 할 수있을 것 같지 않습니다

    scala> modN(5, _)
    <console>:9: error: missing parameter type for expanded function ((x$1) => modN(5, x$1))
    

    정보 반면 여러 매개 변수 목록 표기법을 사용하여 작성 기능을 사용할 수 있습니다 :

    scala> modNCurried(5) _
    res3: Int => Boolean = <function1>
    

    이 답변이 매우 유용 할 수있는 방법을 보여줍니다.

  2. ==============================

    2.그 반대의 경우도 마찬가지 소요 n은 별도의 인수 및 하나에 튜플 인수를받는 함수를 돌려 : 커링은 튜플로 할 것입니다. 이도 깨끗하게 태닝을 지원하지 않는 언어, 부분 응용 프로그램 대 카레를 구별의 핵심입니다 기억.

    그 반대의 경우도 마찬가지 소요 n은 별도의 인수 및 하나에 튜플 인수를받는 함수를 돌려 : 커링은 튜플로 할 것입니다. 이도 깨끗하게 태닝을 지원하지 않는 언어, 부분 응용 프로그램 대 카레를 구별의 핵심입니다 기억.

    curry :: ((a, b) -> c) -> a -> b -> c 
       -- curry converts a function that takes all args in a tuple
       -- into one that takes separate arguments
    
    uncurry :: (a -> b -> c) -> (a, b) -> c
       -- uncurry converts a function of separate args into a function on pairs.
    

    일부 응용 프로그램은 나머지 인수를위한 새로운 기능을 산출 일부 인수에 함수를 적용 할 수있는 기능입니다.

    당신이 단지 태닝이 튜플과 함께 할 수있는 변화라고 생각하면 기억하기 쉽다.

    (예 : 하스켈)는 디폴트로 카레하는 언어의 차이는 분명하다 - 당신이 실제로 터플에 인수를 전달하는 일을해야합니다. 모든 인수가 튜플로 전달됩니다, 그래서 uncurry 훨씬 덜 유용, 덜 분명하다 / 카레 -하지만 스칼라를 포함한 대부분의 다른 언어는 기본적으로 uncurried된다. 그들은 쉽게 카레 기능을 나타냅니다 수 없다해서 - 그리고 사람들은 일부 응용 프로그램 및 무두질이 같은 일이다라고 생각 끝!

  3. ==============================

    3.다 변수 기능 :

    다 변수 기능 :

    def modN(n: Int, x: Int) = ((x % n) == 0)
    

    무두질 (또는 카레 함수) :

    def modNCurried(n: Int)(x: Int) = ((x % n) == 0)
    

    그래서 부분적으로 무두질 비교의 기능을 적용 아니에요. 그것은 다 변수 기능입니다. 어떤 기능의 일부인가에 필적 것은 부분적으로 도포 기능이있는 동일한 파라미터리스트 함수 인 카레 함수의 호출 결과이다.

  4. ==============================

    4.그냥 마지막 점을 명확히

    그냥 마지막 점을 명확히

    모든 매개 변수가 그들 중 일부가 지정된 경우 와일드 카드가 아닌이며, 그들 중 일부하지 않을 경우 스칼라 유형을 추론 할 수있다.

    scala> modN(_,_)
    res38: (Int, Int) => Boolean = <function2>
    
    scala> modN(1,_)
    <console>:13: error: missing parameter type for expanded function ((x$1) => modN(1, x$1))
           modN(1,_)
                  ^
    
  5. from https://stackoverflow.com/questions/14309501/scala-currying-vs-partially-applied-functions by cc-by-sa and MIT license