13

Если у меня есть функция:Почему выделки и uncurrying не подразумевается в Скале

f : A => B => C 

я могу определить неявное преобразование такое, что это может быть использовано, когда функция (A, B) => C ожидается. Это происходит и в другом направлении.

Почему эти преобразования не являются неявным (или доступны неявно)? Я предполагаю, что могут произойти плохие вещи за какое-то значение плохих вещей. Какая это ценность?

ответ

12

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

implicit def curryImplicitly[A,B,C](f: (A, B) => C) = 
    (a: A) => (b: B) => f(a, b) 
implicit def uncurryImplicitly[A,B,C](f: A => B => C) = 
    (a: A, b: B) => f(a)(b) 

С другой стороны, это также было бы полезно.

implicit def flipImplicitly[A,B,C](f: (A, B) => C) = 
    (b: B, a: A) => f(a, b) 
implicit def flipImplicitlyCurried[A,B,C](f: A => B => C) = 
    (b: B) => (a: A) => f(a)(b) 

Но это не транзитивно, так что вам нужны эти:

implicit def flipAndCurry[A,B,C](f: (A, B) => C) = 
    (b: B) => (a: A) => f(a, b) 
implicit def flipAndUncurry[A,B,C](f: A => B => C) = 
    (b: B, a: A) => f(a)(b) 

Но теперь преобразование неоднозначно. Так что это не все розы.

Давайте знать, как это работает на практике. Вам могут потребоваться эквиваленты для Function3, Function4 и т. Д.

+0

Я не играл с этим в 2.8, но я попробовал это обратно в темные дни 2.7.X, и это, как правило, приводило к сбоям компилятора в типе inferencer iirc. Вещи улучшили справедливый бит на этом фронте, так что, может быть, теперь все хорошо ... –

+0

Да, все равно слишком сложно скомпрометировать компилятор, если вы попытаетесь сделать его более высокодоходным, но это значительно улучшилось 2,7. – Apocalisp

+0

Я попробовал их в 2.8 для простых случаев, и все прошло хорошо. – thSoft

8

Вы не хотите, чтобы они были неявно доступны по умолчанию (всегда включено), потому что тогда система типов не может помочь вам, когда вы перегружены аргументами из группы аналогичные товары:

A => B => C 
D => C  // D is allowed to be a tuple (A,B)... 

(A,B) => C // If I have this, to whom should I convert? 

Часть преимуществ сильного ввода предупреждает вас, когда вы сделали что-то глупое. Пытаться слишком усердно, чтобы что-то сделать, снижает преимущества. Здесь, если конверсии выполнялись автоматически, вы не можете вызвать метод, который вы хотите вызвать.

Наличие в наличии неявно по запросу в порядке, но это не так сложно сделать самому, если вам это нужно. Это то, что я использовал бы довольно редко; Я бы не поместил его в первую десятку или, возможно, даже сотню вещей, которые мне бы хотелось в библиотеке (отчасти потому, что я предпочел бы автоматическое преобразование в кортеж вместо автоматического currying/uncurrying).

+4

Обратите внимание, что вы не сможете перегрузить функцию с помощью аргументов 'A => B => C' и' D => C', потому что они имеют одинаковое стирание. Таким образом, проблема не будет возникать на практике. – Apocalisp

+0

А, это ты. По-прежнему полезно иметь подписи типов как двойную проверку, если вы используете разные имена методов, но неправильно введите имя метода. –