ho definito una struttura ad albero espressione in F # come segue:partita incompleta con e modelli
type Num = int
type Name = string
type Expr =
| Con of Num
| Var of Name
| Add of Expr * Expr
| Sub of Expr * Expr
| Mult of Expr * Expr
| Div of Expr * Expr
| Pow of Expr * Expr
| Neg of Expr
volevo essere in grado di pretty-print l'albero di espressione così ho fatto la seguente:
let (|Unary|Binary|Terminal|) expr =
match expr with
| Add(x, y) -> Binary(x, y)
| Sub(x, y) -> Binary(x, y)
| Mult(x, y) -> Binary(x, y)
| Div(x, y) -> Binary(x, y)
| Pow(x, y) -> Binary(x, y)
| Neg(x) -> Unary(x)
| Con(x) -> Terminal(box x)
| Var(x) -> Terminal(box x)
let operator expr =
match expr with
| Add(_) -> "+"
| Sub(_) | Neg(_) -> "-"
| Mult(_) -> "*"
| Div(_) -> "/"
| Pow(_) -> "**"
| _ -> failwith "There is no operator for the given expression."
let rec format expr =
match expr with
| Unary(x) -> sprintf "%s(%s)" (operator expr) (format x)
| Binary(x, y) -> sprintf "(%s %s %s)" (format x) (operator expr) (format y)
| Terminal(x) -> string x
Tuttavia, non mi piace l'approccio failwith
per la funzione operator
poiché non è sicuro in fase di compilazione. Così ho riscritto come un modello attivo:
let (|Operator|_|) expr =
match expr with
| Add(_) -> Some "+"
| Sub(_) | Neg(_) -> Some "-"
| Mult(_) -> Some "*"
| Div(_) -> Some "/"
| Pow(_) -> Some "**"
| _ -> None
ora posso riscrivere la mia funzione format
splendidamente come segue:
let rec format expr =
match expr with
| Unary(x) & Operator(op) -> sprintf "%s(%s)" op (format x)
| Binary(x, y) & Operator(op) -> sprintf "(%s %s %s)" (format x) op (format y)
| Terminal(x) -> string x
ho assunto, in quanto F # è magia, che questo sarebbe solo lavorare. Sfortunatamente, il compilatore mi avvisa delle corrispondenze di pattern incomplete, perché non può vedere che tutto ciò che corrisponde allo Unary(x)
corrisponderà anche allo Operator(op)
e qualsiasi cosa corrispondente allo Binary(x, y)
corrisponderà anche allo Operator(op)
. E considero gli avvertimenti come quello essere pessimi come errori del compilatore.
Quindi le mie domande sono: C'è una ragione specifica per cui questo non funziona (come ho lasciato qualche annotazione magica da qualche parte o c'è qualcosa che non vedo)? C'è una soluzione semplice che potrei usare per ottenere il tipo di sicurezza che voglio? E c'è un problema inerente con questo tipo di controllo in fase di compilazione, o è qualcosa che F # potrebbe aggiungere in qualche versione futura?
Penso che questo tipo di problema sia improbabile da risolvere. Nel caso generale, sarà necessario risolvere il problema dell'arresto. Penso che la soluzione più elegante sarebbe quella di aggiungere un ulteriore livello di pattern in modo da restituire 'Unary (x, op)'. –
In realtà ho pensato di farlo, ma volevo mantenere il mio modello specifico per un caso d'uso (classificando l'arità dell'espressione ed estraendone gli argomenti). – luksan