F#:为什么同时拥有' ::'和' @'

时间:2018-05-23 17:14:02

标签: f#

我最近开始阅读F#,很明显我很快就得到了一个新手级别的问题。它是关于列表(集合)。

根据F#手册,有两个操作来构建列表,它们是缺点(aka ::)和@。鉴于事实@更通用(可以合并子列表,而不是单个元素,也可以附加到尾部,与cons操作不同),我的问题是:在哪种情况下我们必须使用::而不是@来避免歧义,或者不想要的副作用等等?

换句话说:理论上::是否多余?

3 个答案:

答案 0 :(得分:11)

list类型有两个构造函数:[]::。如果删除::,则只会留下[]构造函数,从而无法创建非空列表。

请注意,[1;2;3]之类的内容是1::2::3::[]的语法糖,所以它依赖于::的存在。

同样,@是使用::定义的函数,因此如果::不存在,@也不会。

请注意,@并不适合替代::定义中的list,如果您还没有办法要构建非空列表,@无法用于创建它们([] @ []仍然是一个空列表。)

即使您为单项列表添加了构造函数,@也会导致表达模糊,因为[1;2;3]可以表示为([1] @ [2]) @ [3][1] @ ([2] @ [3]) (另外,您可以在任何地方添加@ [])。因此,对于语义上等效的列表,您最终会得到几种不同的表示形式。

答案 1 :(得分:5)

反过来说,@对于所有意图和目的都是多余的,我相信它在核心库中作为运算符存在的原因纯属历史。

我认为,如果它已经退役并且推荐使用List.append会更好。

今天的情况是@prim-types.fs中定义为以下函数的等价物:

let rec (@) x y = 
    match x with 
    | [] -> y 
    | (h::t) -> h :: (t @ y)

并且稍后reexposedList.append

let append list1 list2 = list1 @ list2

除了“OCaml正在做”之外,没有什么理由可以将它作为操作员暴露出来。

实际上,很少有一个有效的附加列表的情况,并且F#中的大部分集合处理都是使用更适合串联的序列或其他集合类型,但是没有为它提供专用的运算符。单链表是您不想附加的结构的教科书示例。

通过这种方式,@纯粹是教育性的 - 似乎只存在让新手加入语言(或提醒他们注意他们碰巧使用的数据结构的性能特征)。

答案 2 :(得分:0)

它们是两个不同的函数,有两个行为,可用于创建列表。

:: operator将一个元素添加到列表中 @合并两个列表

使用列表可以轻松添加元素。合并两个列表需要更多工作。

最好使用:: operator,并保留@运算符仅用于合并目的。