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

Haskell:根据相同ID生成(Name,同ID名称列表)的编译错误排查

解决Haskell函数编译错误:根据Integer值分组Maybe String列表

我来帮你排查并解决这个Haskell的编译错误问题~先理清楚你的需求和问题点:

测试数据

datatest :: [(Maybe String, Integer)]
datatest = [(Just "name1" , 111), (Just "name2" , 222), (Nothing, 333), (Just "name4",111)]

期望输出

你希望把每个元组的Maybe String,和所有拥有相同Integer值的Maybe String列表配对,得到:

[(Just "name1",[Just "name1",Just "name4"]),(Just "name2",[Just "name2"]),(Nothing,[]),(Just "name4", [Just "name1",Just "name4"])]

你的原函数代码

你编写的test123函数逻辑方向是对的,但存在类型错误:

import qualified Data.List as DL  -- 推测你应该导入了这个模块,否则DL.foldl'无法识别

test123 :: [(Maybe String, Integer)] -> [(Maybe String,[Maybe String])]
test123 rows = fmap (\(name,id) -> 
    DL.foldl' (\(rowAcc,nameAcc) (fname,fid) -> 
        case (id,fid) of 
            (val1,val2) -> if(val1==val2) then (fname,(nameAcc++[name]) ) else (fname,nameAcc) 
            (Nothing , _) -> (fname,nameAcc) 
        ) ("",[]) rows 
    ) rows 

编译错误信息

编译器抛出的类型不匹配错误:

error: • Couldn't match type ‘Integer’ with ‘Maybe t0’
Expected type: [(Maybe String, Maybe t0)]
Actual type: [(Maybe String, Integer)]
• In the third argument of ‘DL.foldl'’, namely ‘rows’

error: • Couldn't match type ‘Integer’ with ‘Maybe t0’
Expected type: [(Maybe String, Maybe t0)]
Actual type: [(Maybe String, Integer)]
• In the second argument of ‘fmap’, namely ‘rows’

错误原因拆解

  1. 完全错误的case分支:你在case (id,fid)里写了(Nothing, _)分支,但id和fid都是Integer类型,Nothing是Maybe类型的构造器,两者完全不兼容。这直接导致编译器试图把Integer强制转换成Maybe t0,触发类型匹配失败。
  2. 初始值类型不匹配:foldl'的初始值("",[])中,第一个元素是String类型,但你的元组第一个元素是Maybe String,进一步加剧了类型推导的混乱。
  3. 逻辑冗余:你在foldl'里维护了rowAcc变量,但全程没有用到它,完全是多余的。

修正后的两种实现方案

方案一:用Map分组(高效简洁,推荐)

先把所有元组按Integer值分组,构建ID到名称列表的映射,再遍历原列表匹配对应分组。时间复杂度O(n),逻辑清晰:

import qualified Data.Map as Map
import Data.Map (Map)

test123 :: [(Maybe String, Integer)] -> [(Maybe String, [Maybe String])]
test123 rows = 
    -- 第一步:构建ID到对应名称列表的映射
    let idToNames = Map.fromListWith (++) [(id, [name]) | (name, id) <- rows]
    -- 第二步:遍历原列表,每个名称对应到映射中的列表;Nothing对应空列表
    in map (\(name, id) -> (name, Map.findWithDefault [] id idToNames)) rows

方案二:修正原foldl'实现(保留你的思路)

如果想保留你用foldl'遍历的思路,修正类型和逻辑错误后的版本:

import qualified Data.List as DL

test123 :: [(Maybe String, Integer)] -> [(Maybe String, [Maybe String])]
test123 rows = fmap (\(targetName, targetId) -> 
    -- 只需要收集匹配targetId的名称,不需要维护多余的rowAcc
    let matchedNames = DL.foldl' (\acc (currentName, currentId) -> 
            if currentId == targetId then acc ++ [currentName] else acc
        ) [] rows
    in (targetName, matchedNames)
    ) rows

验证结果

用你的datatest测试两种方案,都会得到完全符合期望的输出:

> test123 datatest
[(Just "name1",[Just "name1",Just "name4"]),(Just "name2",[Just "name2"]),(Nothing,[]),(Just "name4",[Just "name1",Just "name4"])]

内容的提问来源于stack exchange,提问作者Samuel D'costa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:59:53