Как написать эту функцию в бессмысленном стиле? - PullRequest
0 голосов
/ 20 ноября 2018

Как переписать следующую функцию в стиле без точек, полностью удалив параметр x из определения (два других могут остаться):

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

Это не назначение, а простовопрос.Я не знаю, как поступить.Я могу превратить его в лямбда-функцию

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

, но это не бессмысленно, так как x все еще там.Пожалуйста, помогите.

Ответы [ 4 ]

0 голосов
/ 23 ноября 2018

При преобразовании операторных секций,

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

Теперь Этот соответствует шаблону для 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 (<$>) 
(^>) = (<*>)

Но мы могли бы также поиграть с другими комбинаторами, но с гораздо менее удовлетворительными результатами:

    _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) имеют одинаковый тип.

0 голосов
/ 20 ноября 2018

Используя Control.Arrow, мы можем получить этот почти запутанный код:

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

Это зависит от предопределенного >>> для композиции слева направо, f &&& g = \x -> (f x, g x) и неиспользования.


pointfree.io также предлагает следующий нечитаемый код:

between = (. flip (<)) . ap . ((&&) .) . (<)
0 голосов
/ 20 ноября 2018

Другое решение (требуется импорт Control.Applicative):

between min max = liftA2 (&&) (min <) (max >)
0 голосов
/ 20 ноября 2018

Это можно сделать с помощью аппликатива 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)
...