Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

262
Visualizações
Relación entre las funciones de suspensión de Arrow y la comprensión de la mónada

Soy nuevo en Arrow y trato de establecer mi modelo mental de cómo funciona su sistema de efectos; en particular, cómo aprovecha el sistema de suspend de Kotlin. Mi muy vago entendimiento es el siguiente; si sería genial si alguien pudiera confirmarlo, aclararlo o corregirlo:

Debido a que Kotlin no admite tipos de tipos superiores, implementar aplicativos y mónadas como clases de tipos es engorroso. En cambio, arrow deriva su funcionalidad de mónada (vincular y devolver) para todos los tipos monádicos de Arrow de la primitiva de continuación que ofrece el mecanismo de suspensión de Kotlin. ¿Es esto correcto? En particular, el comportamiento de cortocircuito (por ejemplo, para nullable o either de los dos) se implementa de alguna manera como una continuación delimitada. No entendí qué característica particular de la maquinaria de suspensión de Kotlin entra en juego aquí.

Si lo anterior es correcto en términos generales, tengo dos preguntas de seguimiento: ¿Cómo debo contener el alcance de las operaciones monádicas que no son IO? Tome un ejemplo simple de construcción y validación de objetos:

 suspend fun mkMessage(msgType: String, appRef: String, pId: String): Message? = nullable { val type = MessageType.mkMessageType(msgType).bind() val ref = ApplRefe.mkAppRef((appRef)).bind() val id = Id.mkId(pId).bind() Message(type, ref, id) }

En la notación do de Haskell, esto sería

 mkMessage :: String -> String -> String -> Maybe Message mkMessage msgType appRef pId = do type <- mkMessageType msgType ref <- mkAppRef appRef id <- mkId pId return (Message type ref id)

En ambos casos, la función devuelve el tipo de mónada (un valor anulable, o tal vez). Sin embargo, aunque puedo usar la función pura en Haskell en cualquier lugar que considere adecuado, la función de suspensión en Kotlin solo se puede llamar desde dentro de una función de suspensión. De esta manera, una comprensión de mónada simple que no sea de IO en Arrow se comporta como una mónada de IO que debe estar enhebrada a lo largo de mi base de código; Supongo que esto se debe a que el mecanismo de suspensión fue diseñado para operaciones de E/S reales. ¿Cuál es la forma recomendada de implementar comprensiones de mónadas no IO en Arrow sin convertir todas las funciones en funciones de suspensión? ¿O es este realmente el camino a seguir?

Segundo: si además de las mónadas que no son IO (anulables, lectores, etc.), quiero tener IO, por ejemplo, leer un archivo y analizarlo, ¿cómo combinaría estos dos efectos? ¿Es correcto decir que habría múltiples ámbitos de suspensión correspondientes a las diferentes mónadas involucradas, y que de alguna manera necesitaría anidar estos ámbitos, como si apilara transformadores de mónadas en Haskell?

Las dos preguntas anteriores probablemente significan que todavía me falta un modelo mental que sirva de puente entre la implementación basada en continuación sobre el mecanismo de suspensión de Kotlin con la implementación genérica de mónada como clase de tipos en Haskell.

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

schuster,

Tienes razón en que Arrow usa la función de suspensión de Kotlin para codificar algo así como comphrensions de mónadas.

Para responder a tu primera pregunta:

Kotlin tiene suspend en el idioma (y Kotlin Std), por defecto, la suspend solo se puede llamar desde otro código de suspend . Sin embargo, el compilador también tiene una función llamada RestrictsSuspension , que no permite mezclar ámbitos de suspend y, por lo tanto, no permite combinar IO y Either , por ejemplo. Exponemos un DSL secundario, cualquiera. either.eager que está codificado usando RestrictsSuspension y no permite llamar a funciones de suspensión externas .

Esto le permite codificar mkMessage :: String -> String -> String -> Maybe Message .

 fun mkMessage(msgType: String, appRef: String, pId: String): Message? = nullable.eager { val type = MessageType.mkMessageType(msgType).bind() val ref = ApplRefe.mkAppRef((appRef)).bind() val id = Id.mkId(pId).bind() Message(type, ref, id) }

Para responder a su segunda pregunta: IO como tipo de datos no es necesario en Kotlin, ya que suspend puede implementar todas las operaciones de IO de una manera transparente referencial como funciona en Haskell . El compilador también realiza muchas optimizaciones en el tiempo de ejecución, al igual que lo hace Haskell para IO .

Entonces, la firma suspend fun example(): Either<Error, Value> es el equivalente de EitherT IO Error Value en Haskell. Sin embargo, las operaciones de IO no se implementan en Kotlin Std, sino en una biblioteca KotlinX Coroutines , y Arrow Fx Coroutines también ofrece algunos tipos de datos y operaciones de nivel superior, como parTraverse , definidas sobre KotlinX Coroutines.

Es ligeramente diferente que en Haskell, ya que podemos mezclar efectos en lugar de apilarlos con transformadores de mónadas. Esto significa que podemos llamar a las operaciones IO desde dentro de Either de las operaciones. Esto se debe a la funcionalidad especial y las optimizaciones que el compilador puede realizar en el sistema de suspensión. Este blog explica cómo funciona esa optimización y por qué es tan poderosa. https://nomisrev.github.io/inline-and-suspend/

Aquí también hay más información sobre las continuaciones y las codificaciones sin etiquetas en Kotlin. https://nomisrev.github.io/continuation-monad-in-kotlin/

Espero que eso responda completamente a su pregunta.

over 4 years ago · Santiago Trujillo Relatório

0

No creo que pueda responder a todo lo que preguntas, pero haré todo lo posible por las partes que sé responder.

¿Cuál es la forma recomendada de implementar comprensiones de mónadas no IO en Arrow sin convertir todas las funciones en funciones de suspensión? ¿O es este realmente el camino a seguir?

puede usar nullable.eager y either.eager respectivamente para código puro. El uso nullable/either (sin .eager ) le permite llamar a las funciones de suspensión internas. El uso eager significa que solo puede llamar a funciones que no están suspendidas. (no todas las funciones efectivas en kotlin están marcadas como suspendidas)

Segundo: si además de las mónadas que no son IO (anulables, lectores, etc.), quiero tener IO, por ejemplo, leer un archivo y analizarlo, ¿cómo combinaría estos dos efectos? ¿Es correcto decir que habría múltiples ámbitos de suspensión correspondientes a las diferentes mónadas involucradas, y que de alguna manera necesitaría anidar estos ámbitos, como si apilara transformadores de mónadas en Haskell?

Puede usar funciones de extensión para emular Reader. Por ejemplo:

 suspend fun <R> R.doSomething(i: Int): Either<Error, String> = TODO()

combina Reader + IO + Either . Puede encontrar un ejemplo más grande aquí de Simon, un mantenedor de Arrow.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda