2017-02-13 45 views
2

在通过项目欧拉的第一次几个练习工作时,我惊讶于haskell处理失败的方式让绑定内部符号。
我打算做等价的:模式守卫和让

sundays = length $ do 
    year <- [1901..2000] 
    month <- [1..12] 
    (_, _, 7) <- return . toWeekDate $ fromGregorian year month 1 
    return() 

也就是说,查询当月的一定时间范围内的第一天是如何往往是星期天。这工作,并与一个案件绑定这样做也是如此。结合这似乎是它让我们应该做的总是通过,但同样的事情:

sundays = length $ do 
    year <- [1901..2000] 
    month <- [1..12] 
    let (_, _, 7) = toWeekDate $ fromGregorian year month 1 
    return() 

是什么原因导致这种行为?

回答

6

您的第二个示例中的let绑定永远不会被评估,因为它的值从不使用。这是一样的文字:

sundays = length $ do 
    year <- [1901..2000] 
    month <- [1..12] 
    return() 

如果你想扩展第二个例子,我建议使用guardControl.Monad,这将有效地过滤结果不出所料:

sundays2 = length $ do 
    year <- [1901..2000] 
    month <- [1..12] 
    let (_, _, day) = toWeekDate $ fromGregorian year month 1 
    guard $ day == 7 
    return() 

guard是在列表理解中幕后使用的。你上面的代码可以写在列表理解的形式是这样的:

sundays3 = length $ [() | year <- [1901..2000] 
         , month <- [1..12] 
         , let (_, _, day) = toWeekDate $ fromGregorian year month 1 
         , day == 7 ] 
+1

哦,默认分支'<-' desugars结合成一个case语句与mfail,对列表一样的后卫。这也清除了一些关于如何让绑定符号表示解释的错误观念,谢谢! – Taren