Haskell中有索引列表吗?它是好的还是坏的?

Haskell中有索引列表吗?它是好的还是坏的?,haskell,data-structures,functional-programming,Haskell,Data Structures,Functional Programming,我是哈斯克尔世界的新来者,我想知道是否有这样的事情: data IndexedList a = IList Int [a] findIndex::(Int->Int)->IndexedList a->(a,IndexedList a) findIndex f (IList x l) = (l!!(f x), IList (f x) l) next::IndexedList a->(a,IndexedList a) next x = findIndex (+1) x

我是哈斯克尔世界的新来者,我想知道是否有这样的事情:

data IndexedList a = IList Int [a]

findIndex::(Int->Int)->IndexedList a->(a,IndexedList a)
findIndex f (IList x l) = (l!!(f x), IList (f x) l)

next::IndexedList a->(a,IndexedList a)
next x = findIndex (+1) x
我注意到这种列表并不是纯粹的功能性列表,而是对某些应用程序有用的列表。它应该被认为是有害的吗

谢谢


Bob

与您认为的相反,这个列表实际上纯粹是功能性的。原因是
IList(f x)l
创建了一个新列表(并且,正如您可能认为的那样,不会修改当前的索引列表)。一般来说,在Haskell中创建非纯函数数据结构或函数并不容易,只要您远离
unsafePerformIO

我建议不要使用
IndexedList
的原因是无法保证索引小于列表的长度。在这种情况下,查找
l!!(f x)
将失败并出现异常,这在Haskell中通常被认为是糟糕的样式。另一种方法是使用安全查找,它返回一个
可能是一个
,如下所示:

findIndex :: (Int -> Int) -> IndexedList a -> (Maybe a, IndexedList a)
findIndex f (IList i l) = (maybe_x, IList new_i l)
    where
        new_i   = f i
        maybe_x = if new_i < length l 
                  then Just (l !! newI) 
                  else Nothing
findIndex::(Int->Int)->索引列表a->(可能是a,索引列表a)
findIndex f(IList i l)=(可能是x,IList new i l)
哪里
新的_i=f i
如果新的长度小于l,则可能为
然后就(我!!纽伊)
没有别的了

我也无法想象这样一个列表会有用的用例,但我想我的创造力有限;)

有一个带有指向列表中特定位置的指针的列表肯定很有用。然而,在Haskell中通常使用的方式有些不同——我们倾向于使用拉链,而不是使用显式指针

列表拉链如下所示

data ListZipper a = LZ [a] a [a] deriving (Show)
您应该将中间字段
a
视为当前指向的元素,第一个字段
[a]
视为当前位置之前的元素,最后一个字段
[a]
视为当前位置之后的元素

通常,为了提高效率,我们将元素以相反的顺序存储在当前元素之前,因此带有指向中间元素的指针的列表
[0,1,2,*3*,4,5,6]
将存储为

LZ [2,1,0] 3 [4,5,6]
可以定义将指针向左或向右移动的函数

left  (LZ (a:as) b bs) = LZ as a (b:bs)
right (LZ as a (b:bs)) = LZ (a:as) b bs
如果要向左或向右移动
n
次,则可以借助于接受另一个函数的函数,并将其
n
次应用于其参数

times n f = (!!n) . iterate f
所以要向左移动三次,你可以使用

>> let lz = LZ [2,1,0] 3 [4,5,6]
>> (3 `times` left) lz
LZ [] 0 [1,2,3,4,5,6]
您的两个函数
findIndex
next
可以写成

next :: ListZipper a -> (a, ListZipper a)
next = findIndex 1

findIndex :: Int -> ListZipper a -> (a, ListZipper a)
findIndex n x = let y@(LZ _ a _) = (n `times` right) x in (a, y)

为什么这不完全是功能性的?@TomEllis我认为它隐藏了操纵索引的副作用?不过你实际上并没有修改任何东西。数据封装的概念与副作用的概念是分开的。谢谢,我正在浏览H99,它的一个用例可以在中找到