狀態機在這裏是合適的解決方案。有兩種常用的方法來實現一個:
這東西是功能性編程的麪包和黃油。這裏是一個優雅的解決方案寫在F#前者的風格你的問題,並針對自己的數據集運行:
> let rec skip = function
| _, yss, [] -> yss
| [_; _; _] as ys, yss, xs -> record ([], ys, yss, xs)
| ys, yss, x::xs when x >= 5 -> skip (x::ys, yss, xs)
| ys, yss, x::xs -> skip ([], yss, xs)
and record = function
| ys', ys, yss, [] -> (ys' @ ys) :: yss
| [_; _], ys, yss, xs -> skip ([], ys :: yss, xs)
| ys', ys, yss, x::xs when x < 3 -> record (x::ys', ys, yss, xs)
| ys', ys, yss, x::xs -> record ([], x::ys' @ ys, yss, xs);;
val skip : int list * int list list * int list -> int list list
val record : int list * int list * int list list * int list -> int list list
> let run xs = skip([], [], xs) |> List.map List.rev |> List.rev;;
val run : int list -> int list list
> run [0;0;0;7;8;0;0;2;5;6;10;11;10;13;5;0;1;0];;
val it : int list list = [[5; 6; 10; 11; 10; 13; 5]]
,這裏是寫在後者的風格相同的解決方案:
> type 'a state =
| Skip of 'a list
| Record of 'a list * 'a list;;
type 'a state =
| Skip of 'a list
| Record of 'a list * 'a list
> let rec apply (state, yss) x =
match state, yss with
| Skip([_; _; _] as ys), yss -> apply (Record([], ys), yss) x
| Skip ys, yss when x >= 5 -> Skip(x::ys), yss
| Skip ys, yss -> Skip[], yss
| Record([_; _], ys), yss -> apply (Skip[], ys :: yss) x
| Record(ys', ys), yss when x < 3 -> Record (x::ys', ys), yss
| Record(ys', ys), yss -> Record ([], x::ys' @ ys), yss;;
val apply : int state * int list list -> int -> int state * int list list
> let run xs =
match List.fold apply (Skip [], []) xs with
| Skip _, yss -> yss
| Record(ys', ys), yss -> (ys' @ ys) :: yss
|> List.map List.rev |> List.rev;;
val run : int list -> int list list
> run [0;0;0;7;8;0;0;2;5;6;10;11;10;13;5;0;1;0];;
val it : int list list = [[5; 6; 10; 11; 10; 13; 5]]
注第一個解決方案是如何一次吃完整個輸入,而後者是一次咬下一個數據並返回一個新的狀態,準備吃另一個數據。因此,後者依次應用於每個數據,使用fold
,並且最終的半食用狀態必須在返回之前適當地消耗。
我特別想找到一種方法來從更具說明性的可讀描述中分離出單調邏輯。我傾向於使用更自然的語言(如Prolog或F#),或者將難以閱讀的代碼封裝在經過良好測試的模塊中。儘管如此,我還是希望不需要編寫一堆額外的代碼...... – 2010-05-25 01:36:44