如何以无点样式重写以下函数,从定义中完全删除参数x
(其他两个可能保留):
between min max x = (min < x) && (x < max)
这不是一项作业,只是一个问题。我不知道该如何进行。我可以将其转换为lambda函数
between min max = \x -> (min < x) && (x < max)
但这不是没有意义的,因为x
仍然存在。请帮忙。
答案 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)
具有相同的类型。