Me siento muy cómodo con la programación imperativa. Nunca tengo problemas para expresar algorítmicamente lo que quiero que haga la computadora una vez que descubrí qué es lo que quiero que haga. Pero cuando se trata de lenguajes como SQL o a menudo me atoro porque mi cabeza está demasiado acostumbrada a la programación imperativa.
Por ejemplo, supongamos que tiene la banda de relaciones (bandName, bandCountry), sede (placeName ,placeCountry), juega (bandName ,placeName), y quiero escribir una consulta que diga: todos los nombres de sede de tal manera que para cada bandCountry haya una banda de ese país que juega en el lugar de ese nombre.
Ejemplo: quiero todos los nombres de los lugares en los que tocaron bandas de todos los países (bandCountry). Además, por "relación" me refiero a una tabla SQL.
En mi mente, inmediatamente voy "para cada Nombre del lugar iterar sobre todos los BandCountries y para cada bandCountry obtener la lista de las bandas que provienen de él. Si ninguno de ellos juega en el Lugar del Nombre, vaya al siguiente Lugar del Nombre. De lo contrario, al final de los BandCountries iteración agregarplaceName al conjunto de buenos lugaresNombre ".
... pero no se puede hablar así en SQL y realmente necesito pensar en cómo formular esto, con la solución Imperativa intuitiva constantemente molesta en la parte posterior de mi cabeza. ¿Alguien más tuvo este problema? ¿Cómo superaste esto? ¿Descubriste un cambio de paradigma? ¿Hizo un mapa de conceptos imperativos a conceptos SQL para traducir soluciones imperativas en declarativas? ¿Lee un buen libro?
PD: no estoy buscando una solución para la consulta anterior, la resolví.
fuente
Respuestas:
La idea detrás de hacer cosas declarativamente es que se supone que debes especificar qué , no cómo .
Para mí, parece que estás en el camino correcto. El problema no es que estés pensando en las cosas de manera incorrecta. Es que vas demasiado lejos. Veamos lo que estás tratando de hacer:
Hasta ahora, esto es genial. Pero luego haces esto:
En esencia, estás haciendo un trabajo innecesario. Sabes lo que quieres, que es todo lo que realmente necesitas. Pero luego continúas e intentas descubrir cómo conseguirlo.
Si fuera usted, trataría de adquirir el siguiente hábito:
Puede tomar algo de tiempo y esfuerzo de su parte, pero una vez que realmente comprende la programación declarativa, se vuelve muy útil. De hecho, es posible que te encuentres usando programación declarativa en el resto de tu código.
Si está buscando un libro, le recomendaría SQL y la teoría relacional . Realmente te ayuda a entender la teoría detrás de las bases de datos SQL. Solo recuerde tomar las recomendaciones de Date con un grano de sal. Da muy buena información, pero a veces puede ser un poco testarudo.
fuente
pensar en términos de conjuntos, no iteradores; las instrucciones sql definen las propiedades del conjunto de salida deseado (también conocido como tabla / relación)
El resultado de esto (¡si entendiera sus intenciones correctamente!) sería el conjunto de lugares que tienen al menos una banda que toca en ese lugar. La iteración sobre bandCountry es innecesaria, ya que la relación PLAYS ya tiene la información que busca, solo tiene que eliminar los duplicados
entonces en SQL esto sería:
EDITAR: ok, entonces el conjunto real deseado es un poco más complicado. La pregunta que se hace a la base de datos es: ¿qué lugares han acogido bandas de todos los países?
Por lo tanto, definimos los criterios de membresía para un elemento del conjunto deseado como el objetivo, luego trabajamos hacia atrás para completar el conjunto. Un lugar es un miembro del conjunto de salida si tiene una fila PLAYS para al menos una banda de cada país. ¿Cómo obtenemos esta información?
Una forma es contar los distintos países para cada lugar y compararlo con el recuento de todos los países. Pero no tenemos una relación PAÍS. Si pensamos en el modelo dado por un momento, vemos que el conjunto de todos los países no es el criterio correcto; Es el conjunto de todos los países que tienen al menos una banda. Por lo tanto, no necesitamos una tabla de países (aunque para un modelo normalizado deberíamos tener una), y no nos importa el país del lugar, solo podemos contar los países que tienen bandas, por ejemplo (en MS-SQL )
Podemos contar los países de la banda para cada lugar
y podemos juntar los dos usando una subconsulta
Ahora, esa no es la consulta más bonita posible (GROUP BY y HAVING podrían considerarse una solución más 'elegante' que las variables temporales y una subconsulta) pero es bastante obvio lo que buscamos, así que lo dejaremos así para el propósito del OP .
El objetivo del OP era aprender cómo cambiar la mentalidad de imperativo a declarativo. Con ese fin, observe lo que estaba haciendo la solución imperativa descrita:
¿Cuál es el criterio determinante en lo anterior? Creo que es:
Este es un criterio descalificador . El proceso de pensamiento imperativo está comenzando con un balde lleno y tirando cosas que no cumplen con los criterios. Estamos filtrando datos.
Eso está bien para cosas simples, pero ayuda a pensar en términos de construir el conjunto de resultados deseado; ¿Cuál es el criterio de calificación correspondiente que le permitiría llenar el balde?
El calificador final se puede simplificar usando conteos: un país de banda está 'satisfecho' si al menos una banda de allí toca en un lugar; el número de países de banda "satisfechos" para un lugar debe ser igual al número de países de banda para que el lugar sea calificado.
Ahora podemos razonar a través de las relaciones por navegación:
que conduce de nuevo a la solución anterior (o un facsímil razonable de la misma)
RESUMEN
fuente
Una forma de aprender a pensar y programar en un estilo declarativo es aprender un lenguaje de matriz de propósito general como APL o J. SQL probablemente no sea el mejor vehículo para aprender a programar declarativamente. En APL o J, aprende a operar en matrices enteras (vectores, matrices o matrices de rango superior), sin iteraciones ni bucles explícitos. Esto hace que la comprensión de SQL y álgebra relacional sea mucho más fácil. Como un ejemplo muy simple, para seleccionar elementos de un vector V cuyo valor es mayor que 100, en APL escribimos:
Aquí V> 100 se evalúa como una matriz booleana de la misma forma que V, con 1 marcando los valores que queremos mantener. Al APLer experimentado no se le ocurre una iteración, solo estamos aplicando una máscara al vector V, devolviendo un nuevo vector. Esto, por supuesto, es conceptualmente lo que está haciendo una operación de restricción de cláusula o álgebra relacional.
No creo que puedas controlar bien la programación declarativa sin hacer mucho, y SQL generalmente es demasiado específico. Debe escribir una gran cantidad de código de propósito general, aprender a prescindir de bucles y estructuras if / then / else y todo el aparato que atiende a la programación imperativa, de procedimiento y de estilo escalar.
Puede haber otros lenguajes funcionales que también ayudan con esta forma de pensar, pero los lenguajes de matriz están muy cerca de SQL.
fuente
a = a + 1
) de la noche a la mañana tampoco. Lleva tiempo aprender estilos declarativos como lógica, funcional, etc., al igual que tomó tiempo aprender la programación imperativa.Primero, tienes que aprender ambos. Es posible que tenga una preferencia, pero cuando trabaje en áreas donde el otro es mejor, no luche. Muchos programadores están tentados a usar cursores en bases de datos relacionales, ya que están acostumbrados a recorrer cada registro, pero la base de datos es mucho mejor en los conjuntos. No quieres entrar en la mentalidad de "Sé cómo hacerlo de esta manera y tengo el mayor control, bla, bla, bla".
fuente
Aprende a pensar declarativamente como aprendió a pensar de manera imperativa: practicando comenzando con problemas más simples y avanzando a medida que lo "entiende".
Sus primeras experiencias con la programación imperativa incluyeron un montón de declaraciones contra-intuitivas (y, de hecho, completamente ridículas) como "
a = a + 1
". Envolviste tu mente en eso hasta el punto de que ahora probablemente ni siquiera recuerdes el retroceso de la obvia falsedad de la declaración. Su problema con los estilos declarativos es que volvió a donde estaba cuando comenzó con los estilos imperativos: un "nuevo despistado". Peor aún, tiene años de práctica con un estilo que está totalmente en desacuerdo con este nuevo estilo y tiene años de hábitos para deshacer, como el hábito de "controlar a toda costa".Los estilos declarativos funcionan con un enfoque diferente al que le falta intuición por ahora (a menos que haya mantenido sus habilidades matemáticas muy afiladas a lo largo de los años, lo que la mayoría de las personas no). Tienes que volver a aprender cómo pensar y la única forma de volver a aprender es hacerlo, un simple paso a la vez.
Elegir SQL como su primera incursión en la programación declarativa puede ser un error si realmente quiere aprender los conceptos. Claro, el cálculo de la tupla en el que se basa es tan declarativo como se pone, realmente, pero desafortunadamente la pureza del cálculo de la tupla se ha visto gravemente comprometida por las realidades de implementación y el lenguaje, en efecto, se ha vuelto un poco confuso. Es posible que desee ver otros lenguajes declarativos más directamente útiles (en el sentido en que está acostumbrado) como Lisps (especialmente Esquema ), Haskell y los ML para la programación funcional (en su mayoría) o, como alternativa, Prolog y Mercury para (principalmente) programación lógica.
Aprender estos otros idiomas le dará una mejor idea, en mi opinión, sobre cómo funciona la programación declarativa por algunas razones:
Son útiles para la programación "desde la cuna a la tumba", ya que puedes escribir un programa completo en estos idiomas de principio a fin. Son útiles por sí solos, a diferencia de SQL, que es realmente bastante inútil para la mayoría de las personas como lenguaje independiente.
Cada uno de ellos le da una inclinación diferente en la programación declarativa que puede darle diferentes caminos para finalmente "conseguirlo".
Además, cada uno le da una perspectiva diferente al pensar en la programación en general. Mejorarán su capacidad de razonar sobre problemas y codificación, incluso si nunca los usa directamente.
Las lecciones que aprenda de ellos también lo ayudarán con su SQL, especialmente si repasa el cálculo de la tupla detrás de las bases de datos relacionales para la forma pura de pensar sobre los datos.
Recomiendo especialmente aprender uno de los lenguajes funcionales ( Clojure , como uno de los Lisps, es probablemente una buena opción aquí) y uno de los lenguajes lógicos (me gusta más Mercury, pero Prolog tiene mucho más material útil para aprender) para la máxima expansión del proceso de pensamiento.
fuente
No está mal pensar imperativamente en un entorno declarativo como SQL. Es solo que el pensamiento imperativo debería estar sucediendo a un nivel un poco más alto de lo que describiste. Siempre que necesito consultar una base de datos que usa SQL, siempre pienso en mí mismo:
Lo anterior es un algoritmo imperativo de alto nivel y funciona bastante bien para mí en la configuración de SQL. Creo que esto se considera un enfoque de arriba hacia abajo y Steven A. Lowe describe un enfoque bastante bueno de abajo hacia arriba .
fuente
La clave de su pregunta está en lo que dijo en el penúltimo párrafo: "No se puede hablar así en SQL". Puede ser más útil para usted en esta etapa acercarse a SQL como un idioma extranjero en lugar de un lenguaje de programación. Si lo piensa de esta manera, escribir una consulta SQL realmente está traduciendo una declaración en inglés de lo que quiere en "SQLish". La computadora entiende perfectamente SQLish y hará exactamente lo que usted dice, por lo que no debe preocuparse por la implementación siempre que traduzca correctamente.
Dicho esto, ¿cuál es la mejor manera de aprender un idioma extranjero? Obviamente, debe aprender la gramática y el vocabulario, que puede obtener de su documentación SQL. Lo más importante es la práctica. Debería leer y escribir tanto SQL como sea posible, y no sienta que primero debe conocer la sintaxis a fondo; puedes y debes buscar cosas a medida que avanzas. Sabrá que lo tiene cuando le resulte más fácil describir qué datos desea en SQL que en inglés.
fuente
También me llevó mucho tiempo comprender SQL. Hicimos alguna teoría relacional en la universidad y en ese momento, que solo sirvió para complicar las cosas. Al final, mi proceso de aprendizaje fue muy basado en pruebas y errores gracias a varios materiales de aprendizaje y ejemplos que encontré útiles en el camino. Esencialmente, eventualmente te acostumbrarás, y agregar una nueva forma de pensar sobre datos y consultas será de algún valor para tu desarrollo mental.
Descubrí que podía acelerar mi aprendizaje al construir gradualmente una colección de scripts simples que demostraban cómo usar cada función del lenguaje y cómo lograr ciertos resultados en una tabla conocida (las definiciones de tabla se incluyen como referencia).
A principios de este año realicé una capacitación formal que involucraba un proyecto de migración de datos en una desordenada base de datos Oracle, donde tuve que juntar gradualmente fragmentos de mi biblioteca para filtrar los resultados de la consulta de varias maneras hasta que obtuve exactamente lo que quería, luego transformarlos como necesario, y así sucesivamente. Algunas de las consultas se volvieron muy complejas y difíciles de depurar. Dudo que pueda leerlos ahora, pero espero poder llegar a una solución similar nuevamente usando mis bloques de construcción de referencia.
Otras formas de aumentar su conocimiento intuitivo de los espacios declarativos y funcionales son el aprendizaje de la teoría de conjuntos y los lenguajes de programación más adecuados para un paradigma particular. Actualmente estoy en el proceso de aprender algo de Haskell, por ejemplo, para mantener y mejorar mis habilidades matemáticas.
fuente
Cuando enfrenta un problema, generalmente piensa cómo resolverlo. ¡Pero si sabes cómo la computadora lo resuelve por ti! Entonces te preocupa cómo serán eliminados.
Trato de decir cómo sucede.
Es posible que ya esté familiarizado con los programas recursivos, en los programas recursivos, usted define el problema en lugar de decir cómo se resuelve. Usted define la base y define n basado en n-1 . (por ejemplo
factorial(n) = n * factorial(n-1)
) Pero ya puede saber cómo lo resuelve la computadora. comienza desde la función y llama a la función de forma recursiva hasta que alcanza una definición base, luego evalúa todas las demás funciones en función del valor base.Es lo que sucede en la programación declarativa. define todo en función de las definiciones existentes. Y la computadora sabe cómo derivar la respuesta en función de las funciones básicas.
En SQL, es posible que no relacione las definiciones entre sí, pero relaciona objetos o información entre sí, especifica lo que desea y la computadora busca algo (objeto, información) en función de las relaciones que ha proporcionado.
fuente