2016-12-28 9 views
10

Próbuję zdefiniować moją gramatykę jako dyskryminowaną unię. Ma dwa możliwe typy: int i datetime oraz operatory matematyczne Add i Mul. Add prace nad int i datetime (jak dodać dni w int) Mul działa tylko na int a nie na datetime Gramatyka mogą być rekurencyjneF # jak określić ograniczenie typu w rekurencyjnych dyskryminowanych związkach

Moje gramatyki wygląda

type MyExpression = 
|Integer of int 
|Date of datetime 
|Add of MyExpression * MyExpression 
|Mul of MyExpression * MyExpression 

Pisałem parser (fparsec), który może analizować tekst w mojej gramatyce, ale nie jestem pewien, jak radzić sobie z warunkiem, że Mul może być rekursywny, ale tylko na Integer.

Czy istnieje opcja zdefiniowania tego ograniczenia dla mojego typu MyExpression lub czy muszę obsłużyć to w moich analizowanych danych wejściowych?

Odpowiedz

9

Konstrukcja zaproponowana przez Asti byłoby również mój pierwszy wybór. W zależności od Twoich potrzeb może to być wszystko, czego potrzebujesz.

To jednak, pozwalają także na kompilacji wyrażenia jak

Add(Val(System.Console.Out), Val(System.Console.Error)) 

który prawdopodobnie nie jest to, co chcesz.

Alternatywnie, można modelować wyrażenia tak:

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 

Jest wyraźnie bardziej gadatliwy definicja typu, ale ma ucieleśniać regułę, że wyrażenie może zawierać węzły liść albo całości lub DateTime wartości i żadnych innych wartości - jeśli jest to reguła, którą chcesz wymusić.

Nie twierdzę, że to jest lepsze; Dostarczam tylko alternatywę.

Zastosowanie:

> 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;})) 
7

Jeśli masz ograniczeń opartych typu, może być łatwiej będzie dla ogólnego podejścia:

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) 

Zastosowanie:

Mul(Integer(1), Integer(2)) //compiles 
Mul(Date(DateTime.Now), Date(DateTime.Now)) //error 
+1

uchwyty to niektóre z ograniczeń, ale nie wszystkie z nich - dodaje nie jest sensowne wypowiedzi, ale to typ kontrole: 'Dodaj (data (DateTime.Now), Mul (Integer 1, Integer 2)) ' –

Powiązane problemy