Ajout de tuple en pointfree

16

Quel est le moyen le plus court pour exprimer la fonction

f(a,b)(c,d)=(a+c,b+d)

en notation sans point?

pointfree.io nous donne

uncurry (flip flip snd . (ap .) . flip flip fst . ((.) .) . (. (+)) . flip . (((.) . (,)) .) . (+))

qui avec un peu de travail peut être raccourci

uncurry$(`flip`snd).((<*>).).(`flip`fst).((.).).(.(+)).flip.(((.).(,)).).(+)

pour 76 octets. Mais cela semble encore très long et complexe pour une tâche aussi simple. Existe-t-il un moyen d'exprimer l'addition par paire comme une fonction sans point plus courte?

Pour être clair par ce que j'entends par point-free, une déclaration point-free d'une fonction implique de prendre des fonctions et des opérateurs existants et de les appliquer les uns aux autres de telle sorte que la fonction souhaitée soit créée. Entre parenthèses, et les apostrophes inverses des valeurs littérales ( [], 0, [1..3], etc.) sont autorisés , mais des mots clés comme whereet letne sont pas. Ça signifie:

  • Vous ne pouvez attribuer aucune variable / fonction

  • Vous ne pouvez pas utiliser de lambdas

  • Vous ne pouvez pas importer

Voici la même question quand c'était un CMC

Post Rock Garf Hunter
la source
9
Je n'ai jamais compris pourquoi on l'appelle « sans point » alors qu'il est en fait plein de points. : P
M. Xcoder
5
C'est dommage que nous ne soyons pas autorisés à importer le meilleur package Haskell , sinon la solution serait juste (+)***(+).
Silvio Mayolo
2
Une idée: (+)<$>([1],2)<*>([3],4)donne ([1,3],6).
2017
2
J'ai passé un certain temps à essayer de créer une bonne solution en utilisant la pointe de xnor ... mais je me suis retrouvé avec ces ordures . Je ne sais même pas pourquoi j'essaye parfois ...
totalement humain

Réponses:

11

44 octets

J'ai obtenu ça de \x y -> (fst x + fst y, snd x + snd y)

(<*>).((,).).(.fst).(+).fst<*>(.snd).(+).snd

Essayez-le en ligne!

H.PWiz
la source
8

44 octets

-8 octets grâce à Ørjan Johansen. -3 octets grâce à Bruce Forte.

(.).flip(.)<*>(zipWith(+).)$mapM id[fst,snd]

Essayez-le en ligne!

Se traduit par:

f t1 t2 = zipWith (+) (mapM id [fst, snd] $ t1) (mapM id [fst, snd] $ t2)

67 octets

-8 octets grâce à Ørjan Johansen. -1 octet merci à Bruce Forte.

Si une sortie de tuple est requise:

(((,).head<*>last).).((.).flip(.)<*>(zipWith(+).)$mapM id[fst,snd])

Essayez-le en ligne!

Ouais, le fait manuellement ne produit pas de fruits mûrs. Mais je suis satisfait de la [a] → (a, a)conversion.

listToPair  [a]  (a, a)
listToPair = (,) . head <*> last
-- listToPair [a, b] = (a, b)

Maintenant, s'il y avait une fonction courte avec m (a → b) → a → m b.

totalement humain
la source
3
Je déteste vous le casser, mais mapM id[fst,snd]c'est plus court.
Ørjan Johansen
Malheureusement, mapM idc'est la version golfée de la fonction que vous recherchez probablement sequence.
Ørjan Johansen
Ouais c'est vrai. Je regarde juste (<*>)la signature de m (a → b) → m a → m b. Si proche ...
totalement humain
1
Il y a aussi Control.Lens.??, qui peut avoir été proposé pour inclusion dans la base à un moment donné.
Ørjan Johansen
Je veux extraire le répété (.mapM id[fst,snd])comme let r=(.mapM id[fst,snd]) in r(r.zipWith(+)), mais je n'ai pas réussi à faire en sorte que le vérificateur de type accepte une version sans point.
2017
4

54 octets

Je doute sincèrement que nous allons battre la solution de 44 octets de @ H.PWiz, mais personne n'utilisait le fait qui (,)implémente la classe de type Functor, alors voici une autre intéressante qui n'est pas trop mauvaise:

((<*>snd).((,).).(.fst).(+).fst<*>).flip(fmap.(+).snd)

Essayez-le en ligne!

Explication

L'implémentation de la classe de type Functorpour 2 -Tuples est très similaire à celle de Either(à partir de la base-4.10.1.0 ):

instance Functor ((,) a) where
    fmap f (x,y) = (x, f y)

instance Functor (Either a) where
    fmap _ (Left x) = Left x
    fmap f (Right y) = Right (f y)

Ce que cela signifie pour ce défi, c'est que la fonction suivante ajoute les seconds éléments tout en conservant le premier élément du deuxième argument:

λ f = fmap.(+).snd :: Num a => (a, a) -> (a, a) -> (a, a)
λ f (1,-2) (3,-4)
(3,-6)

Donc, si seulement nous obtenions une petite aide, helpPlz = \a b -> (fst a+fst b,snd b)nous pourrions le faire (helpPlz<*>).flip(fmap.(+).snd)et le serions. Heureusement, nous avons l'outil pointfreequi nous donne:

helpPlz = (`ap` snd) . ((,) .) . (. fst) . (+) . fst

Donc, en rebranchant simplement cette fonction, nous arrivons à la solution ci-dessus (notez celle (<*>) = apqui est dans la base ).

ბიმო
la source
4

60 octets

Je ne vois aucun uncurryamour ici, alors je me suis dit que j'allais intervenir et réparer ça.

uncurry$(uncurry.).flip(.)(flip(.).(+)).(flip(.).((,).).(+))

J'ai pensé, avec tous les fstet snd, que déballer les arguments avec uncurrypourrait donner des résultats. De toute évidence, ce n'était pas aussi fructueux que je l'avais espéré.

Silvio Mayolo
la source
2
uncurryest tellement verbeux. :( Mais vous pouvez remplacer les parenthèses les plus externes par $.
Ørjan Johansen
Oui, et c'est malheureusement le problème avec beaucoup de noms de fonctions dans Haskell. Trop long pour jouer au golf. Mais merci pour les économies de 1 caractère!
Silvio Mayolo