F# 尝试比较每个子列表的长度(了解lambda和list模块)

F# 尝试比较每个子列表的长度(了解lambda和list模块),f#,F#,我试图创建一个函数来检查列表子列表,看看它们是否具有相同的长度并返回bool值 [ [1;2;3]; [4;5;6] ] (return true) [ [1;2;3]; [4;5] ] (return false) 我试图学习lambda和list模块 到目前为止,我已经: let isTable (lst : 'a list list) : bool = List.forall (fun x -> x.Length = 2) ([ [1;2;3]; [4;5;6] ])

我试图创建一个函数来检查列表子列表,看看它们是否具有相同的长度并返回bool值

[ [1;2;3]; [4;5;6] ] (return true)
[ [1;2;3]; [4;5] ] (return false)
我试图学习lambda和list模块

到目前为止,我已经:

let isTable (lst : 'a list list) : bool = 

    List.forall (fun x -> x.Length = 2) ([ [1;2;3]; [4;5;6] ])  
它说x的长度是错误的

有人能解释一下我做错了什么吗?

试试下面的代码:

let isTable (lst: 'a list list) =
    match lst with
    | [] | [[]] -> false
    | []::t -> false
    | [_] -> true
    | h::t -> t |> List.forall(fun l -> l.Length = h.Length)

代码的问题在于,在检查lambda函数时,F#type推断不知道
x
的类型,因此它无法检查对象是否具有成员
长度
。类型推断从左到右检查您的程序,因此它只能在代码后面的参数
[[1;2;3];[4;5;6]]
中计算出
x
将是一个列表

有几种方法可以解决这个问题。您可以使用
List.length
,它是一个函数而不是实例成员,因此推理可以检查:

let isTable (lst : 'a list list) : bool = 
    List.forall (fun x -> List.length x = 2) [ [1;2;3]; [4;5;6] ]
一个更好的选择是使用
|>
操作符,它将左侧的内容传递给右侧的函数,因此编写
x |>f
与调用
fx
是一样的。这会将输入置于左侧,因此推理将起作用:

let isTable (lst : 'a list list) : bool = 
    [ [1;2;3]; [4;5;6] ] |> List.forall (fun x -> x.Length x = 2) 
最后,还可以添加类型注释:

let isTable (lst : 'a list list) : bool = 
    List.forall (fun (x:_ list) -> x.Length = 2) [ [1;2;3]; [4;5;6] ]

在这三种方法中,我认为最惯用的解决方案是使用
|>
,但是
List.length
也很常见。

问题是,F的类型推断系统没有坚定地在您想要执行
x.length
的地方将
x
识别为列表。这可能看起来很奇怪,因为如果您使用Intellisense(例如,将鼠标悬停在
x
),它会告诉您它是一个列表,但编译器会抱怨

其原因是,当使用面向对象(OO)的点
表示法时,F#的类型推理不起作用,而使用函数点
表示法时,F#的类型推理效果要好得多。为了区分两者,F#(和.Net)中的约定是类成员(方法和属性)以大写字母开头(也称为Pascal大小写),因此
x.Length
。另一方面,函数样式代码(如模块和/或记录成员中的函数)以小写(称为驼峰大小写)开头,如
List.length

请注意这两种样式之间的差异:

  • OO,调用一个方法:
    x.Length
  • 函数,调用函数:
    List.length x
如果要使用OO样式,通常情况下,解决方案是添加类型注释,可以通过以下几种方式执行:

  • fun(x:u列表)->x.长度=2
  • fun x->(x:u列表)。长度=2
一般来说,使用功能性风格是更好的做法。但是,你并不总是有选择的余地。例如,有许多字符串方法没有函数等价物:

fun (s:string) -> s.StartsWith "Hello"

我还想指出的是,您的代码并没有真正做到您想要的。只有当所有列表的长度都为2时,它才会返回true,而不是当所有列表的长度都相同时

kagetoki的解决方案很有效,并且还演示了对列表使用模式匹配

以下是一个简化版本:

let isTable lst =
    match lst with
    | h::t -> t |> List.forall(fun (l:_ list) -> l.Length = h.Length)
    | _    -> true
注意,通过声明
l
是一个列表,它已经知道
h
也是一个列表

最后,为了好玩,一款超级紧凑(但不太显眼)的版本:

let isTable =
    function
    | h::t -> t |> List.forall (List.length >> (=) h.Length)
    | _    -> true

谢谢,但是我的代码通过将x.Length更改为x.Length来工作!