You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell自定义atIndex函数越界判断失效问题求助

解决Haskell atIndex函数的越界判断失效问题

首先咱们来拆解问题出在哪:当你传入的索引超过列表长度时,atIndexAcc会一直递归遍历列表,直到列表被拆成空列表。但你只给atIndexAcc定义了(h:t)(非空列表)的匹配模式,完全没处理空列表的情况——这就直接触发了非穷尽模式异常。你写的counter > arr_size判断根本没机会执行,因为列表只有5个元素时,counter从0涨到4就已经遍历完所有元素了,再递归的话t是空列表,(h:t)模式匹配不上,直接报错。

接下来给你两种修改方案,让越界判断正常生效:

方案1:在递归前提前拦截无效索引

既然有效索引的范围是0 <= index < 列表长度,咱们可以在atIndex的主逻辑里先做这个判断,不用进入递归就直接抛出错误:

lengthOf :: Num t => [t] -> t
lengthOf [] = 0
lengthOf arr = lengthOfAcc arr 1
  where
    lengthOfAcc :: Num t => [t] -> t -> t
    lengthOfAcc (_:t) counter = if null t then counter else lengthOfAcc t (counter + 1)

atIndex :: (Ord t, Num t) => [t] -> t -> t
atIndex [] _ = error "atIndex: Empty list passed!"
atIndex arr index = 
  let arr_size = lengthOf arr
  in if index < 0 
       then error "atIndex: Index cannot be smaller than 0!"
       else if index >= arr_size  -- 提前判断索引是否超出上限
              then error "atIndex: Out of array range!"
              else atIndexAcc arr index 0 arr_size
  where
    atIndexAcc :: (Ord t, Eq t, Num t) => [t] -> t -> t -> t -> t
    atIndexAcc (h:t) index counter _ = 
      if counter == index 
        then h 
        else atIndexAcc t index (counter + 1) _

这个方案的好处是避免不必要的递归,直接在入口处拦截无效索引,逻辑更直观。

方案2:给atIndexAcc添加空列表模式处理

如果你希望在递归过程中处理越界情况,可以给atIndexAcc加上空列表的匹配模式,当列表遍历完还没找到对应索引时,直接抛出错误:

lengthOf :: Num t => [t] -> t
lengthOf [] = 0
lengthOf arr = lengthOfAcc arr 1
  where
    lengthOfAcc :: Num t => [t] -> t -> t
    lengthOfAcc (_:t) counter = if null t then counter else lengthOfAcc t (counter + 1)

atIndex :: (Ord t, Num t) => [t] -> t -> t
atIndex [] _ = error "atIndex: Empty list passed!"
atIndex arr index = if index < 0 
                      then error "atIndex: Index cannot be smaller than 0!"
                      else atIndexAcc arr index 0 (lengthOf arr)
  where
    atIndexAcc :: (Ord t, Eq t, Num t) => [t] -> t -> t -> t -> t
    atIndexAcc [] _ _ _ = error "atIndexAcc: Out of array range!"  -- 新增空列表处理
    atIndexAcc (h:t) index counter _ = 
      if counter == index 
        then h 
        else atIndexAcc t index (counter + 1) _

这里移除了原来的counter > arr_size判断,因为当列表为空时,就说明已经遍历完所有元素但没找到对应索引,必然是越界了。

额外小提示

你自己实现的lengthOf功能是对的,但Haskell标准库已经有length函数(返回Int类型),如果不需要自定义逻辑的话,可以用fromIntegral . length来转换类型,简化代码:

lengthOf :: Num t => [t] -> t
lengthOf = fromIntegral . length

内容的提问来源于stack exchange,提问作者Zaphiel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:43:57