在 Haskell 中使 "A || B && C" 无积分

Make "A || B && C" point-free in Haskell

我正在 Haskell 处理一个简单的闰年练习,我想让我的解决方案无意义。从这里开始:

isLeapYear :: Integer -> Bool
isLeapYear year = divisibleBy 400 year || divisibleBy 4 year && not (divisibleBy 100 year)
  where
    divisibleBy m y = (== 0) $ flip mod m y

我尝试使用 liftA3,在 this 之后执行 (x || (y && z)) 的函数,但测试没有完成,我不知道为什么。

那么,那么,我有3个问题:

非常感谢您的帮助。

In my first solution, what's preventing divisibleBy to be point-free? (Typechecker complains if I remove the arguments)

您可能认为它们是等价的(为了简单起见,我将 flipmod 写成一个函数):

divisibleBy  m y = (== 0) $ flipmod m y
divisibleBy'     = (== 0) . flipmod

但实际上,divisibleBy' 现在是一个(无效的)函数,它接受一个参数 x,然后将 flipmod x 与零进行比较:

    ((==0) . flipmod) 5
→   (==0) (flipmod 5)
→   flipmod 5 == 0

比较一个函数(flipmod 5)和一个数字肯定不行。

你需要写一些更复杂的东西,即:

divisibleBy = ((== 0) .) . flipmod

所以现在,正确地:

    divisibleBy 5 6
→   (((== 0) .) (flipmod 5)) 6
→   ((== 0) . flipmod 5) 6
→   (== 0) (flipmod 5 6)
→   flipmod 5 6 == 0

这个结构 (f.).g 也可以写成 ((.).(.)) f g,那个运算符有时被称为 dot。我不认为写这样的东西是个好主意,但它可能会回答你的问题。


The tests hang. Why does that happen?

我不知道。您可能需要在此处提供一个 mcve,因为作为一个完整的程序,这对我来说效果很好:

import Control.Applicative

isLeapYear :: Integer -> Bool
isLeapYear = liftA3 (\x y z -> x || (y && z))
                    (divisibleBy 400)
                    (divisibleBy 4)
                    (not . divisibleBy 100)
  where
    divisibleBy m y = (== 0) $ flip mod m y

main = print (filter isLeapYear [1850..1950])