我最近开始阅读F#,很明显我很快就得到了一个新手级别的问题。它是关于列表(集合)。
根据F#手册,有两个操作来构建列表,它们是缺点(aka ::
)和@
。鉴于事实@
更通用(可以合并子列表,而不是单个元素,也可以附加到尾部,与cons操作不同),我的问题是:在哪种情况下我们必须使用::
而不是@
来避免歧义,或者不想要的副作用等等?
换句话说:理论上::
是否多余?
答案 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)
并且稍后reexposed为List.append
:
let append list1 list2 = list1 @ list2
除了“OCaml正在做”之外,没有什么理由可以将它作为操作员暴露出来。
实际上,很少有一个有效的附加列表的情况,并且F#中的大部分集合处理都是使用更适合串联的序列或其他集合类型,但是没有为它提供专用的运算符。单链表是您不想附加的结构的教科书示例。
通过这种方式,@
纯粹是教育性的 - 似乎只存在让新手加入语言(或提醒他们注意他们碰巧使用的数据结构的性能特征)。
答案 2 :(得分:0)
它们是两个不同的函数,有两个行为,可用于创建列表。
:: operator将一个元素添加到列表中 @合并两个列表
使用列表可以轻松添加元素。合并两个列表需要更多工作。
最好使用:: operator,并保留@运算符仅用于合并目的。