Pregunta

He estado tratando de explicar la diferencia entre las declaraciones de cambio y la coincidencia de patrones (F #) a un par de personas, pero realmente no he podido explicarlo bien ... la mayoría de las veces solo me miran y dicen " entonces, ¿por qué no usas if..then..else " ;.

¿Cómo se lo explicarías?

EDITAR! Gracias a todos por las excelentes respuestas, realmente desearía poder marcar múltiples respuestas correctas.

¿Fue útil?

Solución

Después de haber sido una de esas "personas", no sé si hay una forma sucinta de resumir por qué la coincidencia de patrones es tan sabrosa. Es experimental.

Cuando recién había mirado la coincidencia de patrones y pensaba que era una declaración de cambio glorificada, creo que no tenía experiencia en la programación con tipos de datos algebraicos (tuplas y uniones discriminadas) y no vi ese patrón la coincidencia fue tanto una construcción de control como una construcción de unión. Ahora que he estado programando con F #, finalmente lo entiendo. La frialdad de la coincidencia de patrones se debe a la confluencia de características que se encuentran en los lenguajes de programación funcionales, por lo que no es trivial que las personas ajenas lo aprecien.

Traté de resumir un aspecto de por qué la coincidencia de patrones es útil en la segunda de una breve serie de blogs de dos partes sobre lenguaje y diseño de API; echa un vistazo a primera parte y segunda parte .

Otros consejos

Los patrones le proporcionan un lenguaje pequeño para describir la estructura de los valores que desea hacer coincidir. La estructura puede ser arbitrariamente profunda y puede vincular variables a partes del valor estructurado.

Esto le permite escribir cosas de manera extremadamente sucinta. Puede ilustrar esto con un pequeño ejemplo, como una función derivada para un tipo simple de expresiones matemáticas:

type expr =
    | Int of int
    | Var of string
    | Add of expr * expr
    | Mul of expr * expr;;

let rec d(f, x) =
    match f with
    | Var y when x=y -> Int 1
    | Int _ | Var _ -> Int 0
    | Add(f, g) -> Add(d(f, x), d(g, x))
    | Mul(f, g) -> Add(Mul(f, d(g, x)), Mul(g, d(f, x)));;

Además, debido a que la coincidencia de patrones es una construcción estática para tipos estáticos, el compilador puede (i) verificar que cubrió todos los casos (ii) detectar ramas redundantes que nunca pueden coincidir con ningún valor (iii) proporcionar una implementación muy eficiente (con saltos, etc.).

Extracto de este artículo del blog :

La coincidencia de patrones tiene varias ventajas sobre las declaraciones de cambio y el envío de métodos:

  • Las coincidencias de patrones pueden actuar sobre ints, flotadores, cuerdas y otros tipos como bien como objetos.
  • Las coincidencias de patrones pueden actuar sobre varios diferentes valores simultáneamente: coincidencia de patrones paralelos. Método el despacho y el cambio están limitados a un solo valor, p. " esto " ;.
  • Los patrones se pueden anidar, lo que permite despacho sobre árboles de arbitrario profundidad. El envío y el cambio del método son limitados al caso no anidado.
  • Los patrones-O permiten que los subpatrones sean compartido. El envío del método solo permite compartir cuando los métodos son de clases que comparten una base clase. De lo contrario, debe hacerlo manualmente factorizar la comunidad en una función separada (dándole un nombre) y luego inserte llamadas manualmente de todos los lugares apropiados para su función innecesaria.
  • La coincidencia de patrones proporciona redundancia comprobando qué capturas de errores.
  • Patrón anidado y / o paralelo los partidos están optimizados para usted por el F # compilador. El equivalente de OO debe ser escrito a mano y constantemente reoptimizado a mano durante desarrollo, que es prohibitivo tedioso y propenso a errores el código OO de calidad de producción tiende a ser extremadamente lento en comparación.
  • Los patrones activos le permiten inyectar semántica de despacho personalizado.

Fuera de mi cabeza:

  1. El compilador puede decir si no has cubierto todas las posibilidades en tus partidos
  2. Puedes usar una coincidencia como una tarea
  3. Si tiene una unión discriminada, cada coincidencia puede tener un 'tipo' diferente

El interruptor es las dos ruedas delanteras.

La coincidencia de patrones es todo el automóvil.

Las tuplas tienen ", " y las variantes tienen argumentos Ctor ... estos son constructores, crean cosas.

Los patrones son destructores, los desgarran.

Son conceptos duales.

Para decirlo con más fuerza: la noción de una tupla o variante no puede ser descrita simplemente por su constructor: el destructor es obligatorio o el valor que ha hecho es inútil. Estas descripciones duales son las que definen un valor.

Generalmente pensamos en los constructores como datos, y los destructores como flujo de control. Los destructores de variantes son ramas alternativas (una de muchas), los destructores de tuplas son hilos paralelos (todos).

El paralelismo es evidente en operaciones como

(f * g) . (h * k) = (f . h * g . k) 

si piensa en el control que fluye a través de una función, las tuplas proporcionan una forma de dividir un cálculo en hilos de control paralelos.

Visto de esta manera, las expresiones son formas de componer tuplas y variantes para crear estructuras de datos complicadas (piense en un AST).

Y las coincidencias de patrones son formas de componer los destructores (de nuevo, piense en un AST).

Las coincidencias de patrones en OCaml, además de ser más expresivas como se mencionó en varias formas que se han descrito anteriormente, también ofrecen algunas garantías estáticas muy importantes. El compilador demostrará para usted que el análisis de caso realizado por su declaración de coincidencia de patrón es:

  • exhaustivo (no se pierden casos)
  • no redundante (no hay casos que nunca puedan ser afectados porque están previstos por un caso anterior)
  • sonido (sin patrones que sean imposibles dado el tipo de datos en cuestión)

Este es un gran problema. Es útil cuando está escribiendo el programa por primera vez, y enormemente útil cuando su programa está evolucionando. Si se usan correctamente, las declaraciones de coincidencia facilitan el cambio de los tipos en su código de manera confiable, porque el sistema de tipos lo señala a las declaraciones de coincidencia rotas, que son un indicador decente de dónde se debe corregir el código.

Las declaraciones

If-Else (o switch) tratan de elegir diferentes formas de procesar un valor (entrada) dependiendo de las propiedades del valor en cuestión.

La coincidencia de patrones se trata de definir cómo procesar un valor dada su estructura , (también tenga en cuenta que las coincidencias de patrones de caso único tienen sentido).

Por lo tanto, la coincidencia de patrones tiene más que ver con la deconstrucción de valores que con la elección, esto los convierte en un mecanismo muy conveniente para definir funciones (recursivas) en estructuras inductivas (tipos de unión recursiva), lo que explica por qué se usan tan abundantemente en lenguajes como Ocaml, etc. .

PD: es posible que conozca la coincidencia de patrones y los patrones de If-Else " de su uso ad-hoc en matemáticas;

" si x tiene la propiedad A, entonces y else z " (Si más)

" algún término en p1..pn donde .... es la descomposición principal de x .. " (coincidencia de patrón (caso único))

¿Quizás podrías dibujar una analogía con cadenas y expresiones regulares? Describes qué estás buscando y dejas que el compilador descubra cómo por sí mismo. Hace que su código sea mucho más simple y claro.

Como comentario aparte: creo que lo más útil de la coincidencia de patrones es que fomenta los buenos hábitos. Me ocupo de los casos de esquina primero , y es fácil comprobar que he cubierto todos los casos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top