No se pueden proporcionar entradas largas (más de 1024 caracteres) a OCaml toplevel y coqtop (y Proof General)

Editar 4: Resulta que esto es en realidad solo una limitación de la entrada TTY en general; no hay nada específico sobre OCaml, Coq o Emacs que esté causando el problema.


Estoy trabajando en un programa Coq usando Proof General en Emacs y encontré un error con una entrada que es demasiado larga. Si una región para enviar a coqtop a través de Proof General contiene más de 1023 caracteres, Proof General (aunque no Emacs) se bloquea mientras espera una respuesta y el *coq* el búfer contiene uno extra ^G carácter por cada carácter superior a 1023. Por ejemplo, si se envió una región de 1025 caracteres a coqtop, Entonces el *coq* el búfer terminaría con los dos caracteres adicionales ^G^G. No puedo continuar más allá de este punto en el archivo, y tengo que matar el coqtop proceso (ya sea con Cc Cx o con una kill/killall de la terminal).

Algo acerca de esta limitación surge de coqtop sí mismo. Si uno genera una cadena de 1024 caracteres o más y la canaliza, como ejecutando

perl -e 'print ("Eval simpl in " . (" " x 1024) . "1.\n")' | coqtop

entonces todo funciona bien. (Similar, coqc funciona bien también.) Sin embargo, si corro coqtop en una terminal, no puedo escribir más de 1024 caracteres en una línea, incluso el carácter de retorno final. Por lo tanto, escribir una línea de 1023 caracteres y luego presionar Intro funciona; pero después de escribir 1024 caracteres, presionar cualquier tecla, incluido el retorno (pero sin incluir la eliminación, etc.), no hace más que producir un pitido. Y resulta que ocaml (el nivel superior de OCaml) tiene el mismo comportamiento:

perl -e 'print ((" " x 1024) . "1;;")' | ocaml

funciona bien, pero no puedo escribir más de 1024 caracteres en una línea si ejecuto ocaml desde una terminal. Ya que tengo entendido que coqtop se basa en el nivel superior de OCaml (más obviamente cuando se ejecuta como coqtop -byte), me imagino que esta es una limitación relacionada.

Las versiones de software relevantes son:

Y mis preguntas son:

  • Qué pasa ocaml y coqtop está haciendo cumplir este límite de caracteres? ¿Y por qué solo para la entrada desde la terminal o Emacs, a diferencia de la entrada desde una tubería o un archivo?
  • ¿Por qué la (aparente) ignorancia de Proof General de este límite causa errores colgantes y errores misteriosos? ^Gs?
  • ¿Cómo puedo evitar esta limitación? Mi objetivo final es usar Coq dentro de Proof General/Emacs, por lo que las soluciones alternativas que eluden el problema subyacente están bien.

Editar 3: Después de descubrir que la limitación de entrada de 1024 caracteres también existe en el nivel superior de Ocaml (algo que imagino que está relacionado), agregué esa información y eliminé la descripción original del problema, ya que se oscureció por completo y se reemplazó. (Ver el historial de edición si necesario).

preguntado el 04 de julio de 12 a las 03:07

2 Respuestas

Reporté esto como problema 5678 en el rastreador de errores de OCaml, y el usuario dim explicó que esto no era un problema con OCaml per se, pero era una limitación de entrada TTY. El asunto es este. Dado que el texto no se envía a los comandos en ejecución hasta que el usuario presiona regresar, toda esa entrada en espera debe almacenarse en algún lugar. El búfer en el que se almacena, llamado cola de entrada o búfer de escritura anticipada, tiene un tamaño fijo, que está controlado por la constante C MAX_INPUT. Esta constante es igual a 1024 en Mac OS X. El almacenamiento en búfer como este permite un procesamiento útil de la entrada, como la eliminación de caracteres antes de que se envíen. Todos los comandos se ejecutan desde la terminal que no hacen nada especial (como usar el readline biblioteca) mostrará este comportamiento; por ejemplo, cat se ahoga exactamente de la misma manera.

