我想返回列表中元素的前一个元素.我打算获取参数索引并使用它来弃用列表,使得参数是最后一个元素,然后反转它并获取反向列表的第二个元素.我得到的错误:类型elemIndex是Maybe Int同时take功能要求Int.我想修复它或使用简单的递归编写代码是否有使用递归的较短代码?
precedingElement :: Eq a => a -> [a] -> Maybe a
precedingElement elt lst | lst == [] = error "List is empty"
| elt `notElem` lst = Nothing
| otherwise = Just x where x = snd (reverse (take (elt `elemIndex` lst) lst))
Run Code Online (Sandbox Code Playgroud)
我最喜欢的一个被低估的实用程序对于这样的问题非常方便.让我有一个落后的名单,所以我不需要扭转我的大脑.
data Bwd x = B0 | Bwd x :< x -- rightmost is nearest
Run Code Online (Sandbox Code Playgroud)
将列表元素视为算盘线上的珠子.向左轻拂几下,然后将手指放在下一个上.你有什么?手指左侧的珠子列表(最右侧最近),手指右侧的珠子列表(最左侧最近),手指放在珠子上.
也就是说,列表的单孔元素上下文由孔的任一侧的一对向后和向前列表给出.
type ListContext x = (Bwd x, [x])
Run Code Online (Sandbox Code Playgroud)
这些谁知道我的老歌承认ListContext作为衍生的[].
焦点元素(你的手指在珠子上)是
type ListFocus x = (ListContext x, x)
Run Code Online (Sandbox Code Playgroud)
并且有一个有用的操作,用它的上下文装饰每个列表元素,使它成为焦点.
focus :: [x] -> [ListFocus x]
focus = go B0 where
go xz [] = []
go xz (x : xs) = ((xz, xs), x) : go (xz :< x) xs
Run Code Online (Sandbox Code Playgroud)
例如,
focus [1,2,3] = [((B0,[2,3]),1), ((B0 :< 1,[3]),2), ((B0 :< 1 :< 2,[]),3)]
Run Code Online (Sandbox Code Playgroud)
现在很容易回答涉及元素及其周围环境的各种问题.你可能focus不仅仅是为了解决这个问题而构建,但它是我保留的那种东西,因为它解决了很多问题.
[p | ((_ :< p,_),q) <- focus xs, q == x]
Run Code Online (Sandbox Code Playgroud)
计算p位于xin 左侧的所有值xs.如你看到的.
(顺便说一下,这个focus操作并非来自任何地方.它来自列表数据类型的差异结构.这个答案(在它被称为picks)中更详细地讲述了列表故事,这个答案开发了数据类型的通用故事.)
为了返回给定元素的前一个元素,可以使用一些模式匹配和递归:
precedingElement _ [] = Nothing
precedingElement _ [x] = Nothing
precedingElement elt (x:y:rest)
| y == elt = Just x
| otherwise = precedingElement elt (y:rest)
Run Code Online (Sandbox Code Playgroud)