Haskell 在给定索引处使用元素更新列表
是否有这样的功能:Haskell 在给定索引处使用元素更新列表,haskell,Haskell,是否有这样的功能: update :: a -> Int -> [a] -> Maybe [a] 这样,它将使用给定索引处的元素更新列表,或者在索引超出边界时返回Nothing 例如: > update 9 1 [3,4,5] Just [3,9,5] > update 4 2 [3,4,5] Just [3,4,4] > update 6 5 [3,4,5] Nothing 它可以写得相当残酷: update val idx l = if idx
update :: a -> Int -> [a] -> Maybe [a]
这样,它将使用给定索引处的元素更新列表,或者在索引超出边界时返回Nothing
例如:
> update 9 1 [3,4,5]
Just [3,9,5]
> update 4 2 [3,4,5]
Just [3,4,4]
> update 6 5 [3,4,5]
Nothing
它可以写得相当残酷:
update val idx l =
if idx >= length l || idx < 0
then Nothing
else updateUnsafe val idx l
updateUnsafe _ _ [] = error "Empty List"
updateUnsafe val idx (h:t) =
if idx == 0 then val:t
else h:(updateUnsafe val (idx - 1) t)
然而,当我们得到在第一种情况下可以修复的永无止境列表时,它们都将无限循环。我们可以重写updateUnsafe
以不抛出错误,而是让它在上运行,也可以改为类型:
update _ idx _ | idx < 0 = Nothing
update _ _ [] = Nothing
update val idx (h:t) =
if idx == 0 then Just $ val:t
else (h:) <$> (updateUnsafe val (idx - 1) t)
update idx idx<0=无
更新u[]=无
更新val idx(h:t)=
如果idx==0,则只需$val:t
else(h:)(updateUnsafe val(idx-1)t)
在标准库中,我看不到任何函数可以解决这个问题。它可以非常残酷地编写:
update val idx l =
if idx >= length l || idx < 0
then Nothing
else updateUnsafe val idx l
updateUnsafe _ _ [] = error "Empty List"
updateUnsafe val idx (h:t) =
if idx == 0 then val:t
else h:(updateUnsafe val (idx - 1) t)
然而,当我们得到在第一种情况下可以修复的永无止境列表时,它们都将无限循环。我们可以重写updateUnsafe
以不抛出错误,而是让它在上运行,也可以改为类型:
update _ idx _ | idx < 0 = Nothing
update _ _ [] = Nothing
update val idx (h:t) =
if idx == 0 then Just $ val:t
else (h:) <$> (updateUnsafe val (idx - 1) t)
update idx idx<0=无
更新u[]=无
更新val idx(h:t)=
如果idx==0,则只需$val:t
else(h:)(updateUnsafe val(idx-1)t)
我在标准库中看不到任何函数可以解决这个问题,我会这样做。特别要注意的是,它不使用任何部分函数或不完整的模式匹配,即使在命中它们“永远”不会发生的地方也是如此。它还正确处理负索引的情况,立即返回Nothing
,而不是永远循环
update :: a -> Int -> [a] -> Maybe [a]
update y = go
where
go _ [] = Nothing -- whoops, called update with too large an index
go i (x:xs) = case i `compare` 0 of
LT -> Nothing -- whoops, called update with a negative index
EQ -> Just (y:xs)
GT -> (x:) <$> update y (pred i) xs
update::a->Int->[a]->可能[a]
更新y=go
哪里
go[]=Nothing——哎呀,调用的更新索引太大了
go i(x:xs)=案例i`compare`0 of
LT->Nothing--哎呀,叫“带负索引的更新”
EQ->Just(y:xs)
GT->(x:)更新y(pred i)xs
我会这样做。特别要注意的是,它不使用任何部分函数或不完整的模式匹配,即使在命中它们“永远”不会发生的地方也是如此。它还正确处理负索引的情况,立即返回Nothing
,而不是永远循环
update :: a -> Int -> [a] -> Maybe [a]
update y = go
where
go _ [] = Nothing -- whoops, called update with too large an index
go i (x:xs) = case i `compare` 0 of
LT -> Nothing -- whoops, called update with a negative index
EQ -> Just (y:xs)
GT -> (x:) <$> update y (pred i) xs
update::a->Int->[a]->可能[a]
更新y=go
哪里
go[]=Nothing——哎呀,调用的更新索引太大了
go i(x:xs)=案例i`compare`0 of
LT->Nothing--哎呀,叫“带负索引的更新”
EQ->Just(y:xs)
GT->(x:)更新y(pred i)xs
uhh,当这完全可以处理时,您为什么要故意抛出错误?例如,update::a->Int->[a]->可能[a]
或..->([a],Bool)
?嗯,我的意思是,你总是可以根据需要手动抛出一些东西,但它不属于update
函数。很好的建议如果索引超出范围,为什么不直接返回原始列表呢?我不认为这比替换一个已经存在值的元素更模糊。(这与take
如果请求大小大于参数的长度,则返回最长的列表的精神是一样的。)根据这一点,没有这样的函数,但答案是您需要的。@chepner我认为a可能更具原则性。通过检查Maybe,您可以随时从Maybe版本切换到自返回版本,但是如果您始终返回的唯一版本[a]
,那么判断替换是否成功并不便宜。uhh,当这完全可以处理时,为什么要故意抛出错误?例如,update::a->Int->[a]->可能[a]
或…->([a],Bool)
?嗯,我的意思是,你总是可以根据需要手动抛出一些东西,但它不属于update
函数。很好的建议如果索引超出范围,为什么不直接返回原始列表呢?我不认为这比替换一个已经存在值的元素更模糊。(这与take
如果请求大小大于参数的长度,则返回最长的列表的精神是一样的。)根据这一点,没有这样的函数,但答案是您需要的。@chepner我认为a可能更具原则性。通过检查Maybe,您可以随时从Maybe版本转换为自动返回版本,但是如果您始终返回的唯一版本[a]
,那么判断替换是否成功并不便宜。第一个版本相当危险,因为它将在无限列表上无限循环。我认为Data.list.splitAt
在这里会有很大帮助。类似于(,[])的idx xs处的大小写拆分->错误“;(before,:after)->before++val:after
第一个版本非常危险,因为它将在无限列表上无限循环。我认为Data.list.splitAt
在这里会有很大帮助。类似于(,[])的idx xs处的大小写拆分->错误“;(before,:after)->before++val:after
可能在顶部添加另一个子句,以便只处理一次负索引?可能在顶部添加另一个子句,以便只处理一次负索引?