2010-08-11 13 views
13

Si tengo una función:Por qué se currying y uncurrying no implícita en Scala

f : A => B => C 

puedo definir una conversión implícita de tal manera que esto se puede utilizar cuando se espera una función (A, B) => C. Esto va en la otra dirección también.

¿Por qué estas conversiones no son implícitas (o están disponibles implícitamente)? Estoy asumiendo que cosas malas podrían suceder por algún valor de cosas malas. ¿Qué valor es esto?

Respuesta

12

No creo que vaya a pasar nada malo. La conversión es completamente inequívoca. En el peor de los casos, Scala no podrá darse cuenta de que se aplica la conversión implícita.

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) 

Por otra parte, estos también serían útiles.

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) 

Pero esas no son transitivos, por lo que necesita éstos:

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) 

Pero ahora la conversión es ambigua. Entonces no son todas las rosas.

Sepa cómo funciona en la práctica. Es posible que necesite equivalentes para Function3, Function4, etc.

+0

No he jugado con esto en 2.8, pero probé esto en los días oscuros de 2.7.X y tendía a provocar bloqueos en el compilador, en el tipo iferenc de referencia. Las cosas han mejorado un poco en ese frente, así que tal vez todo está bien ahora ... –

+0

Sí, todavía es demasiado fácil bloquear el compilador si intentas inferir un tipo de mayor nivel, pero es una gran mejora sobre 2.7. – Apocalisp

+0

Probé estos en 2.8 para casos simples, y todo salió bien. – thSoft

8

No desea que estén implícitamente disponibles de forma predeterminada (siempre activada) porque el sistema de tipos tiene problemas para ayudarlo cuando se ha sobrecargado con argumentos de un grupo de tipos similares:

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? 

Parte de la ventaja de la escritura fuerte es advertirle cuando ha hecho algo tonto. Intentar demasiado para que las cosas funcionen reduce los beneficios. Aquí, si las conversiones se realizaron de manera automática, es posible que no llame al método al que desea llamar.

Tenerlos disponibles implícitamente cuando se solicite está bien, pero no es tan difícil hacerlo usted mismo si lo necesita. Esto es algo que usaría muy raramente; No lo pondría en mi top 10 o probablemente ni siquiera en un centenar de cosas que me gustaría tener en la biblioteca (en parte porque preferiría la conversión automática a una tupla en lugar de la función de currying/uncurrying automático).

+4

Tenga en cuenta que no podrá sobrecargar una función con argumentos 'A => B => C' y' D => C', porque tienen el mismo borrado. Entonces, el problema no surgirá de esta manera en la práctica. – Apocalisp

+0

Ah, cierto que eres. Todavía puede ser útil tener firmas de tipo como una doble verificación si usa nombres de método diferentes pero obtiene el nombre del método incorrecto. –

Cuestiones relacionadas