如何以无点风格重写以下函数,将参数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.Applicative
(:
between min max = liftA2 (&&) (min <) (max >)
使用Control.Arrow
,我们可以获得几乎混淆的代码:
(min <) &&& (< max) >>> uncurry (&&)
这依赖于用于从左到右构图、f &&& g = x -> (f x, g x)
和取消卷曲的预定义>>>
。
pointfree.io还建议使用以下不可读代码:
between = (. flip (<)) . ap . ((&&) .) . (<)
按操作员段转换,
between min max x = (min < x) && (x < max)
= ((&&) . (min <)) x ((< max) x)
现在这个适合S-组合子Sf 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)]
因为CCD_ 9和CCD_。