嗨,我有一个任务要编写,该函数接受Int -> Int
中的函数列表和单个Int
中的函数,并检查应用于该Int
的函数是否给出结果为大于5。
这是我的解决方案:
foo :: [Int -> Int] -> Int -> Bool
foo ls = any (>5) . f ls
where f ls v = map ($ v) ls
我想知道有一种方法可以用eta减少最后一个参数(现在是eta减少但不是单行)用单行(不使用where或let)编写。我尝试过这样的事情:
foo ls = any (>5) . flip map ls
但是现在的问题是调用函数看起来像这样
foo [(+3), (*4), (+1)] ($2)
最后一个参数我想避免写$。我尝试过这样的事情(和类似的事情):
foo ls = any (>5) . flip map ls ($)
但是我总是会遇到某种错误。请注意,我不能更改类型签名,也不能更改翻页。
答案 0 :(得分:3)
有办法吗?当然。可读吗?不能。Haskell的设计使您摆脱一些常见的错误,例如不必要的可变性或(必要的)可变状态的隐藏使用。但是,遵循其他错误的方法使之激动人心,例如以有害于可读性和可维护性的方式使代码无指向性。
关于无点定义的问题是,转换为无点定义是一个完全机械的过程(只要起始定义中不涉及模式匹配)。有一些工具可以自动执行此操作。
首先编写完全经过eta扩展的定义:
foo ls x = any (>5) (map ($ x) ls)
然后将其放入您喜欢的工具中进行转换。 http://pointfree.io/是将执行此操作的在线服务。
它吐出了完全不可读的内容:
foo = (any (> 5) .) . flip (map . flip id)
请勿使用。这不值得。
但是也许您只想缩小一个论点的范围,这太多了吗?好吧,您可以通过作弊一点,并假装第一个参数是作用域中的值而不是参数,然后在以下内容中添加以下定义来做到这一点:
foo x = any (>5) (map ($ x) ls)
它返回foo = any (> 5) . flip map ls . flip id
,然后将其插入以下参数:
foo ls = any (> 5) . flip map ls . flip id
这要好一些,这要归功于(.)
运算符的缺少部分。但是它仍然包含flip id
,这很容易混淆。
不要这样做。保持克制。编写易于阅读和修改的代码。
答案 1 :(得分:1)
从一个完全未简化的定义开始:
foo ls v = any (>5) (map (\f -> f v) ls)
我们可以使用lambdabot拥有完全减少eta的解决方案:
foo = (any (> 5) .) . flip (map . flip id)
但是,这看起来很糟糕,不建议这样做。
答案 2 :(得分:1)
实际上,您在问题中的最后一次审判
foo ls = any (>5) . flip map ls ($)
已经非常接近解决方案。
唯一的问题是,考虑($)
的定义:
($)::(a -> b) -> a -> b
($)
的第一个参数是函数(a->b)
,但是在您的情况下,它需要一个值a
,因此flip ($)
交换了参数的顺序($)
并重新显示为:
foo ls = any (>5) . flip map ls . flip ($)
是您想要的功能。
答案 3 :(得分:0)
由于手头有一个应用列表,您可以简单地将应用运算符<*>
用作[(+3), (*4), (+1)] <*> [2]
来应用它,以获得诸如[5,8,3]
之类的结果列表。现在方便使用any :: Foldable t => (a -> Bool) -> t a -> Bool
函数。所以在一起
checker x = any (>5) $ [(+3), (*4), (+1)] <*> [x]
应该做的工作。如果您需要的是无点版本,那么它将是
checker = any (>5) . ([(+3), (*4), (+1)] <*>) . pure