Al crear un cliente para una API web en C #, me encontré con un problema relacionado nullcon un valor en el que representaría dos cosas diferentes:
- nada , por ejemplo, un
foopuede o no tener unbar - desconocido : por defecto, la respuesta API solo incluye un subconjunto de propiedades, debe indicar qué propiedades adicionales desea. Tan desconocido significa que la propiedad no se solicitó a la API.
Después de algunas búsquedas, descubrí el tipo Quizás (u Opción), cómo se usa en lenguajes funcionales y cómo "resuelve" problemas de anulación de referencia al obligar al usuario a pensar en la posible ausencia de un valor. Sin embargo, todos los recursos que encontré hablaron de reemplazar nulo con Quizás . Encontré algunas menciones de lógica de tres valores , pero no lo entiendo completamente y la mayoría de las veces su mención fue en el contexto de "es algo malo".
Ahora me pregunto si tiene sentido tener tanto el concepto de nulo como el de Quizás , para representar lo desconocido y nada, respectivamente. ¿Es esta la lógica de tres valores sobre la que leí, o tiene otro nombre? ¿O es la forma prevista de anidar un tal vez en un tal vez?

null. Es una idea completamente rota.M M xyM xdebería tener la misma semántica.Maybe aMaybe Maybe aUserInput aM (M x)yM xdebería tener la misma semántica". TomemosM = Listpor ejemplo: las listas de listas no son lo mismo que las listas. CuandoMes una mónada, hay una transformación (es decir, la multiplicación de la mónada) a partirM (M x)de laM xcual se explica la relación entre ellos, pero no tienen "la misma semántica".Respuestas:
El
nullvalor como presente predeterminado en todas partes es solo una idea realmente rota , así que olvídate de eso.Siempre debe tener exactamente el concepto que mejor describa sus datos reales. Si necesita un tipo que indique "desconocido", "nada" y "valor", debe tener precisamente eso. Pero si no se ajusta a sus necesidades reales, entonces no debe hacerlo. Es una buena idea ver qué usan otras personas y qué han propuesto, pero no tiene que seguirlas a ciegas.
Las personas que diseñan bibliotecas estándar intentan adivinar patrones de uso comunes, y generalmente lo hacen bien, pero si hay algo específico que necesita, debe definirlo usted mismo. Por ejemplo, en Haskell, podría definir:
Incluso puede darse el caso de que deba usar algo más descriptivo que sea más fácil de recordar:
Podría definir 10 de estos tipos para ser utilizados en diferentes escenarios. El inconveniente es que no tendrá funciones de biblioteca preexistentes disponibles (como las de
Maybe), pero esto generalmente resulta ser un detalle. No es tan difícil agregar su propia funcionalidad.fuente
Hasta donde sé, el valor
nullen C # es un valor posible para algunas variables, dependiendo de su tipo (¿estoy en lo cierto?). Por ejemplo, instancias de alguna clase. Para el resto de los tipos (comoint,booletc.) puede agregar este valor de excepción declarando variables conint?o en subool?lugar (esto es exactamente lo que hace elMaybeconstructor, como describiré a continuación).El
Maybeconstructor de tipos de la programación funcional agrega este nuevo valor de excepción para un tipo de datos dado. Entonces, siIntes el tipo de enteros oGamees el tipo de estado de un juego, entoncesMaybe Inttiene todos los enteros más un valor nulo (a veces llamado nada ). Lo mismo paraMaybe Game. Aquí, no hay tipos que vienen con elnullvalor. Lo agrega cuando lo necesita.En mi opinión, este último enfoque es el mejor para cualquier lenguaje de programación.
fuente
Maybey soltar pornullcompleto?isinstancepruebas concretas . Scala también tiene una coincidencia de patrones "adecuada", y C♯ en realidad también obtuvo patrones simples recientemente.final(para una clase que no se puede heredar de), también tienesealed, para un clase que solo se puede extender dentro de la misma unidad de compilación . Esto significa que el compilador puede conocer estáticamente todas las subclases posibles (siempre que todas sean ellas mismassealedofinal) y, por lo tanto, realizar comprobaciones exhaustivas de coincidencias de patrones, lo que no es posible estáticamente para un idioma con carga de código de tiempo de ejecución y herencia sin restricciones.int??es ilegal en C #.Si puede definir uniones de tipo, como
X or Y, y si tiene un tipo llamadoNullque representa solo elnullvalor (y nada más), entonces, para cualquier tipoT, enT or Nullrealidad no es tan diferente deMaybe T. El único problema connulles cuando las golosinas de idioma un tipoTcomoT or Nullimplícita, por lo quenullun valor válido para todo tipo (excepto los tipos primitivos en lenguajes que los tienen). Esto es lo que sucede, por ejemplo, en Java, donde una función que toma aStringtambién aceptanull.Si trata los tipos como un conjunto de valores y
orcomo una unión de conjuntos,(T or Null) or Nullrepresenta el conjunto de valoresT ∪ {null} ∪ {null}, que es lo mismo queT or Null. Hay compiladores que realizan este tipo de análisis (SBCL). Como se dijo en los comentarios, no puede distinguir fácilmente entreMaybe TyMaybe Maybe Tcuando ve los tipos como dominios (por otro lado, esa vista es bastante útil para los programas de tipo dinámico). Pero también podría mantener los tipos como expresiones algebraicas, donde(T or Null) or Nullrepresenta múltiples niveles de Maybes.fuente
Maybe (Maybe X)no sea lo mismo queMaybe X.NothingNo es lo mismo queJust Nothing. La combinaciónMaybe (Maybe X)conMaybe Xhace imposible el tratamientoMaybe _polimórfico.Necesita averiguar lo que desea expresar y luego encontrar la forma de expresarlo.
Primero, tiene valores en su dominio problemático (como números, cadenas, registros de clientes, booleanos, etc.). En segundo lugar, tiene algunos valores genéricos adicionales además de los valores de su dominio problemático: por ejemplo, "nada" (la ausencia conocida de un valor), "desconocido" (sin conocimiento sobre la presencia o ausencia de un valor), no mencionado fue " algo "(definitivamente hay un valor, pero no sabemos cuál). Quizás puedas pensar en otras situaciones.
Si quisiera poder representar todos los valores más estos tres valores adicionales, crearía una enumeración con los casos "nada", "desconocido", "algo" y "valor" e iría desde allí.
En algunos idiomas, algunos casos son más simples. Por ejemplo, en Swift tiene para cada tipo T el tipo "T opcional" que tiene sus posibles valores nulo más todos los valores de T. Esto le permite manejar fácilmente muchas situaciones, y es perfecto si tiene "nada" y " valor". Puede usarlo si tiene "desconocido" y "valor". Usted podría no usarlo si usted necesita para manejar "nada", "desconocido" y "valor". Otros idiomas pueden usar "nulo" o "tal vez", pero esa es solo otra palabra.
En JSON, tiene diccionarios con pares clave / valor. Aquí, una clave puede faltar en un diccionario o puede tener un valor nulo. Entonces, al describir cuidadosamente cómo se almacenan las cosas, puede representar valores genéricos más dos valores adicionales.
fuente