Haskell中是否有索引列表,是好还是坏?

时间:2013-12-30 15:27:03

标签: haskell data-structures functional-programming

我是Haskell世界的新来者,我想知道是否有这样的事情:

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

我注意到这种列表不是纯函数,而是对某些应用程序有用。它应该被视为有害吗?

谢谢,

鲍勃

2 个答案:

答案 0 :(得分:10)

拥有一个指向列表中特定位置的列表肯定是有用的。但是,它通常在Haskell中完成的方式有所不同 - 而不是使用显式指针,我们倾向于使用 zipper

列表拉链看起来像这样

data ListZipper a = LZ [a] a [a] deriving (Show)

您应该将中间字段a视为当前指向的元素,第一个字段[a]作为当前位置之前的元素,最后一个字段{{1}作为当前位置之后的元素。

通常我们以相反的顺序将元素以相反的顺序存储在当前元素之前,以提高效率,以便带有指向中间元素的指针的列表[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

答案 1 :(得分:4)

与您认为此列表实际上纯粹功能相反。原因是IList (f x) l创建了一个新列表(并且您可能认为不会修改当前的IndexedList)。在Haskell中创建非纯函数的数据结构或函数通常并不容易,只要您远离unsafePerformIO

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

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

我也不能想到这样一个列表会有用的用例,但我想我受到了创造力的限制;)