Haskell函数组合 - (a - > b) - > (a - > c) - > (b - > c - > d) - > (a - > d)

时间:2016-07-06 07:02:21

标签: haskell lambda function-composition pointfree

我想了解如何以无点方式完成以下工作:

withinBounds :: [Int] -> Bool
withinBounds xs = (all (>= 0) xs) && (all (<= 8) xs)

我理解为了可读性/理智而以这种方式编写它是优越的,但我想了解更多关于如何编写函数的信息。我一直在试着如何做到这一点。 整个(扩展?)类型签名是

[Int] -> ([Int] -> Bool) -> ([Int] -> Bool) -> (Bool -> Bool -> Bool) -> Bool

我试图去的作品的类型签名是

(a -> b) -> (a -> c) -> (b -> c -> d) -> (a -> d)

我用以混蛋 - lambda形式的笔记写下了以下内容。如果有一种方法可以在某种程度上简化lambda演算的问题,那么如果可以解释它也会很好:

\L@[] ->  \f1@([] -> Bool) -> \f2@([] -> Bool) -> \f3@(Bool -> Bool -> Bool) -> f3.(f1.L).(f2.L) 

在上面,.是应用程序,@正在捕获(因此f3是(Bool - &gt; Bool - &gt; Bool)的另一个名称)。 非常感谢。

编辑:我知道这不是最优或可重复使用的代码,而且我知道将其转换为无点可使其在可读性等方面更糟糕。为了澄清,我问我怎么能把它变成无点的因为我想了解更多关于haskell和组合的信息。

Edit2:A really good SO answer on point-free

4 个答案:

答案 0 :(得分:9)

您可以使用函数是Applicative的事实。 并以这种方式写withinBounds

withinBounds = pure (&&) <*> all (>= 0) <*> all (<= 8)

或者这样:

withinBounds = (&&) <$> all (>= 0) <*> all (<= 8)

您可以阅读有关申请人herehere

的信息

答案 1 :(得分:9)

有一个类基本上专门用于具有多个“通道”的无点组合Arrow。如果你决心让所有东西都没有点,那么这就是IMO的最佳选择。关于这一点的丑陋之处在于你经常需要解决这些问题:

import Control.Arrow

withinBounds = all (>=0) &&& all (<=8) >>> uncurry (&&)

如何通过图表最好地理解其工作原理:

      all (>=0) ────
       ╱                ╲
──── &&&            >>>  uncurry (&&) ───
       ╲                ╱
      all (<=8) ──── 

Arrow在广义环境中工作;不仅适用于 Hask 功能,还适用于任何合适的类别。但它足以将其应用于函数。

答案 2 :(得分:2)

围绕整个问题做一个结束,我想我可能会这样写:

import Data.Ix
withinBounds = all (inRange (0, 8))

当然,这有点过分,从那时起,人们自然会问如何以无点的方式实现inRange。如果你绝对不能使用inRange,那么我会以这种方式实现它:

withinBounds = all (liftA2 (&&) (>=0) (<=8))

这使用reader applicative为两个函数提供单个参数。 liftA2是您请求的组合函数,但参数翻转:

requested :: (a -> b) -> (a -> c) -> (b -> c -> d) -> (a -> d)
liftA2    :: (b -> c -> d) -> (a -> b) -> (a -> c) -> (a -> d)

答案 3 :(得分:-2)

注意x&lt; = 8当且仅当8-x> = 0时,所以,只使用前奏,我们可以写

withinBounds :: [Int] -> Bool
withinBounds = all $ (all (>=0)) . (zipWith (+) [0,8]) . (zipWith (*) [1,-1]) . (replicate 2)

基本上我只是将x映射到[x,x]然后映射到[x,8-x],然后我要求这两个同时为&gt; = 0。

当然,正如评论中所指出的,您还可以制作a,b参数,以便以后重复使用。

希望这有帮助。