简体   繁体   中英

F# match the beginning of an array

I have a Byte[] buffer that may contain one or multiple data frames, I need to read the first bytes to know how long the actual frame is.

This is a "non-working" version of what I want to do:

let extractFrame (buffer:byte[]) =
  match buffer with 
    | [|head1;head2;head3;..|] when head2 < (byte)128 -> processDataFrame buffer head2
    | <...others....>
    | _ -> raise(new System.Exception())

Basically, I need to evaluate the first three bytes, and then call processDataFrame with the buffer and the actual length of the frame. Depending on the headers, the frame can be data, control, etc...

Can this be done with any kind of match (lists, sequences, ...etc...)? Or will I have to create another small array with just the length of the header?(I would like to avoid this).

If you want to use matching you could create active pattern ( http://msdn.microsoft.com/en-us/library/dd233248.aspx ):

let (|Head1|_|) (buffer:byte[]) =
    if(buffer.[0] (* add condition here *)) then Some buffer.[0]
    else None 

let (|Head2|_|) (buffer:byte[]) =
    if(buffer.[1] < (byte)128) then Some buffer.[1]
    else None 

let extractFrame (buffer:byte[]) =
  match buffer with 
    | Head1 h1 -> processDataFrame buffer h1
    | Head2 h2 -> processDataFrame buffer h2
........
    | _ -> raise(new System.Exception())

I think that this might actually be easier to do using the plain if construct.

But as Petr mentioned, you can use active patterns and define your own patterns that extract specific information from the array. To model what you're doing, I would actually use a parameterized active pattern - you can give it the number of elements from the array that you need and it gives you an array with eg 3 elements back:

let (|TakeSlice|_|) count (array:_[]) = 
  if array.Length < count then None
  else Some(array.[0 .. count-1])

let extractFrame (buffer:byte[]) =
  match buffer with 
  | TakeSlice 3 [|head1;head2;head3|] when head2 < (byte)128 -> 
      processDataFrame buffer head2
  | <...others....>
  | _ -> raise(new System.Exception())  

One disadvantage of this approach is that your pattern [|h1; h2; h3|] [|h1; h2; h3|] [|h1; h2; h3|] has to match to the length that you specified 3 - the compiler cannot check this for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM