@amalloy的评论列表理解仅限于"本地"视角,这是这里的关键见解.写作nub列表理解是一种明智的方式,但首先需要改变你的观点.
遗憾地从库中省略的一个常用函数是用其上下文装饰列表的每个元素的函数.
picks :: [x] -> [([x], x, [x])]
picks [] = []
picks (x : xs) = ([], x, xs) : [(x : bs, y, as) | (bs, y, as) <- picks xs]
Run Code Online (Sandbox Code Playgroud)
所以
picks [1,2,3] =
[([],1,[2,3]), ([1],2,[3]), ([1,2],3,[])]
Run Code Online (Sandbox Code Playgroud)
列表的每个元素都放在三元组的中间,左边是元素'before',右边是元素''.
我的这个答案解释了深层结构,它picks在某种意义上构成了一个"标准"操作,可以从列表结构中得出.但是我们不需要那些背景信息来部署它.
该picks函数为我们提供了我们需要编写的上下文信息nub作为列表理解.我们需要做的就是挑选出他们自己的"前列表"中没有出现的元素.
myNub :: Eq x => [x] -> [x]
myNub xs = [x | (bs, x, as) <- picks xs, not (elem x bs)]
Run Code Online (Sandbox Code Playgroud)
我对这项操作的效率没有任何承诺,但我确实喜欢将列表理解与额外的空间背景相结合的清晰度.