Adição de tupla no pointfree

16

Qual é a maneira mais curta de expressar a função

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

em notação sem ponto?

pointfree.io nos dá

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

que com um pouco de trabalho pode ser reduzido para

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

por 76 bytes. Mas isso ainda parece muito longo e complexo para uma tarefa tão simples. Existe alguma maneira de expressar a adição aos pares como uma função sem pontos mais curta?

Para ficar claro com o que quero dizer com sem ponto, uma declaração sem ponto de uma função envolve pegar funções e operadores existentes e aplicá-los um ao outro de modo que a função desejada seja criada. Acentos graves, parênteses e valores literais ( [], 0, [1..3], etc) são permitidos, mas palavras-chave como wheree letnão são. Isso significa:

  • Você não pode atribuir nenhuma variável / função

  • Você não pode usar lambdas

  • Você não pode importar

Aqui está a mesma pergunta quando era um CMC

Post Rock Garf Hunter
fonte
9
Eu nunca entendi por que é chamado de " sem pontos " quando na verdade está cheio de pontos. : P
Mr. Xcoder
5
É uma pena que não tenhamos permissão para importar o melhor pacote Haskell , caso contrário a solução seria apenas (+)***(+).
Silvio Mayolo 30/12
2
Uma ideia: (+)<$>([1],2)<*>([3],4)([1,3],6).
Xnor
2
Passei algum tempo tentando criar uma boa solução utilizando a dica do xnor ... mas acabei com esse lixo . Eu nem sei por que eu tento às vezes ...
totallyhuman

Respostas:

11

44 bytes

Obtive isso de \x y -> (fst x + fst y, snd x + snd y)

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

Experimente online!

H.PWiz
fonte
8

44 bytes

-8 bytes graças a Ørjan Johansen. -3 bytes graças a Bruce Forte.

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

Experimente online!

Traduz para:

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

67 bytes

-8 bytes graças a Ørjan Johansen. -1 byte graças a Bruce Forte.

Se a saída da tupla for necessária:

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

Experimente online!

Sim, eu manualmente não produz frutos maduros. Mas estou feliz com a [a] → (a, a)conversão.

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

Agora, se houvesse uma função curta com m (a → b) → a → m b.

totalmente humano
fonte
3
Odeio quebrá-lo para você, mas mapM id[fst,snd]é mais curto.
Ørjan Johansen
Infelizmente, mapM idé a versão em golf da função que você provavelmente está procurando sequence,.
Ørjan Johansen
Sim, é verdade. Estou apenas olhando para (<*>)a assinatura que é m (a → b) → m a → m b. Tão perto ...
totallyhuman
1
Há também Control.Lens.??, o que pode ter sido proposto para inclusão na base em algum momento.
Ørjan Johansen
Eu quero extrair o repetido (.mapM id[fst,snd])como let r=(.mapM id[fst,snd]) in r(r.zipWith(+)), mas eu não tenho sido capaz de obter o typechecker a aceitar uma versão pointfree.
Xnor
4

54 bytes

Sinceramente, duvido que venceremos a solução de 44 bytes do @PWiz, mas ninguém estava usando o fato de (,)implementar a classe type Functor, então aqui está outra interessante que não é tão ruim:

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

Experimente online!

Explicação

A implementação da classe type Functorpara 2 -Tuples é muito semelhante à de Either(da 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)

O que isso significa para esse desafio é que a função a seguir adiciona os segundos elementos enquanto mantém o primeiro elemento do segundo argumento:

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

Então, se tivéssemos algum ajudante helpPlz = \a b -> (fst a+fst b,snd b), poderíamos fazer (helpPlz<*>).flip(fmap.(+).snd)e estaríamos prontos. Felizmente, temos a ferramenta pointfreeque nos dá:

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

Então, simplesmente reconectando essa função, chegamos à solução acima (observe a (<*>) = apque está na base ).

ბიმო
fonte
4

60 bytes

Não estou vendo nenhum uncurryamor aqui, então imaginei que iria aparecer e consertar isso.

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

Eu pensei, com todos os fste snd, que descompactar os argumentos com uncurrypoderia produzir alguns resultados. Claramente, não foi tão proveitoso quanto eu esperava.

Silvio Mayolo
fonte
2
uncurryé tão detalhado. :( Mas você pode substituir os parênteses mais externos por $.
Ørjan Johansen
Sim, e infelizmente esse é o problema com muitos nomes de funções em Haskell. Apenas muito tempo para jogar golfe. Mas obrigado pela economia de 1 caractere!
Silvio Mayolo