Adición de tuplas en punto libre

16

¿Cuál es la forma más corta en que podemos expresar la función?

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

en notación sin punto?

pointfree.io nos da

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

que con un poco de trabajo se puede acortar a

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

por 76 bytes. Pero esto todavía parece muy largo y complejo para una tarea tan simple. ¿Hay alguna forma de expresar la suma por pares como una función sin puntos más corta?

Para que quede claro lo que quiero decir con punto libre, una declaración de punto libre de una función implica tomar funciones y operadores existentes y aplicarlos entre sí de tal manera que se cree la función deseada. Acentos abiertos, paréntesis y valores literales ( [], 0, [1..3], etc.) son permitidos, pero como palabras clave wherey letno lo son. Esto significa:

  • No puede asignar ninguna variable / función

  • No puedes usar lambdas

  • No puedes importar

Aquí está la misma pregunta cuando era un CMC

Post Rock Garf Hunter
fuente
99
Nunca entendí por qué se llama " sin puntos " cuando en realidad está lleno de puntos. : P
Sr. Xcoder
55
Es una pena que no podamos importar el mejor paquete de Haskell , o de lo contrario la solución sería (+)***(+).
Silvio Mayolo
2
Una idea: (+)<$>([1],2)<*>([3],4)da ([1,3],6).
xnor
2
Pasé algún tiempo tratando de diseñar una solución fina utilizando la punta de xnor ... pero terminé con esta basura . Ni siquiera sé por qué lo intento a veces ...
totalmente humano

Respuestas:

11

44 bytes

Tengo esto de \x y -> (fst x + fst y, snd x + snd y)

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

Pruébalo en línea!

H.PWiz
fuente
8

44 bytes

-8 bytes gracias a Ørjan Johansen. -3 bytes gracias a Bruce Forte.

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

Pruébalo en línea!

Se traduce a:

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

67 bytes

-8 bytes gracias a Ørjan Johansen. -1 byte gracias a Bruce Forte.

Si se requiere salida de tupla:

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

Pruébalo en línea!

Sí, yo hacerlo manualmente no produce fruta madura. Pero estoy contento con la [a] → (a, a)conversión.

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

Ahora si hubiera una función corta con m (a → b) → a → m b.

totalmente humano
fuente
3
Odio decírtelo, pero mapM id[fst,snd]es más corto.
Ørjan Johansen
Lamentablemente, mapM ides la versión de golf de la función que probablemente estás buscando sequence.
Ørjan Johansen
Si eso es verdad. Solo estoy mirando (<*>)la firma que es m (a → b) → m a → m b. Tan cerca ...
totalmente humano
1
También hay Control.Lens.??, que puede haber sido propuesto para su inclusión en la base en algún momento.
Ørjan Johansen
Quiero extraer el (.mapM id[fst,snd])like repetido let r=(.mapM id[fst,snd]) in r(r.zipWith(+)), pero no he podido hacer que el typechecker acepte una versión sin puntos.
xnor
4

54 bytes

Sinceramente, dudo que superemos la solución de 44 bytes de @ H.PWiz, pero nadie estaba usando el hecho de que (,)implementa la clase de tipo Functor, así que aquí hay otra interesante que no está tan mal:

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

Pruébalo en línea!

Explicación

La implementación de la clase de tipo Functorpara 2 -Tuplas es muy similar a la de Either(desde 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)

Lo que esto significa para este desafío es que la siguiente función agrega los segundos elementos mientras mantiene el primer elemento del segundo argumento:

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

Entonces, si solo obtuviéramos un poco de ayuda helpPlz = \a b -> (fst a+fst b,snd b), podríamos hacer (helpPlz<*>).flip(fmap.(+).snd)y estaríamos listos. Afortunadamente tenemos la herramienta pointfreeque nos brinda:

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

Entonces, simplemente volviendo a conectar esa función llegamos a la solución anterior (tenga en cuenta que (<*>) = apestá en la base ).

ბიმო
fuente
4

60 bytes

No veo ningún uncurryamor aquí, así que pensé en aparecer y arreglar eso.

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

Pensé, con todo el fsty snd, que desempacar los argumentos con uncurrypodría arrojar algunos resultados. Claramente, no fue tan fructífero como esperaba.

Silvio Mayolo
fuente
2
uncurryEs muy detallado. :( Pero puedes reemplazar los paréntesis más externos con $.
Ørjan Johansen
Sí, y desafortunadamente ese es el problema con muchos nombres de funciones en Haskell. Demasiado tiempo para jugar al golf. ¡Pero gracias por el ahorro de 1 personaje!
Silvio Mayolo