我想對變數(僅限整數)進行靜態符號分析。
例子:我有兩個變數的可能符號和操作
A 正 A 正 = A 正
[Pos] [Pos] -> [Pos]
正數或零 正數 = 正數
[Pos; Zero] [Pos] -> [Pos]
正數或零或負數 * 零 = 零
[Pos; Zero; Neg] * [Zero] -> [Zero]
等等...
我的變數符號被編碼為串列/陣列。
正數或零變數將被編碼為 [Pos; Zero] A 負變數將被編碼為 [Neg] 正、負或零變數將被編碼為 [Pos; 否定; 零]順序無關緊要[Pos; 零]與[零;位置]
我需要在 OCAML 中執行此操作,但您可以使用任何語言/偽代碼提供幫助。
這是我的想法:
let sign_operation (op:op) (l_expr: sign list) (r_expr: sign list): sign list =
match op with
| Add -> (match l_expr, r_expr with
| [Pos], [Pos] -> [Pos]
| [Pos], [Zero] -> [Pos]
| [Zero], [Pos] -> [Pos]
| [Pos], [Neg] -> [Neg;Zero;Pos]
| [Neg], [Pos] -> [Neg;Zero;Pos]
| [Neg], [Zero] -> [Neg]
| [Zero], [Neg] -> [Neg]
| [Neg], [Neg] -> [Neg]
| [Zero], [Zero] -> [Zero]
| _ -> failwith "no")
| Sub -> (match l_expr, r_expr with
| [Pos], [Pos] -> [Neg;Zero;Pos]
| [Pos], [Zero] -> [Pos]
| [Zero], [Pos] -> [Neg]
| [Pos], [Neg] -> [Pos]
| [Neg], [Pos] -> [Neg]
| [Neg], [Zero] -> [Neg]
| [Zero], [Neg] -> [Pos]
| [Neg], [Neg] -> [Neg;Zero;Pos]
| [Zero], [Zero] -> [Zero]
| _ -> failwith "no")
| Mul -> (match l_expr, r_expr with
| [Pos], [Pos] -> [Pos]
| [Pos], [Zero] -> [Zero]
| [Zero], [Pos] -> [Zero]
| [Pos], [Neg] -> [Neg]
| [Neg], [Pos] -> [Neg]
| [Neg], [Zero] -> [Zero]
| [Zero], [Neg] -> [Zero]
| [Neg], [Neg] -> [Pos]
| [Zero], [Zero] -> [Zero]
| [Neg;Zero;Pos], [Zero] -> [Zero]
| [Zero], [Neg;Zero;Pos] -> [Zero]
| _ , [Zero] -> [Zero]
| [Zero] , _ -> [Zero]
| _ -> failwith "no")
| Div -> (match l_expr, r_expr with
| [Pos], [Pos] -> [Pos]
| [Pos], [Zero] -> [Error]
| [Zero], [Pos] -> [Zero]
| [Pos], [Neg] -> [Neg]
| [Neg], [Pos] -> [Neg]
| [Neg], [Zero] -> [Error]
| [Zero], [Neg] -> [Zero]
| [Neg], [Neg] -> [Pos]
| [Zero], [Zero] -> [Error]
| [Neg;Zero;Pos], [Zero] -> [Error]
| [Zero], [Neg;Zero;Pos] -> [Zero]
| _ -> [Error])
| Mod -> (match l_expr, r_expr with
| [Pos], [Pos] -> [Pos]
| [Pos], [Zero] -> [Error]
| [Zero], [Pos] -> [Zero]
| [Pos], [Neg] -> [Error]
| [Neg], [Pos] -> [Error]
| [Neg], [Zero] -> [Error]
| [Zero], [Neg] -> [Error]
| [Neg], [Neg] -> [Error]
| [Zero], [Zero] -> [Error]
| _ -> [Error])
這不適用于具有兩個或更多可能符號的任何變數。
如果我有一個變數 [Pos; 零; Neg] 減 [Pos; 零],這不會在我的模式中匹配。以每一種可能的順序嘗試每一種可能的排列會太長。
你能建議一個更好的方法來做到這一點嗎?
抱歉,如果我不能很好地理解自己,請隨時提出任何問題,謝謝!
uj5u.com熱心網友回復:
在你的問題中,你寫
正數或零 正數 = 正數
[Pos; Zero] [Pos] -> [Pos]
你怎么會知道這事?您是否曾就讀過一所專門教您向某事物添加正數或零數會得到什么的學校?當然不是。您將其分解為更簡單的情況,推理如下:
- 第一個數字可能是正數。在那種情況下,我知道 Pos Pos = Pos
- 第一個數字可能為零。在那種情況下,我知道 Zero Pos = Pos。
- 因此,在第一個數字可能包含的所有值中,結果是 Pos 或 Pos。
- 當然,我們可以將其簡化為始終為 Pos。
撰寫一個以相同方式推理的程式。不要一次查看一對符號串列,而是為每個操作撰寫一個函式,該函式只處理每個運算元的一個符號,生成可能結果的串列。在輸入串列表示的每對可能的符號上呼叫該函式,然后組合結果。
例如。
signOp Add x y = case (x, y) of
(Zero, r) -> [r]
(l, Zero) -> [l]
_ | x == y -> [x]
| otherwise -> [Pos, Zero, Neg]
uj5u.com熱心網友回復:
解決此問題的功能方法如下:
let compare (s0 : sign) (s1 : sign) : int =
match (s0,s1) with
| (x,y) when x = y -> 0
| (Neg, _) | (_, Pos) -> 1
| (Pos,_) | (_,Neg) -> -1
(* flatten and remove duplicates *)
let join ( xs : (sign list) list) : (sign list) =
List.sort_uniq compare (List.flatten xs)
let add (s0 : sign) (s1 : sign) : sign list =
match (s0,s1) with
| (x,y) when x = y -> [x]
| (Pos, Zero) | (Zero, Pos) -> [Pos]
| (Neg, Zero) | (Zero, Neg) -> [Neg]
| (Pos,Neg) | (Neg, Pos) -> [Pos;Neg;Zero]
let add_list (sl : sign list) (s : sign) : sign list =
join (List.map (add s) sl)
let add_abstract (sl0 : sign list) (sl1 : sign list) : sign list =
join (List.map (add_list sl0) sl1)
對于非交換運算,例如減法和除法,您可能必須更加小心。
如果您了解 monad,這里是執行此操作的 OCaml 方式:
(* "let*" is "bind" or ">>=" in Haskell *)
let (let*) (sl : sign list) (f : sign -> sign list) : sign list =
join (List.map f sl)
let add_list (sl : sign list) (s : sign) : sign list =
let* s0 = sl in
(add s s0)
let add_abstract (sl0 : sign list) (sl1 : sign list) : sign list =
let* s0 = sl0 in
let* s1 = sl1 in
(add s0 s1)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/395975.html
上一篇:從中心以螺旋形式填充矩陣
