惯用的Haskell是否尝试消除对fst和snd的对操作,因为它确实是head,init,tail等?

时间:2011-11-22 00:27:32

标签: haskell

这是一个不适合我的功能,我想我需要摆脱fst。

flagHolidays :: [(C.Day,Availability)] -> Handler [(C.Day,Availability)]
flagHolidays dayPairs = do
   let days = map fst dayPairs
       yepNope = Prelude.map isHoliday days
       availability = Prelude.map flagAvailability yepNope
   return $ Prelude.zip days availability

我能想到的唯一方法是按照(x,y):(xs,ys)的方式进行非常难看的模式匹配。删除fst是否有意义?如果是这样,那么对这个对列表进行模式匹配的最佳方法是什么?

4 个答案:

答案 0 :(得分:22)

在惯用的haskell代码中使用headtailinit的原因是它们不是全部函数 - 某些输入会导致错误发生。将空列表传递给任何这些函数会导致空列表异常。

fstsnd没有此问题,因为没有输入可以传递给那些会导致异常的函数。所以没有理由试图避免这些功能。

您的功能可以更好地编写(其他评论提供了有关此内容的详细信息),但由于使用了fstsnd而无法使用。

答案 1 :(得分:14)

使功能纯净,

flagHolidays = map (second $ flagAvailability . isHoliday)

要回答实际问题,除非作为参数传递fst和snd很少使用。

<编辑]嗯,我写得有点草率。这是不对的。你传递了一对配对,从不使用该对的第二个组成部分。已更正,但同样(现在使用fst):

flagHolidays = map ((id &&& flagAvailability . isHoliday) . fst)

答案 2 :(得分:4)

dayPairs是对的列表,因此days应该是map fst dayPairs。这是使用fst惯用的一个地方,作为高阶函数的参数。除此之外,当作者忘记懒惰模式时,它主要用于推迟对的评估。

答案 3 :(得分:4)

我认为你是正确的,因为你这样做的方式似乎并不特别惯用。

除了错误之外,还有很多更好的方法。作为几个示例(可能不是最佳的,但仍然更具可读性),您可以在地图中使用lambda:

return $ map (\(d,a) -> (d, flagAvailability $ isHoliday a)) dayPairs

或者你可以使用列表理解:

return [(day, flagAvailability $ isHoliday a) | (day,a) <- dayPairs]

可能有一些聪明的方法可以使中心映射完全没有点,但即便如此也可能不值得 - 上述任何一个表达式都可以使操作相当清晰。但是,我认为消除变量dayPairs可能是一种改进:

flagHolidays = return . map (\(d,a) -> (d, flagAvailability $ isHoliday a))