如何以无点风格编写此功能?

How to write this function in point-free style?

如何以无点样式重写以下函数,从定义中完全删除参数 x(其他两个可能保留):

between min max x = (min < x) && (x < max)

这不是作业,只是一道题。我不知道如何进行。我可以把它变成一个 lambda 函数

between min max = \x -> (min < x) && (x < max)

但这并不是没有意义的,因为 x 仍然存在。请帮忙。

可以使用 Reader 应用程序完成:

between min max = \x. (min < x) && (x < max)
              { Convert infix comparisons to sections }
                = \x. ((min <) x) && ((< max) x)
              { Move infix (&&) to applicative style }
                = \x. (&&) ((min <) x) ((< max) x)
              { Lift to applicative style using the applicative instance of `(->) a` }
                = \x. (pure (&&) <*> (min <) <*> (< max)) x
              { Eta-reduce }
                = pure (&&) <*> (min <) <*> (< max)
              { Optionally simplify for idiomatic style }
                = (&&) <$> (min <) <*> (< max)

使用Control.Arrow我们可以得到这个几乎混淆的代码:

(min <) &&& (< max) >>> uncurry (&&)

这依赖于从左到右组合的预定义 >>>f &&& g = \x -> (f x, g x) 和非柯里化。


pointfree.io 还建议以下不可读代码:

between = (. flip (<)) . ap . ((&&) .) . (<)

另一个解决方案(需要导入Control.Applicative):

between min max = liftA2 (&&) (min <) (max >)

通过operator sections改造,

between min max x = (min < x) && (x < max)
                  = ((&&) . (min <)) x ((< max) x)

现在 this 适合 S-组合器的模式,<b>S</b> f g x = (f x) (g x)。在 Haskell 中有多种编码方式,但主要的两种是通过 Applicative 和 Arrows:

    _S f g x = (f x) (g x)
             = (f <*> g) x
             = uncurry id . (f &&& g) $ x

第二个给了我们

between a z = uncurry (&&) . ((a <) &&& (< z))

第一个更合适

between a z = (&&) <$> (a <) <*> (< z)
            = liftA2 (&&) (a <) (< z)
            = (a <) <^(&&)^> (< z)     -- nice and visual

(<^) = flip (<$>) 
(^>) = (<*>)

但我们也可以 fiddle 使用其他组合器,但结果不太令人满意,

    _S f g x = f x (g x)
             = flip f (g x) x
             = (flip f . g) x x
             = join (flip f <$> g) x
             = (flip f =<< g) x 

             = (f x . g) x
             = (. g) (f x) x
             = ((. g) =<< f) x

这很好地说明了在追求无意义的过程中毫无意义的危险。

还有一种可能(在句法上)有意义,那就是

    _S f g x = (f x) (g x)
        --   = foldr1 ($) . sequence [f,g] $ x  -- not valid Haskell

        -- sequence [f,g] x = [f x,g x]

由于打字问题,这通常不是一个有效的 Haskell,但在我们的特定情况下,它确实产生了一个更有效的定义,它似乎也很好地遵循了它的内在逻辑,

between a z = -- foldr1 ($) . sequence [(&&).(a <), (< z)] -- not OK
            = foldr1 (&&) . sequence [(a <), (< z)]        -- OK
            = and . sequence [(a <), (> z)]

因为(a <)(> z)的类型相同