Вопросы, связанные с картой в Scala

У меня есть несколько вопросов, связанных с картой. Здесь я спрашиваю их один за другим

1) http://twitter.github.com/scala_school/basics.html дает пример функции curried - я думал, что это определение функции, но на самом деле это не так. REPL не признает это как действительный оператор вообще.

multiplyThenFilter { m: Int =>   m * 2 } { n: Int =>   n < 5}

2) Почему мы не можем определить функцию из частично параметризованного метода? то есть что неправильно со следующим определением?

scala> def multiply(m: Int, n: Int): Int = m * n
multiply: (m: Int, n: Int)Int

scala> val timesTwo = multiply(2,_)
<console>:11: error: missing parameter type for expanded function ((x$1) => multiply(2, x$1))
       val timesTwo = multiply(2,_)
                                 ^

3) Почему мы не можем сделать частично параметризованную функцию? то есть что неправильно со следующим определением?

scala> (multiply(_,_)).curried
  res13: Int => (Int => Int) = <function1>  // THIS IS OK

scala> (multiply(20,_)).curried
<console>:12: error: missing parameter type for expanded function ((x$1) => multiply(20, x$1))
              (multiply(20,_)).curried
                           ^

Ответ 1

Вопрос 1

Пример Scala School - путаница - это определенно не определение. Там проблема открыта для него на GitHub, так что, возможно, это ошибка. Вы можете себе представить, что разумное определение может выглядеть так:

def multiplyThenFilter(f: Int => Int)(p: Int => Boolean): Int => Option[Int] = {
  i =>
    val j = f(i)
    if (p(j)) Some(j) else None
}

(или, что то же самое, f andThen (Some(_) filter p).)

Тогда примером будет функция, которая удваивает свой вход и возвращает результат в Some, если он меньше 5, а None в противном случае. Но никто не знает точно, что автор намеревался, пока не будет ответа на этот вопрос.


Вопрос 2

Причина, по которой ваш timesTwo не работает, заключается в том, что компилятор Scala не поддерживает такой тип вывода - см. этот вопрос и мой ответ там для немного связанных деталей. Вам нужно будет выполнить одно из следующих действий:

def multiply(m: Int, n: Int): Int = m * n    
val timesTwo = multiply(2, _: Int)

def multiply(m: Int)(n: Int): Int = m * n    
val timesTwo = multiply(2) _

I.e., если вы хотите ввести здесь тип, вам нужно будет использовать несколько списков параметров. В противном случае вам нужно помочь компилятору с типом.


Вопрос 3

Для вашего третьего вопроса предположим, что у вас есть следующее, чтобы избежать проблемы в вашем втором вопросе:

val timesTwo = multiply(2, _: Int)

Это Function1, который просто не имеет метода curried. Для этого вам нужен Function2 (или Function3 и т.д.).

Просто не имеет смысла говорить о каррировании функции с помощью одного аргумента. Currying выполняет функцию с несколькими аргументами и дает вам функцию, принимающую один аргумент, который возвращает другую функцию (которая сама по себе принимает один аргумент и возвращает другую функцию и т.д.).