Para evitar este comportamiento, se puede desactivar el ICANON bandera, por ejemplo ejecutando stty -icanon; esto pone el TTY en modo de entrada no canónico, donde la entrada no se procesa en absoluto antes de enviarse al comando. Esto significa que la edición se vuelve imposible: eliminar, las flechas izquierda y derecha, etc., ingresan todos sus equivalentes literales (^?, ^[[D, ^[[C, …); similar, ⌃D ya no envía un EOF, sino simplemente un carácter de control literal. Sin embargo, para mi caso de uso particular, esto (¡hasta ahora!) parece ser ideal, ya que Emacs está manejando todas mis entradas por mí. (Edit: ¡Pero hay una mejor opción!) (Bibliotecas como readline, según tengo entendido, cambie esta configuración también, pero tenga cuidado con los caracteres de control y la edición de manejo, etc., ellos mismos). Para restaurar el modo canónico, uno puede ejecutar stty icanon.

El ledit herramienta envuelve la edición de línea alrededor del programa que se le da como argumento, por lo que ledit coqtop funciona bien (aunque extrañamente; prefiero ledit -l 65536 para evitar su desplazamiento), pero interactuaba extrañamente con Emacs. los rlwrap tool hace lo mismo, pero deja al otro programa leyendo desde un TTY; así, mientras it puede recibir entradas más largas, presionar enter y enviarlas al comando envuelto se comporta de manera muy extraña y termina necesitando que se elimine el comando.

Edit: En mi caso de uso específico, también puedo simplemente decirle a Emacs que use una canalización en lugar de un PTY, resolviendo los problemas de un plumazo. La variable Emacs process-connection-type controla cómo se comunican los procesos subsidiarios; nil medios para usar una pipa, y no-nil significa usar un TTY. Prueba General usa la variable proof-shell-process-connection-type para determinar cómo debe configurarse. El uso de una tubería resuelve todos los problemas de límite de 1024 caracteres.

respondido 20 mar '17, 10:03

No estoy seguro de cómo funciona aquí la interacción Emacs/coqtop, pero creo que de hecho hay un error de nivel superior de OCaml, y debería informarse en el rastreador de errores de OCaml. ¿Estaría dispuesto a denunciarlo? Si no, puedo encargarme de eso.

¿Qué sucede con ocaml y coqtop que imponen este límite de caracteres?

Hay varios búfer de entrada en juego en el código de nivel superior, algunos de ellos de longitud 1024; después de una mirada rápida al código, hay una lógica de cambio de tamaño en caso de que la entrada sea demasiado grande, por lo que debemos trabajo. He podido reproducir el problema "no se pueden escribir más de N caracteres en el nivel superior interactivo" (cuando no se usa rlwrap), pero con un límite N=4096 en lugar de N=1024, por lo que no estoy seguro de que sea exactamente el mismo problema.

¿Y por qué solo para la entrada desde la terminal o Emacs, a diferencia de la entrada desde una tubería o un archivo?

El código de nivel superior hace una distinción entre entrada interactiva y no interactiva; iirc. afecta la forma en que se imprimen las ubicaciones de error, por ejemplo.

¿Por qué la ignorancia (aparente) de Proof General de este límite causa errores colgantes y misteriosos ^G?

No tengo ni idea. los coqtop problema que está observando puede incluso ser un una experiencia diferente bicho (que el ocaml one) causado por una lógica de almacenamiento en búfer similar.

¿Cómo puedo solucionar esta limitación?

¿Qué tal no enviar entradas demasiado largas a la vez en Proof General? Tal vez pueda factorizar su código para usar definiciones intermedias o algo así, para mantenerse por debajo del límite.

Con respecto a la situación de "corrección ascendente": creo que tanto OCaml como Coq están en proceso de obtener una nueva versión pronto. Si las personas están lo suficientemente interesadas en el error como para obtener una solución muy pronto (en particular, si usted mismo encuentra la solución), podría integrarse en sentido ascendente razonablemente rápido. De lo contrario, tendrá que esperar al próximo ciclo de lanzamiento y posiblemente mantener una bifurcación local mientras tanto para evitar el problema. Pragmáticamente, la opción de "solución alternativa cambiando mi desarrollo de Coq" es probablemente la solución de menor esfuerzo, ¡pero no beneficiará a la humanidad en su conjunto!

Edit: (para responder comentarios)

La lógica de cambio de tamaño en la que estaba pensando está en Lexing.lex_refill, encontrado en stdlib/lexing.ml, llamado por el cierre creado por Lexing.from_function, llamado desde toplevel/toploop.ml.

Tengo otra idea de "solución alternativa": escriba su frase larga en un archivo externo foo.v, y use Load foo. para obtener el nivel superior para leer el archivo en sí. Sospecho que esto solucionará la limitación de tamaño, pero no lo he probado.

Respondido 05 Jul 12, 12:07

Excelente respuesta, gracias! Unas pocas cosas. Primero, puedo enviar el error; gracias por la url ¿En qué archivo encontraste la lógica de cambio de tamaño? En segundo lugar, descubrí que rlwrap déjame escribir más caracteres, pero me atraganté al enviarlos. Y tercero: la refactorización es una opción, pero solo hasta cierto punto. si tengo mucho tiempo Inductive definición, no puedo dividirlo de manera efectiva en varios tipos de datos más pequeños :-/ Así que espero poder encontrar una solución real. - Antal Spector-Zabusky

Solo para la posteridad, he informado el problema como problema 5678 en el rastreador. Desafortunadamente, la lógica de cambio de tamaño no parece ser lo que está causando el problema. - Antal Spector-Zabusky

Resulta que el error no tuvo que ver con OCaml. Agregué la información que obtuve del informe de error como respuesta. ¡Gracias por tu ayuda! - Antal Spector-Zabusky

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.