Haskell类型与类型类问题:记录构造缺字段及Car坐标查找
解决Haskell中记录构造缺字段问题与二维列表Car元素坐标查找
一、记录构造缺字段的解决方案
你定义的Person和Car都是带记录语法的代数数据类型,Haskell的记录构造器必须传入所有字段的值,直接只给部分字段会编译报错。解决这个问题最常用的方式是定义一个带默认值的基础实例,再通过记录更新语法修改需要的字段:
-- 定义Person的默认实例,所有字段设为初始值 defaultPerson :: Person defaultPerson = Person { firstName = "" , lastName = "" , age = 0 , height = 0.0 , phoneNumber = "" , flavor = "" } -- 创建自定义Person时,只修改需要的字段 alice :: Person alice = defaultPerson { firstName = "Alice", age = 30, flavor = "Chocolate" } -- Car同理 defaultCar :: Car defaultCar = Car { company = "", model = "", year = 0 } tesla :: Car tesla = defaultCar { company = "Tesla", model = "Model 3", year = 2024 }
如果使用GHC编译器,还可以开启NamedFieldPuns或RecordWildCards扩展来简化记录的使用,但核心思路都是避免直接用全字段构造器创建实例。
二、完成二维列表中Car元素的坐标查找函数
你的enumerate函数已经帮我们把列表和索引绑定起来了,接下来只需要嵌套遍历二维列表的行和列,通过模式匹配过滤出Car类型的Things,收集对应的坐标即可。这里提供两种实现方式:
方式1:用辅助函数判断类型
enumerate = zip [0..] findCar :: [[Things]] -> [(Int, Int)] findCar things = [ (x, y) | (y, row) <- enumerate things -- 遍历每一行,获取行号y , (x, thing) <- enumerate row -- 遍历行内元素,获取列号x , isCar thing -- 筛选出Car类型的元素 ] where isCar (C _) = True -- 匹配包装了Car的Things isCar _ = False -- 排除Person类型的元素
方式2:直接在列表推导中模式匹配(更简洁)
利用Haskell列表推导的模式匹配特性,直接匹配C _类型的元素,自动过滤掉P Person的情况:
enumerate = zip [0..] findCar :: [[Things]] -> [(Int, Int)] findCar things = [ (x, y) | (y, row) <- enumerate things , (x, C _) <- enumerate row -- 仅匹配Car类型的元素,自动跳过Person ]
测试一下这个函数:
-- 测试数据 testThings :: [[Things]] testThings = [ [P defaultPerson, C tesla] , [C defaultCar, P alice] ] -- 调用findCar testThings会返回 [(1,0), (0,1)]
这个结果对应:第0行第1列是Car,第1行第0列是Car,符合预期。
内容的提问来源于stack exchange,提问作者oldboy123
相关产品推荐
相关产品推荐

