È possibile eseguire un foldLeft
in un elenco di argomenti, in cui il valore iniziale fornito alla piega è una funzione completamente elaborata, l'operatore è apply
e l'elenco è un elenco di argomenti da passare alla funzione f
?Applicazione di un elenco di argomenti alla funzione di piegatura utilizzando foldLeft in Scala
Per esempio, diciamo che f è definito come:
scala> val f = (i: Int, j: Int, k: Int, l: Int) => i+j+k+l
f: (Int, Int, Int, Int) => Int = <function4>
cui possiamo naturalmente utilizzare direttamente:
scala> f(1, 2, 3, 4)
res1: Int = 10
O curry e applicare gli argomenti uno alla volta:
scala> f.curried
res2: Int => Int => Int => Int => Int = <function1>
scala> f.curried.apply(1).apply(2).apply(3).apply(4)
res3: Int = 10
A prima vista sembra un lavoro per foldLeft
.
Il mio primo tentativo di descrivere questa sequenza di apply
usando foldLeft
assomiglia:
scala> List(1, 2, 3, 4).foldLeft(f.curried)({ (g, x) => g.apply(x) })
tuttavia, che produce il seguente errore:
<console>:9: error: type mismatch;
found : Int => Int => Int => Int
required: Int => Int => Int => Int => Int
List(1, 2, 3, 4).foldLeft(f.curried)({ (g, x) => g.apply(x) })
La mia lettura del messaggio di errore è che l'inferenza dei tipi avrebbe bisogno di qualche suggerimento per g
.
La soluzione che sto cercando lascia tutto non modificato nella mia espressione originale, tranne il tipo di g
:
List(1, 2, 3, 4).foldLeft(f.curried)({ (g: ANSWER, x) => g.apply(x) })
Il mio primo pensiero è stato che un tipo di unione sarebbe utile qui. Ho visto la derivazione di Miles Sabin dei tipi di unione usando Curry-Howard, quindi se quella prima impressione è vera, allora mi sembra di avere i meccanismi di base necessari per risolvere il problema.
Tuttavia: anche se i tipi di unione sono la risposta, sarebbe utile se potessi fare riferimento a "L'unione di tutti i tipi dal tipo completamente curried di una funzione al tipo di funzione al curry con tutto tranne l'ultimo argomento fornito ". In altre parole, un modo per trasformare il tipo:
T1 => ... => Tn
nel tipo unione:
(T1 => ... => Tn) |∨| ... |∨| (Tn-1 => Tn)
sarebbe utile come il tipo per g
sopra.
Facendo un foldLeft
su una List
limita la discussione al caso in cui T1
attraverso Tn-1
sono tutti uguali. Una notazione come
(T1 =>)+ Tn
sarebbe descrivere il tipo che voglio prevedere g
.
Il caso specifico che sto chiedendo non richiede arbitrariamente lunghe catene, così abbiamo potuto fornire limiti sul iteratore utilizzando
(T1 =>){1,4} Tn
Guardando avanti a voler fare questo per catene di tipi che non sono uguale, anche se, forse qualche funzione magica sui tipi che sminuzza la catena nel set di tutti i suffissi è più utile:
Suffixes(T1 => ... => Tn)
implementazione di questo è ben al di là delle mie capacità Scala al momento. Sarebbe apprezzato qualsiasi suggerimento su come farlo. Se questo può essere fatto con l'uso avanzato del sistema di tipi esistente di Scala o attraverso un plug-in del compilatore o nessuno dei due, non lo so.
Come è stato notato nei commenti seguenti, chiamare il risultato un "tipo di unione" non è perfetto per questo caso d'uso. Non so cos'altro dire, ma questa è l'idea più vicina che ho al momento. Altre lingue hanno un supporto speciale per questa idea? Come funzionerebbe in Coq e Agda?
La denominazione di questo problema e la comprensione di dove si colloca rispetto all'immagine più grande (di teoria dei tipi, decidibilità e così via) è più importante per me che avere un'implementazione funzionante di ANSWER
, anche se entrambi sarebbero belli. Punti bonus per chiunque sia in grado di tracciare connessioni con Scalaz, Monoidi o Teoria delle categorie in generale.
non sono sicuro che i tipi di unione sono il modo di andare qui. Sembra che tu stia cercando una cosa simile a una piega della funzione al curry sugli argomenti rappresentati come HList. Penso che qualcosa del genere sia probabilmente fattibile. Comunque, è un problema interessante ... Indagherò e risponderò correttamente se trovo qualcosa di lavorabile. –
Wow - grazie, Miles. Mi piacerebbe sapere cosa ne pensi di questo problema. Sono d'accordo che i tipi di sindacato, di per sé, sembrano non essere esattamente ciò che è richiesto in questa situazione. –
@MilesSabin Ho chiarito la mia domanda e ho proposto alcune forme che una risposta potrebbe assumere. Non sono ancora chiaro se questo sia o dovrebbe essere possibile, ma in entrambi i casi questo è stato un buon esercizio per me parlarne. –