简体   繁体   English

使“A || B && C” 在 Haskell 中无点

[英]Make “A || B && C” point-free in Haskell

I'm tackling a simple leap year exercise in Haskell, and I'd like to make my solution point-free.我正在 Haskell 中处理一个简单的闰年练习,我想让我的解决方案无点。 Starting from this:从此开始:

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

I tried using liftA3 , with a function doing (x || (y && z)) following this , but the tests do not finish and I don't know why.我试着用liftA3 ,具有功能做(x || (y && z))下面这个,但测试没有完成,我不知道为什么。

So, then, I have 3 questions:那么,我有3个问题:

  • Do you have any pointers as to how could I achieve this?您对我如何实现这一目标有任何指示吗?
  • In my first solution, what's preventing divisibleBy to be point-free?在我的第一个解决方案中,是什么阻止了divisibleBy成为无点? (Typechecker complains if I remove the arguments) (如果我删除参数,类型检查器会抱怨)
  • As I mentioned before, I tried something like liftA3 (\\xyz -> x || (y && z)) (divisibleBy 400) (divisibleBy 4) (indivisibleBy 100) , but the tests hang.正如我之前提到的,我尝试了类似liftA3 (\\xyz -> x || (y && z)) (divisibleBy 400) (divisibleBy 4) (indivisibleBy 100) ,但测试挂起。 Why does that happen?为什么会这样? I'm not getting how liftA3 works.我不liftA3是如何工作的。

Thanks a lot for your help.非常感谢你的帮助。

In my first solution, what's preventing divisibleBy to be point-free?在我的第一个解决方案中,是什么阻止了 divisibleBy 成为无点? (Typechecker complains if I remove the arguments) (如果我删除参数,类型检查器会抱怨)

You might think that these are equivalent (I am writing flipmod as one function for simplicity's sake):您可能认为这些是等效的(为了简单起见,我将flipmod作为一个函数编写):

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

But in actuality, divisibleBy' is now an (invalid) function that takes an argument x and then compares flipmod x to zero:但实际上, divisibleBy'现在是一个(无效的)函数,它接受一个参数x然后将flipmod x与零进行比较:

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

Comparing a function ( flipmod 5 ) and a number is certainly no good.比较一个函数( flipmod 5 )和一个数字肯定不好。

You'd need to write something more sophisticated, namely:你需要写一些更复杂的东西,即:

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

So that now, properly:所以现在,正确地:

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

This construction (f.).g can also be written as ((.).(.)) fg , and that operator is sometimes called dot .这种构造(f.).g也可以写成((.).(.)) fg ,并且该运算符有时称为dot I don't think writing things like this is a very good idea, but it might answer your question.我不认为写这样的东西是一个很好的主意,但它可能会回答你的问题。


The tests hang.测试挂起。 Why does that happen?为什么会这样?

I don't know.我不知道。 You'll probably need to provide an mcve here, because this works fine for me as a full program:你可能需要在这里提供一个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])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM