2011-03-18 28 views
7

¿Alguien podría explicarme cuáles son las diferencias entre los constructores de datos/tipos y las funciones? Haskell los mezcla y nos da una interfaz universal (todas parecen funciones, en particular, podemos aplicarlas parcialmente), mientras que los lenguajes de la familia ML las distinguen.Diferencias entre constructores y funciones de datos/tipos?

+1

¡Haskell * no * tiene un lema de "todo es una función"! http://conal.net/blog/posts/everything-is-a-function-in-haskell/ – sclv

Respuesta

16

Su dicotomía "Haskell vs. the ML world" es incorrecta¹. SML también promueve constructores de funciones, y Caml Light solía hacerlo. No estoy seguro de por qué fue eliminado en OCaml, creo que el diseñador pensó que no era una necesidad real.

Existen razones profundas por las que los constructores son un poco particulares. Se pueden usar en patrones, mientras que las funciones generales no; supongo que esto se puede explicar en términos de lógica polarizada y enfoque². Además, un constructor aplicado a valores puede considerarse un valor, mientras que esto no es cierto para funciones generales. Es común en los lenguajes de call-by-value restringir la definición de valores recursivos a una subclase que permite la aplicación del constructor, pero no la aplicación de función general.

Estoy de acuerdo en que el "azúcar semántico" de promover todos los constructores para las funciones es agradable. Sin embargo, creo que esto no sería tan útil si tuviéramos un buen azúcar sintáctico para abstracción breve, como el Some(_) de Scala. Si los constructores deben curryfied (su observación de "aplicación parcial") o no es una pregunta diferente y ortogonal, en mi opinión.

¹: además de ser una dicotomía equivocada, el tono de su pregunta tiene cierto sabor a "Haskellers y MLers, aquí está el anillo, por favor, pelea". Puede que no sea intencional, pero de todos modos probablemente deberías evitar tales formulaciones. El diseño del lenguaje está hecho de compromisos, y asumiendo que dos idiomas diferentes tomaron decisiones diferentes, uno de ellos es , el derecho y el otro no es un buen enfoque.

PD: la pregunta ha sido editada y ahora es mucho más neutral. Gracias por editar




²: según lo solicitado por petebu, aquí es un poco más (en realidad mucho más) información sobre "el enfoque y la polaridad". Me gustaría señalar que realmente no soy un experto en este tema (de ahí el "supongo").

Recomendaría primero el artículo Focusing on Pattern Matching (PDF) de Neelakantan Krishnaswami, 2009. Contiene una introducción para personas que no son competentes en lógica polarizada y enfoque (pero deben estar al menos familiarizados con el cálculo secuencial). Como es habitual en el cálculo secuencial, los tipos/proposiciones se introducen "a la derecha" y se eliminan/deconstruyen "a la izquierda". Pero aquí separamos los tipos por "polaridad", el producto y las sumas son positivas y las funciones son negativas (mi intuición es que los productos/sumas son datos mientras que las funciones son cálculos, pero la separación está motivada por consideraciones muy naturales de su comportamiento en el cálculo posterior), y el documento muestra que la eliminación a la izquierda de los tipos de flechas corresponde a la aplicación de funciones, mientras que la eliminación a la izquierda de los tipos de suma/producto corresponde a la coincidencia de patrones. Hay una construcción case que se comporta de forma similar a la coincidencia de patrones (con algunas diferencias), que elimina los aspectos positivos, por lo que no se puede aplicar a las funciones.

