【问题标题】:Make "A || B && C" point-free in Haskell在 Haskell 中使“A || B && C”无点
【发布时间】:2020-08-27 00:05:31
【问题描述】:

我在 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 个问题:

  • 您对我如何实现这一点有任何建议吗?
  • 在我的第一个解决方案中,是什么阻止了divisibleBy 无点? (如果我删除参数,类型检查器会抱怨)
  • 正如我之前提到的,我尝试了类似liftA3 (\x y z -> x || (y && z)) (divisibleBy 400) (divisibleBy 4) (indivisibleBy 100) 的方法,但测试挂起。为什么会这样?我不明白 liftA3 的工作原理。

非常感谢您的帮助。

【问题讨论】:

  • 你不应该总是使用它,但是... pointfree.io
  • 所以应该是:isLeapYear = ap ((||) . divisibleBy 400) (ap ((&&) . divisibleBy 4) (not . divisibleBy 100))。可读性差,但略短。
  • 我明白了,谢谢!我想知道是否有一种方法可以在不牺牲太多可读性的情况下实现这一点,也许是通过一些我还不知道的功能。 pointfree.io 版本看起来有点过头了。
  • flip mod m y 似乎是多余的。这个更好:mod y m
  • 让表达变得无意义并不是一件纯粹的好事。

标签: haskell applicative pointfree


【解决方案1】:

在我的第一个解决方案中,是什么阻止了 divisibleBy 无点? (如果我删除参数,类型检查器会抱怨)

您可能认为这些是等价的(为简单起见,我将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。我不认为写这样的东西是一个很好的主意,但它可能会回答你的问题。


测试挂起。为什么会这样?

我不知道。您可能需要在此处提供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])

【讨论】:

  • 嗯,也许有一个字符滑过什么的,因为我再次检查并成功了。谢谢@Lynn!
猜你喜欢
  • 1970-01-01
  • 2020-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多