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

Haskell Function Composition - (a -> b) -> (a -> c) -> (b -> c -> d) -> (a -> d)

我想了解如何在无积分的情况下完成以下操作:

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

我知道为了 readability/sanity 这样写更好,但我想了解更多有关如何组合函数的信息。我一直在摸索如何才能做到这一点。 整个(扩展?)类型签名是

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

我要获取的组合的类型签名是

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

我以 bastard-lambda 形式写了以下笔记。如果有一种方法可以稍微简化 lambda 演算的问题,如果也能解释一下就太好了:

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

上面.是应用,@是捕获(所以f3是(Bool -> Bool -> Bool)的别称)。 非常感谢。

编辑:我知道这不是最佳或可重用的代码,而且我知道将它变成无点会使它在可读性等方面变得更糟。为了澄清,我问的是如何将它变成点-free 因为我想了解更多关于 haskell 和 composition.

编辑 2:A really good SO answer on point-free

您可以利用函数是可应用的这一事实。 并这样写 withinBounds

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

或者这样:

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

您可以阅读 Applicatives here and here

有一个 class 基本上专用于无点组合 具有多个“通道”:Arrow。如果您决心让一切都变得毫无意义,那么这就是 IMO 的必经之路。丑陋的一点是你经常需要 uncurry 函数:

import Control.Arrow

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

通过图表可以更好地理解其工作原理:

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

Arrow 适用于通用设置;不仅适用于 Hask-函数,而且适用于任何合适的类别。但它足以将其应用于函数。

注意 x<=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] 然后我要求这两个同时 >=0。

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

希望这对您有所帮助。

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

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

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

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

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

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