poo - ¿Cómo me muevo? ¿No tengo polimorfismo paramétrico?
polimorfismo php (4)
Soy un recién llegado de Go, pero he leído que los asiduos de Go no se pierden el polimorfismo paramétrico. Cada vez que trato de aprender un nuevo idioma, utilizo la lista de problemas de L99 para practicar.
Incluso si intento escribir algo tan trivial como el primer problema (que en Go sería una sola declaración, tomando el último elemento de un segmento), ¿cómo escribiría esto como una función que toma un segmento de cualquier tipo y (usando esa única declaración a la que hice referencia más arriba) devuelve el último elemento de esa división?
Pensé que, aunque el lenguaje no tiene polimorfismo paramétrico, debe haber alguna forma idiomática de "Ir" para hacer esto para que los asiduos de Go afirmen que no se pierden el polimorfismo paramétrico. De lo contrario, si el ejemplo fuera más complejo que solo el último elemento de una lista, por ejemplo, necesitaría una función para realizar su tarea para cada tipo.
¿Qué me estoy perdiendo?
Cita los "99 problemas de luz", pero Lisp no tiene polimorfismo paramétrico o tipos estáticos en absoluto.
Muchos lenguajes de tipo estático, como Objective-C, y Java antes de los genéricos, no tienen polimorfismo paramétrico. La solución es usar un tipo que pueda aceptar todos los valores, que en Go es interface{}
, y emitir cuando necesite obtener algún tipo específico de él.
Para su pregunta específica, cómo tomar "cualquier tipo de rebanada"; desafortunadamente, no hay una interfaz que incluya específicamente segmentos, ya que los segmentos no tienen ningún método; así que estarás estancado con el uso de la interface{}
. Dado que tiene un tipo de sector desconocido, debe usar la reflexión (el paquete reflect
) para realizar todas las operaciones de sector, incluida la longitud y la capacidad, agregar y acceder al elemento en un índice particular.
Otra alternativa es que en lugar de usar "segmento de cualquier tipo", solo use "segmento de interfaz {}", es decir, []interface{}
, en todo su código, luego puede usar los operadores de sector normales en él, y puede poner Todos los elementos entran, pero se lanzan cuando los sacas.
Esto se parece mucho a cuando descubrí que estaba escribiendo el mismo código varias veces para diferentes arreglos de diferentes tipos en otros lenguajes de programación como C, fpc o delphi. Inventé el polimorfismo paramétrico para un lenguaje que probablemente nunca lo implementará, usando trucos de preprocesador y lo llamé "incluir polimorfismo paramétrico de archivo" como una prueba de concepto de que de hecho podría implementar el polimorfismo paramétrico en un lenguaje de procedimiento sin necesidad de OOP ni ningún otro complejo. sistema de genéricos. Sin embargo, usar el preprocesador es una forma de abuso, fue solo para probar el concepto con FPC.
Como Golang no usa un preprocesador, deberá usar interfaces o punteros y enviar el tipo como parámetro. Pero incluso usar punteros significa que tienes que escribir muchos códigos para convertirlos y hacer que todo funcione. Las interfaces son mejores que los punteros porque los punteros son menos seguros.
Soluciones como esta:
last := a[len(a)-1]
Son propensos a los errores porque alguien puede olvidar el signo menos 1. Algunos idiomas tienen algo ligeramente mejor:
// return last element, the "high" of a
last := a[high(a)]
// return first element, the "low" of a
first := a[low(a)]
El código anterior no funciona en Go AFAIK (no he investigado si ir tiene algo similar a esto), es solo lo que algunos otros idiomas tienen (fpc) que puede ser algo que Go considera.
Esta forma baja y alta de lidiar con las cosas garantiza absolutamente que se elija el último y el primer elemento, mientras que usar "menos uno" es propenso a cometer errores matemáticos básicos. Alguien puede olvidar el menos uno ... porque se confundieron con una matriz basada en una matriz basada en cero. Incluso si el lenguaje no tiene una matriz basada en 1, se podría cometer un error debido a que los humanos a veces piensan de una manera basada en 1 (nuestros dedos comienzan con 1, no con 0). Algunos programadores inteligentes dirían que, no, nuestros dedos comienzan en cero, no uno. Tu pulgar es cero. Bien, bien ... pero ... para la mayor parte del mundo ... ;-) terminamos cambiando de un lado a otro en el mundo real frente al mundo informático, y esto causa muchas Errores en el software.
Pero algunos dirían que "Bajo" y "Alto" son solo azúcar sintáctica que no es necesaria en un lenguaje mínimo. Se debe decidir si la seguridad adicional vale la pena, lo que en muchos casos puede ser. Cuánta complejidad LOW () y HIGH () agrega a un compilador, no estoy seguro, y cómo afecta al rendimiento ... No estoy 100% seguro ... Creo que el compilador puede ser inteligente en cuanto a la optimización de alta y baja, pero no estoy seguro
La forma de ir de cómo devolver el último elemento de un sector es simplemente escribirlo en línea como una expresión. Por ejemplo:
var a []int
...
last := a[len(a)-1]
Encapsular la expresión simple a[len(a)-1]
en una función genérica es una complicación innecesaria.
A diferencia de Lisp, Go no es un lenguaje puramente funcional. La evaluación de Go basada en una lista de 99 problemas de Lisp puede ser engañosa. Go es un "lenguaje de programación de sistemas": la manipulación de listas, la metaprogramación, la IA simbólica u otras tareas adecuadas para Lisp no son el lado fuerte de Go.
Veo Go como una C mejorada con recolección de basura y concurrencia . Go no está aquí para competir con Lisp.
Solo respondiendo a la pregunta de cómo obtener el último (y primer) elemento de una matriz, esta es la forma correcta en Go:
last := a[:1] first := a[1:]
Pero esto no tiene nada que ver con el polimorfismo paramétrico, es decir, la inferencia de tipo y se calcula en tiempo de compilación.
Estoy en el proceso de intentar escribir una biblioteca de árbol binario y todavía estoy luchando con la forma más eficiente, legible y eficiente de abstraer un tipo de datos, específicamente, tengo la tienda, el cursor y el sistema de mapas de índice escritos, y Funciones de paseo, pero quiero poder cambiar el tipo de datos que realmente se almacena en los nodos. Aprendí mucho sobre composición e integración en el proceso, pero no me está haciendo completamente feliz.
Conozco un poco de los principios de la programación funcional y Go trata a las funciones como de primera clase, por lo que, en teoría, es probable que exista una solución funcional al problema del polimorfismo paramétrico. Estoy en el proceso de averiguarlo porque básicamente me encanta el paradigma funcional, pero de todas formas odio la recursión (prefiero la iteración, 100 veces más fácil de visualizar).