如何以无点样式编写此函数?

时间:2018-11-20 11:09:46

标签: haskell functional-programming pointfree tacit-programming

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

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

这不是一项作业,只是一个问题。我不知道该如何进行。我可以将其转换为lambda函数

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

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

4 个答案:

答案 0 :(得分:8)

可以使用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)

答案 1 :(得分:5)

另一种解决方案(需要导入Control.Applicative

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

答案 2 :(得分:4)

使用Control.Arrow,我们可以找到几乎混淆的代码:

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

这依赖于预定义的>>>来实现从左到右的构图f &&& g = \x -> (f x, g x),并且不费吹灰之力。


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

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

答案 3 :(得分:2)

通过运算符节转换,

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

现在 this 适合 S 组合器S 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 (<$>) 
(^>) = (<*>)

但是我们也可以摆弄其他组合器,尽管效果不如人意

    _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)具有相同的类型。