La otra referencia importante sería Focusing on Binding and Computation, por Dan Licata, Noam Zeilberger y Robert Harper, 2008 (tenga en cuenta que si planea enviar un trabajo sobre estos temas, "Centrarse en ..." se está convirtiendo en un poco cliché).Enfatiza mucho menos el vínculo con la coincidencia de patrones ML-style, pero introduce la muy buena idea de que, si bien las flechas computacionales son "negativas a la izquierda" (se ve fácilmente como la equivalencia clásica A→B ≡ ¬A∨B), se puede introducir una flecha diferente, "positiva en la izquierda ", por lo tanto, positivamente polarizada, que puede combinarse con patrones. Resulta que esta flecha es una buena coincidencia para representar enlaces variables (si está familiarizado con la sintaxis abstracta de orden superior, la idea es que la polaridad izquierda excluya "términos exóticos" que intenten calcular en sus variables), de modo que los términos con enlaces de variables son estructuras de datos que pueden ajustarse a patrones como sumas o productos.
Encontré su documento un poco difícil de leer, así que comenzaría con Dan Licata's slides. Finalmente, Robert Harper ha realizado other slides que proporciona una intuición diferente en termes de juicios/derivaciones inductivas: las flechas positivas representan derivabilidad (¿podría construir una derivación de C bajo la hipótesis A y B?) Mientras que las flechas negativas representan admisibilidad (dado derivaciones de A y B, ¿cómo las reescribiría/exploraría/manipularía para construir una derivación de C?). Cosas muy interesantes

+0

+1 para la nota numerada – phooji

+0

+1. "Esto se puede explicar en términos de lógica polarizada y enfoque". ¿Puedes dar más detalles sobre esto? Un enlace a un papel haría. – petebu

+0

@petebu: he editado para proporcionar dos referencias. – gasche

0

Haskell reduce y simplifica parte de la sintaxis OCaml. Pero la sintaxis Haskell distingue inequívocamente constructores y funciones. Las funciones comienzan con una letra minúscula y los constructores comienzan con una letra mayúscula. Con operadores de infijo, los constructores de datos deben comenzar con dos puntos y los operadores normales pueden nunca comenzar con dos puntos.

La interfaz para constructores puede parecer una aplicación de función simple (quizás parcial), esto hace que los constructores de un argumento y la mayoría de los tipos nuevos sean muy fáciles de usar (solo "hola"). Pero Haskell sí le permite usar nombres de registro similares a OCaml y el estilo de {campo = valor, campo = valor}, aunque en Haskell no está obligado a tener nombres de campo ni a usar esta sintaxis. Así que OCaml tiene una sintaxis simple solo para campos individuales, pero Haskell le permite tener una sintaxis simple para más de un campo. Eventualmente, evitar los nombres de campo es malo para el tipo grande ya que la sintaxis similar a la función posicional es más difícil de refactorizar.

1

Primero se debe explicar la diferencia entre el valor y el tipo.

"Como Haskell es un lenguaje puramente funcional, todos los cálculos se realizan mediante la evaluación de expresiones (términos sintácticos) para obtener valores (entidades abstractas que consideramos como respuestas). Cada valor tiene un tipo asociado". - Una introducción suave a Haskell 98 (Este tutorial no es muy delicado)

Los valores de Haskell son de "primera clase", mientras que los tipos de Haskell no lo son. Los tipos se utilizan para describir valores y la asociación de un valor y su tipo se llama tipado.

La diferencia entre el constructor de datos/tipos es que: la aplicación de un constructor de datos produce un valor, pero la aplicación de un constructor de tipos produce un tipo.

Las funciones son simplemente expresiones que describen valores, que están asociadas a un tipo. Cuando evalúa una función, solo está evaluando las expresiones que describen los valores.

+0

-1. Creo que OP estaba preguntando acerca de la diferencia entre los constructores y las funciones de tipo de datos algebraicos, cuyos valores de rendimiento son ambos. – petebu

+1

@petebu Tenía la misma creencia, pero en realidad el OP es * muy * ambiguo, y su pregunta podría (como me di cuenta después de leer esta respuesta) ser leída como "¿por qué los ML no usan una sintaxis similar a la función en el nivel de tipo como Haskell? ". Supongo que la respuesta más natural es que los ML no admiten tipos de alto nivel fuera del lenguaje del módulo, por lo que las aplicaciones parciales no tendrían sentido. – gasche

Cuestiones relacionadas