Comment réécrire la fonction suivante dans un style sans point, en supprimant complètement le paramètre x de la définition (les deux autres peuvent rester):

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

Ce n'est pas une mission, juste une question. Je ne sais pas comment procéder. Je peux le transformer en fonction lambda

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

Mais ce n'est pas sans point, car x est toujours là. Veuillez aider.

-12
user2304996 20 nov. 2018 à 14:09

4 réponses

Meilleure réponse

Une autre solution (nécessite l'importation de Control.Applicative):

between min max = liftA2 (&&) (min <) (max >)
5
mschmidt 20 nov. 2018 à 20:58

En utilisant Control.Arrow, nous pouvons atteindre ce code presque obscurci:

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

Cela repose sur le >>> prédéfini pour la composition de gauche à droite, f &&& g = \x -> (f x, g x) et non curry.


pointfree.io suggère également le code illisible suivant:

between = (. flip (<)) . ap . ((&&) .) . (<)
4
chi 20 nov. 2018 à 13:56

Par transformation de sections d'opérateur,

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

Maintenant ceci correspond à un modèle pour le S -combinator, S f g x = (f x) (g x). Il existe de nombreuses façons de l'encoder dans Haskell, mais les deux principales sont via Applicative et via Flèches:

    _S f g x = (f x) (g x)
             = (f <*> g) x
             = uncurry id . (f &&& g) $ x

Le second nous donne

between a z = uncurry (&&) . ((a <) &&& (< z))

Et le premier, encore plus approprié

between a z = (&&) <$> (a <) <*> (< z)
            = liftA2 (&&) (a <) (< z)
            = (a <) <^(&&)^> (< z)     -- nice and visual

(<^) = flip (<$>) 
(^>) = (<*>)

Mais on pourrait aussi jouer avec d'autres combinateurs, avec des résultats beaucoup moins satisfaisants cependant,

    _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 

Ou

             = (f x . g) x
             = (. g) (f x) x
             = ((. g) =<< f) x

Ce qui illustre bien les dangers de l'inutilité dans la poursuite du sans point.

Il y a une autre possibilité qui a du sens (syntaxiquement), qui est

    _S f g x = (f x) (g x)
        --   = foldr1 ($) . sequence [f,g] $ x  -- not valid Haskell

        -- sequence [f,g] x = [f x,g x]

Ce n'est pas un Haskell valide en général en raison des problèmes de frappe, mais dans notre cas spécifique, cela donne lieu à une autre définition valide, qui semble également suivre bien la logique interne de celui-ci,

between a z = -- foldr1 ($) . sequence [(&&).(a <), (< z)] -- not OK
            = foldr1 (&&) . sequence [(a <), (< z)]        -- OK
            = and . sequence [(a <), (> z)]

Car (a <) et (> z) ont le même type.

2
Will Ness 23 nov. 2018 à 10:16

Cela peut être fait en utilisant l'applicatif 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)
8
Kris 20 nov. 2018 à 11:27