我是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
我注意到这种列表不是纯函数,而是对某些应用程序有用。它应该被视为有害吗?
谢谢,
鲍勃
答案 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
我也不能想到这样一个列表会有用的用例,但我想我受到了创造力的限制;)