recursividad - F#cómo especificar restricción de tipo en uniones recursivas discriminadas
recursividad estructura de datos (2)
Estoy tratando de definir mi gramática como una unión discriminada. Tiene dos tipos posibles: int
y datetime
y operadores matemáticos de Add
y Mul
. Add
trabajos en int
y datetime
(como add days in int) Mul
funciona solo en int
y no en datetime
gramática puede ser recursiva
Mi gramática parece
type MyExpression =
|Integer of int
|Date of datetime
|Add of MyExpression * MyExpression
|Mul of MyExpression * MyExpression
He escrito un analizador (fparsec) que puede analizar texto en mi gramática, pero no estoy seguro de cómo manejar la condición de que Mul
puede ser recursivo, pero solo en Integer
.
¿Existe una opción para definir esta restricción en mi tipo MyExpression
o tengo que manejar esto en mi entrada analizada?
El diseño sugerido por Asti también sería mi primera opción. Dependiendo de sus requisitos, eso puede ser todo lo que necesita.
Sin embargo, también te permite compilar una expresión como
Add(Val(System.Console.Out), Val(System.Console.Error))
que probablemente no es lo que quieres.
Alternativamente, podría modelar expresiones como esta:
open System
type IntExpression =
| Integer of int
| Mul of IntExpression * IntExpression
| Add of IntExpression * IntExpression
type DateTimeExpression =
| Date of DateTime
| Add of DateTimeExpression * DateTimeExpression
type MyExpression =
| IntExpression of IntExpression
| DateTimeExpression of DateTimeExpression
Esta es claramente una definición de tipo más detallado, pero incorpora la regla de que una expresión puede contener nodos hoja de valores enteros o DateTime
, y ningún otro valor, si esa es la regla que desea aplicar.
No estoy afirmando que esto sea mejor; Solo estoy suministrando una alternativa.
Uso:
> IntExpression(Mul(IntExpression.Add(Integer(1), Integer(2)),Integer 3));;
val it : MyExpression =
IntExpression (Mul (Add (Integer 1,Integer 2),Integer 3))
> DateTimeExpression(Add(Date(DateTime.MinValue),Date(DateTime.MinValue)));;
val it : MyExpression =
DateTimeExpression
(Add
(Date 01.01.0001 00:00:00 {Date = 01.01.0001 00:00:00;
Day = 1;
DayOfWeek = Monday;
DayOfYear = 1;
Hour = 0;
Kind = Unspecified;
Millisecond = 0;
Minute = 0;
Month = 1;
Second = 0;
Ticks = 0L;
TimeOfDay = 00:00:00;
Year = 1;},
Date 01.01.0001 00:00:00 {Date = 01.01.0001 00:00:00;
Day = 1;
DayOfWeek = Monday;
DayOfYear = 1;
Hour = 0;
Kind = Unspecified;
Millisecond = 0;
Minute = 0;
Month = 1;
Second = 0;
Ticks = 0L;
TimeOfDay = 00:00:00;
Year = 1;}))
Si tiene restricciones basadas en tipo, puede ser más fácil ir por un enfoque genérico:
type MyExpression<''t> =
|Val of ''t
|Mul of MyExpression<int> * MyExpression<int>
|Add of MyExpression<''t> * MyExpression<''t>
let Integer (x:int) = Val(x)
let Date (x:DateTime) = Val(x)
Uso:
Mul(Integer(1), Integer(2)) //compiles
Mul(Date(DateTime.Now), Date(DateTime.Now)) //error