我需要检查列表是否以另一个更短的列表开头.该功能,当使用时,警卫很简单:
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)
在这种情况下,它将与接受的答案匹配.
我想最好的方式可能是
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)