-13

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

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

这不是一个任务,只是一个问题。我不知道该怎么做。我可以把它变成一个 lambda 函数

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

但这不是无点的,因为x仍然存在。请帮忙。

4

4 回答 4

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)
于 2018-11-20T11:27:21.103 回答
5

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

between min max = liftA2 (&&) (min <) (max >)
于 2018-11-20T18:34:49.007 回答
4

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

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

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


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

between = (. flip (<)) . ap . ((&&) .) . (<)
于 2018-11-20T13:42:12.140 回答
2

通过算子部分变换,

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

现在符合S -combinator 的模式,S f g x = (f x) (g x). 在 Haskell 中有很多编码方式,但主要的两种是通过 Applicative 和通过箭头:

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

于 2018-11-23T10:16:23.233 回答