13

Se ho una funzione:Perché currying e uncurrying non implicito nella scala

f : A => B => C 

posso definire una conversione implicita in modo tale che questo può essere usato dove è prevista una funzione di (A, B) => C. Questo va anche nella direzione opposta.

Perché queste conversioni non sono implicite (o disponibili implicitamente)? Suppongo che cose brutte potrebbero accadere per un certo valore di cose cattive. Che valore è questo?

risposta

12

Non credo che accada qualcosa di brutto. La conversione è completamente non ambigua. Nel caso peggiore, Scala non sarà in grado di capire che si applica la conversione implicita.

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) 

Quindi, anche in questo caso sarebbe utile.

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) 

Ma quelli non sono transitiva, quindi è necessario questi:

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) 

Ma ora la conversione è ambiguo. Quindi non sono tutte rose.

Sappiamo come funziona in pratica. Potresti aver bisogno di equivalenti per Function3, Function4, ecc.

+0

Non ho giocato con questo in 2.8, ma l'ho provato nei giorni bui di 2.7.X e tendeva a causare arresti anomali del compilatore, nel tipo inferirore iirc. Le cose sono migliorate un po 'su quel fronte, quindi forse è tutto buono ora ... –

+0

Sì, è ancora troppo facile mandare in crash il compilatore se cerchi di inferire un tipo più alto, ma è un enorme miglioramento rispetto a 2.7. – Apocalisp

+0

Ho provato questi in 2.8 per casi semplici, e tutto è andato bene. – thSoft

8

Non li vuoi implicitamente disponibili per impostazione predefinita (sempre attivo) perché il sistema di tipi ha problemi ad aiutarti quando hai sovraccaricato argomenti di un gruppo di tipi simili:

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 del vantaggio di una digitazione forte ti avverte quando hai fatto qualcosa di sciocco. Tentare troppo per far funzionare le cose riduce i benefici. Qui, se le conversioni fossero state eseguite automaticamente, potresti non chiamare il metodo che intendevi chiamare.

Averli disponibili implicitamente su richiesta va bene, ma non è così difficile farlo da soli se ne hai bisogno. Questo è qualcosa che userei abbastanza raramente; Non lo inserirò nella mia top ten o forse anche nella top 100 che mi piacerebbe in biblioteca (in parte perché preferirei la conversione automatica a una tupla invece che al curry automatico/non ricorrente).

+4

Nota che non sarai in grado di sovraccaricare una funzione con argomenti 'A => B => C' e' D => C', perché hanno la stessa cancellazione. Quindi il problema non si presenterà in questo modo nella pratica. – Apocalisp

+0

Ah, giusto sei. Può ancora essere utile avere le firme dei tipi come controllo doppio se si usano nomi di metodi diversi ma si ottiene il nome del metodo sbagliato. –

Problemi correlati