如何以无点风格编写此功能?
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)
的类型相同
如何以无点样式重写以下函数,从定义中完全删除参数 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)
的类型相同