Não entendo a digitação das continuações delimitadas de Scala (um @cpsparam [b, c])
-
19-09-2019 - |
Pergunta
Estou lutando para entender o que significa precisamente quando um valor tem tipo A @cpsParam[B,C]
e que tipos deste formulário devo atribuir aos meus valores ao usar o recurso de continuação delimitado.
Eu olhei para algumas fontes:
http://lamp.epfl.ch/~trompf/continuations-icfp09.pdf
http://www.scala-lang.org/node/2096
http://dcsobral.blogspot.com/2009/07/delimited-continuations-explined-in.html
http://blog.richdougherty.com/2009/02/delimited-continuations-in-scala_24.html
Mas eles não me deram muita intuição a isso. No último link, o autor tenta dar uma explicação explícita, mas não é claro o suficiente de qualquer maneira.
O A aqui representa a saída do cálculo, que também é a entrada para sua continuação. O B representa o tipo de retorno dessa continuação, e o C representa seu tipo de retorno "final" - porque a mudança pode fazer um processamento adicional para o valor retornado e alterar seu tipo.
Não entendo a diferença entre "saída do cálculo", "tipo de retorno da continuação" e "Tipo de retorno final da continuação". Eles parecem sinônimos.
Solução
Então, as pessoas me ajudaram com isso em outro lugar. Aqui está a resposta:
reset ({
...
...shift((k:A=>B) => ...::C)::A...
...
}::B)::C
Então, shift
é um buraco do tipo A
em um cálculo {...}
do tipo B
. O argumento de shift
Retorna um valor do tipo C
e é por isso reset ({...})
tem tipo C
.
O truque principal para entender esse material era ver que {...}
e reset {...}
tem tipo diferente, dependendo de que tipo de shift
O argumento de Returna.
Por exemplo:
reset ({
"number "+shift((k:Int=>String) => List(k(1), k(2), k(3)))
})
retorna List("number 1", "number 2", "number 3")
.
Aqui A
é Int
, B
é String
, C
é List[String]
Porque {"number" + _}
é (aqui) uma função de Int
para String
e o argumento de shift
, dada essa função, produz um List[String]
, que se torna resultado do reset({...})
.
Outras dicas
Ainda estou em um processo de descobrir as regras/implicações exatas de digitação envolvidas aqui.
Parece fácil/mais fácil se os tipos nos exemplos forem "simples o suficiente" para "se encaixar bem", como mostrado acima, mas se torna mais interrevagante/difícil (pelo menos para mim) ao comparar as coisas com a digitação do TIARK ROMPF:
|- e: A@cpsParam[B,C]; {[|r|]}: U
-----------------------------------------------------
[|val x: A = e; r|] = [|e|].map( (x: A) => {[|r|]} )
Então, o resultado de [|e|].map( (x: A) => {[|r|]} )
terá o tipo Shift[U,B,C]
De acordo com a definição de mapa dado no artigo de Tiark.
Aqui você não é necessariamente o mesmo que B.
Até agora eu não entendo por que você pode ser diferente de B sem algo comoU <: B
dado na definição de mapa no artigo de Tiark.
O que estou perdendo o Repsectivamente, deixando de entender aqui?
Alguma dica/idéias?