这是我的功能 .
toResult :: [SqlValue] -> IO Course
toResult [ fromSql -> courseid, fromSql -> title,
fromSql -> name, fromSql -> version,
fromSql -> cdate, fromSql -> fid ] = do
let courseXML = show (fid :: Int)
xml <- B.readFile courseXML
let Right doc = parseXML courseXML xml
let passing = read $ T.unpack $ fromJust
$ lookup (T.pack "PassingScore")
$ elementAttrs $ head $ docContent doc
return (Course courseid title name version cdate passing)
对此函数的任何调用都不会传递一个只有六个SqlValue值列表的参数,这是一个错误 .
编译它会返回非穷举模式匹配警告:
Pattern match(es) are non-exhaustive
In an equation for `toResult':
Patterns not matched:
[]
[_]
[_, _]
[_, _, _]
...
我知道我可以忽略警告,但我正在努力学习如何正确地处理这个Haskell .
任何和所有建议都表示赞赏 .
戴夫
更新中...
根据此处提供的建议,我已将代码更改为当前形式 .
toResult :: (SqlValue, SqlValue, SqlValue, SqlValue, SqlValue, SqlValue) -> IO Course
toResult ( fromSql -> courseid, fromSql -> title,
fromSql -> name, fromSql -> version,
fromSql -> cdate, fromSql -> fid ) = do
let courseXML = show (fid :: Int)
xml <- B.readFile courseXML
let Right doc = parseXML courseXML xml
let passing = read $ T.unpack $ fromJust
$ lookup (T.pack "PassingScore")
$ elementAttrs $ head $ docContent doc
return (Course courseid title name version cdate passing)
listToTuple :: [SqlValue] -> (SqlValue, SqlValue, SqlValue, SqlValue, SqlValue, SqlValue)
listToTuple [a,b,c,d,e,f] = (a,b,c,d,e,f)
listToTuple xs = error "Wrong number of values"
getCourses :: Connection -> IO [Course]
getCourses conn = do
let query = "{Actual query deleted to protect the innocent.}"
res <- quickQuery conn query []
mapM toResult (listToTuple res)
但是,这将无法编译,并出现以下错误 . 这次我错过了什么简单的事情?
src\CDCQuarterly.hs:122:20:
Couldn't match type `(,,,,,)
SqlValue SqlValue SqlValue SqlValue SqlValue'
with `[]'
Expected type: [(SqlValue,
SqlValue,
SqlValue,
SqlValue,
SqlValue,
SqlValue)]
Actual type: (SqlValue,
SqlValue,
SqlValue,
SqlValue,
SqlValue,
SqlValue)
In the second argument of `mapM', namely `(listToTuple res)'
In a stmt of a 'do' block: mapM toResult (listToTuple res)
src\CDCQuarterly.hs:122:32:
Couldn't match type `[SqlValue]' with `SqlValue'
Expected type: [SqlValue]
Actual type: [[SqlValue]]
In the first argument of `listToTuple', namely `res'
In the second argument of `mapM', namely `(listToTuple res)'
2 回答
我可以想出两种避免警告的方法 . 第一种也是最简单的方法是为
toResult
添加另一个方程式,该方程式捕获所有其他大小的列表并提供信息性错误:但是如果你的函数只能在长度为6的列表上运行,我怀疑列表是否真的是这里使用的最佳数据结构 .
理想情况下,您的函数类型签名应该让读者很清楚地知道如何使用该函数 . 如果您的函数只能接受长度为6的列表,那么它的类型签名无法通信 . 我建议选择不具有可变长度的不同数据结构,例如6元组(可能与
type
或newtype
结合使用)或自定义data
类型 . 这完全消除了基于长度的模式匹配问题,并使您的功能更容易理解"outside world."在不了解更多上下文的情况下,我无法确切地知道在您的情况下哪种常量大小的数据结构最合适,但这里有一个简单的例子,希望能够说明我所描述的方法的好处:
不幸的是,如果你无法从这种情况中完全删除
List
类型,那么所有这一切都会将问题转移到其他地方,因为你最终需要第二个函数来从List转换为元组 . These types of functions are invariably ugly and a pain to work with.它_10043261_重新100%,
quickQuery
将返回一个正好六个元素的列表(你真的,完全,在数学上确定这个吗?),你仍然必须考虑到这种情况的逻辑可能性 . 这意味着您必须在运行时提供一种处理此案例的方法 .那么,当传递多于或少于六个值时,您想要做什么?如何在您的程序中实现错误处理?这是一个使用
error
的潜在天真的例子:虽然没有比我的第一个建议好多少,但这至少具有将长度处理逻辑与结果生成逻辑分开的优点 .
我很欣赏从这次经历中得到的投入和学习 . 但是,我从一个发出编译时警告的工作函数发展而来,我很乐意忽略一个编译错误,阻止构建输出可执行文件 .
我已经从这个主题中加入了一些建议,但基本上已经回到了我关于非详尽模式匹配的原始警告 . 最终,似乎在执行数据库查询之间存在不可调和的不一致性,该数据库查询总是返回相同数量的元素的列表,然后将该列表用作固定大小的集合,或者将该列表转换为固定大小的集合 .
每种语言都有它的怪癖 . 也许这是Haskell的一个 .
感谢所有的输入和指导 .
戴夫史密斯