如何使用Active Pattern而不是guard来编写startsWith列表函数?

Ser*_*hov 4 f# guard-clause

我需要检查列表是否以另一个更短的列表开头.该功能,当使用时,警卫很简单:

let rec startsWith l1 l2 =
  match l1, l2 with
  | [], _ | _, [] -> true
  | x::xs, y::ys when x = y -> startsWith xs ys
  | _ -> false

let lst1 = [ 1; 2; 1 ]
let lst2 = [ 1; 2; 1; 2; 3; ]
let lst3 = [ 1; 3; 1; 2; 3; ]

let c1 = startsWith lst1 lst2  // true
let c2 = startsWith lst1 lst3  // false
Run Code Online (Sandbox Code Playgroud)

但无论我沿着活动模式的路线尝试过什么:

let (|HeadsMatch|) (l1 : ('a) list) (l2 : ('a) list) = 
  if l1.Head = l2.Head then Some(l1.Tail, l2.Tail) else None

let rec startsWith l1 l2 =
   match l1, l2 with
   | [], _ | _, [] -> true
   | HeadsMatch /* need to capture the result */ -> startsWith t1 t2
   | _ -> false
Run Code Online (Sandbox Code Playgroud)

我无法编译.如何使用Active模式制作此功能的版本?如果这是不可能的,你能解释一下原因吗?

PS还有其他很好的方法来编写上述功能吗?

编辑:我从丹尼尔的回答中摘取了片段,以免分散真正的问题.

编辑:我的问题从一开始就开始了.我已将活动模式功能定义为

let (|HeadsMatch|_|) lst1 lst2 =
Run Code Online (Sandbox Code Playgroud)

但应该是

let (|HeadsMatch|_|) (lst1, lst2) =
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它将与接受的答案匹配.

Dan*_*iel 5

我想最好的方式可能是

let startsWith = Seq.forall2 (=)
Run Code Online (Sandbox Code Playgroud)

如果你想从头开始编写,你需要在两个列表上匹配:

let rec startsWith l1 l2 =
  match l1, l2 with
  | [], _ | _, [] -> true
  | x::xs, y::ys when x = y -> startsWith xs ys
  | _ -> false
Run Code Online (Sandbox Code Playgroud)

如果你想用活动模式编写它以用于学习目的,那么使用Tarmil的定义就可以了

let rec startsWith l1 l2 =
  match l1, l2 with
  | [], _ | _, [] -> true
  | HeadsMatch(xs, ys) -> startsWith xs ys
  | _ -> false
Run Code Online (Sandbox Code Playgroud)