Non capisco la tipizzazione delle continuazioni delimitati di Scala (A @cpsParam [B, C])
-
19-09-2019 - |
Domanda
sto lottando per capire cosa esattamente vuol dire quando un valore è di tipo A @cpsParam[B,C]
e quali tipi di questa forma dovrei assegnare ai miei valori quando si utilizza l'impianto continuazioni delimitato.
Ho guardato alcune fonti:
http://lamp.epfl.ch/~rompf/continuations-icfp09 .pdf
http://www.scala-lang.org/node/2096
http://dcsobral.blogspot.com/2009 /07/delimited-continuations-explained-in.html
http://blog.richdougherty.com/2009 /02/delimited-continuations-in-scala_24.html
, ma non mi hanno dato molta intuizione in questo. Nel l'ultimo anello, l'autore cerca di dare una spiegazione esplicita, ma non è abbastanza chiaro in ogni caso.
L'A qui rappresenta l'uscita del calcolo, che è anche l'ingresso alla sua continuazione. Il B rappresenta il tipo di ritorno che il mantenimento e il C rappresenta il suo ritorno tipo perché "finale" shift può fare ulteriore trattamento al valore restituito e cambiare il tipo.
Non capisco la differenza tra "uscita del calcolo", "tipo di ritorno della continuazione" e "tipo ritorno finale della continuazione". Suonano come sinonimi.
Soluzione
Così, la gente mi ha aiutato con questo altrove. Ecco la risposta:
reset ({
...
...shift((k:A=>B) => ...::C)::A...
...
}::B)::C
Quindi, shift
è un foro di tipo A
in una {...}
calcolo di tipo B
. L'argomento di shift
restituisce un valore di tipo C
ed è per questo reset ({...})
ha tipo C
.
Il trucco chiave nella comprensione di questo roba era di vedere che {...}
e reset {...}
hanno diverso tipo a seconda del tipo ritorna l'argomento del shift
.
Ad esempio:
reset ({
"number "+shift((k:Int=>String) => List(k(1), k(2), k(3)))
})
ritorna List("number 1", "number 2", "number 3")
.
Qui A
è Int
, B
è String
, C
è List[String]
perché {"number" + _}
è (qui) una funzione da Int
al String
e l'argomento di shift
, in tale funzione, produce una List[String]
, che diventa risultato della reset({...})
.
Altri suggerimenti
Sono ancora in un processo di capire l'esatta battitura regole / implicazioni coinvolte nel qui.
Sembra facile / più facile se i tipi negli esempi sono "abbastanza semplice" a "adattarsi bene", come indicato sopra, ma diventa più interresting / difficile (almeno per me) nel confronto tra le cose al di battitura dare da tiark Rompf:
|- e: A@cpsParam[B,C]; {[|r|]}: U
-----------------------------------------------------
[|val x: A = e; r|] = [|e|].map( (x: A) => {[|r|]} )
in modo che il risultato di [|e|].map( (x: A) => {[|r|]} )
avrà il tipo Shift[U,B,C]
secondo la definizione di carta dato in carta di tiark.
Qui U non è necessariamente essere uguale a B.
Finora non capisco il motivo per cui U è consentito di essere diverso da B senza qualcosa di simile
U <: B
data nella definizione di carta in carta di tiark.
Che cosa mi manca repsectively non riuscendo a capire qui?
Qualche consiglio / idee?