Implementar paradigmas de programação funcional


21

Sua empresa está apenas começando um projeto e, pela primeira vez, você decidiu usar um estilo de código de programação funcional. No entanto, seu chefe é realmente indiferente e não deseja usar funções internas e requer que você implemente as funções principais. Em particular, você precisa escrever as funções: Map, Nest, Apply, Range, Folde Tableem uma língua da sua escolha. O chefe é um homem muito ocupado, e ele quer ter os programas o mais curto possível, para não perder tempo lendo. Ele também gostaria que você não usasse loops, portanto, você terá uma redução de 10% na contagem de bytes por não usar loops.

Os requisitos detalhados das funções estão abaixo:

Mapa

A Mapfunção usa dois parâmetros: fe listonde fé uma função e listé uma lista de valores. Ele deve retornar o faplicado a cada elemento de list. Portanto, ele funcionará como tal:

Map(f,{a,b,c})

retorna

{ f(a), f(b), f(c) }

e

Map(f, {{a,b},{b,c}})

retorna

{ f({a,b}), f({b,c})}

Ninho

A Nestfunção usa três parâmetros, bem como: f, arg, timesonde fé uma função, argé o seu argumento inicial, e timesé quantas vezes a função é aplicada. Deve retornar uma expressão com tempos faplicados timespara arg. Portanto, ele funcionará como tal:

Nest(f, x, 3)

retorna

f(f(f(x)))

e

Nest(f, {a,b}, 3)

retorna

f(f(f({a,b})))

Aplique

A Applyfunção usa dois parâmetros: fe argsonde fé uma função e argsuma lista. Deve aplicar f- se ao args. Assim sendo:

Apply(f, {a,b,c})

retorna

f(a,b,c)

Alcance

A Rangefunção pega um número inteiro re gera os números inteiros até esse número. Assim sendo:

Range(5)

retorna

{ 1, 2, 3, 4, 5}

Dobra

A Foldfunção usa três parâmetros f, arg, othersonde fé uma função, argé um parâmetro simples, e othersuma lista. Funcionará assim:

Fold(f, x, {a, b, c, d})

retorna

f(f(f(f(x,a),b),c),d)

Tabela

As funções da tabela devem ter uma função fe um parâmetro chamado iteratorno formato: {iMin, iMax}where iMine iMaxsão números inteiros. Você deve aplicar fno intervalo especificado. Assim sendo:

Table(f, {0, 5})

retorna

{f(0), f(1), f(2), f(3), f(4), f(5)}

Eu usei a definição dessas funções na página de programação funcional do Mathematica ; portanto, vá para lá se precisar de mais orientações. Observe que você não precisará implementar toda a versão das funções mostradas nessa página, mas apenas as escritas nesta postagem.

As brechas padrão não são permitidas como de costume.

Caso seu idioma não permita que funções sejam passadas como argumentos, você precisará implementar esse recurso e adicioná-lo à sua resposta. No entanto, a contagem de bytes desta operação não será adicionada ao total.

Este é o código de golfe, portanto o código mais curto vence. Boa sorte!!!


Isso é incrível! +1 No entanto, eu realmente não entendo como Tablefunciona aqui. Seu exemplo deveria ser Table(f, {x, 0, 5})? Também não entendo o objetivo x, pois apenas aplica a função ao intervalo.
precisa saber é o seguinte

@ kirbyfan64sos Obrigado! Sim, isso foi um erro de digitação, deixei x em como uma referência para mathematica, que usa como feauture simbólico, porém eu acho que eu posso tirá-lo
WizardOfMenlo

Mais uma pergunta: como denominamos as funções? Temos que dar a eles exatamente os mesmos nomes? Uma letra?
kirbyfan64sos

@ kirbyfan64sos Como é código-golfe, permitirei nomes com uma única letra, no entanto, em sua resposta, coloque um cabeçalho sobre cada função para que possamos saber qual é. Também não use letras em colisão.
WizardOfMenlo

Você poderia ser mais específico sobre o que conta como um loop?
xnor

Respostas:


9

Haskell, muitos bytes anteriores contam 127 * 0,9 = 114,3 bytes

f#(a:b)=f a:f#b;f#x=x
(f&x)0=x;(f&x)i=f$f&x$i-1
i=id
r x=i%(1,x)
(g?x)(a:b)=g(g?x$b)a;(g?x)y=x
f%(a,b)|a>b=[]|1<2=f a:f%(a+1,b)

Sem loops, apenas recursão.

#é o mapa: (*2) # [1,2,3]->[2,4,6]

&é ninho: ((*2) & 3) 4->48

ié aplicável: i (*2) 7->14

ré o intervalo: r 4->[1,2,3,4]

?é fold: ((+) ? 0) [1,2,3,4]->10

%é tabela: (*2) % (2,4)->[4,6,8]

Conforme solicitado, uma versão não-gasta com comentários. Observe &e ?são operadores de infixo ternários, que exigem parênteses adicionais quando chamados ou correspondidos por padrão.

f # (a:b) = f a : f#b        -- map on a list (a->head, b->tail) is f a in front of mapping f to b
f # x     = x                -- map on the empty list is the empty list
                             -- (non empty lists are caught in the line before) 

(f & x) 0 = x                -- nesting zero times is x
(f & x) i = f $ f&x $ i-1    -- nesting i times is f (nesting one time less)

i=id                         -- apply in Haskell is just the identity function 

r x = i % (1,x)              -- defined via the "table" of the identity function from 1 to x

(g ? x) (a:b) = g (g?x$b) a  -- folding g into a list (a->head, b->tail) is g applied to (folding g into b) and a
(g ? x) y     = x             -- folding the empty list is x
                             --  again, y must be the empty list, else it would have been handled by the previous line

f % (a,b)                    
  |a>b       = []                -- if iMin is greater than iMax, the table is empty
  |otherwise = f a : f%(a+1,b)   --  otherwise f a in front of the table with iMin increased by one

Obrigado a @dfeuer e @Zgarb por algumas dicas úteis


Eu sou novo no haskell, parece muito bom, no entanto, você poderia adicionar uma explicação ao que está fazendo?
23615 WizardOfMenlo #

11
@WizardOfMenlo: adicionou alguns comentários
nimi

Acabei de perceber o quão elegante Haskell é, muito bom!
WizardOfMenlo

11
Ignorando listas infinitas e eficiência m#q=reverse$f((:).m)[]q,. Este é o mesmo comprimento que o seu, mas muito mais difícil de ler.
Dfeuer

Você pode encurtar !, tornando-a um nome em vez de um operador: i f=f.
dfeuer

5

Python 2, 305,1 bytes (-10% 376 369 366 349 339 bytes)

exec'e=eval;q=len;m=@,l:e("["+"f(l.pop()),"*q(l)+"][::-1]");n=@,x,l:e("f("*l+"*x"+")"*l);r=@:e("r(f-1)+"*(f>1)+"[f]");a=@,a:e("f(a["+`r(q(a))`[1:-1]$",","-1],a[")+"-1])");f=@,x,l:e("f("*q(l)+"x,["+`r(q(l))`[1:-1]$",","-1]),l[")+"-1])");t=@,n,x:e("[f("+`r(x)[n-1:]`$",","),f(")[1:-1]+")]")'.replace("@","lambda f").replace("$",".replace(")

Quando expandido, equivalente a:

e=eval;q=len
m=lambda f,l:e("["+"f(l.pop()),"*q(l)+"][::-1]")
n=lambda f,x,l:e("f("*l+"*x"+")"*l)
r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
a=lambda f,a:e("f(a["+`r(q(a))`[1:-1].replace(",","-1],a[")+"-1])")
f=lambda f,x,l:e("f("*q(l)+"x,["+`r(q(l))`[1:-1].replace(",","-1]),l[")+"-1])")
t=lambda f,n,x:e("[f("+`r(x)[n-1:]`.replace(",","),f(")[1:-1]+")]")

Sem loops!

Bem, isso faz muita coisa evale se seu chefe não aguenta loops, ele odeia avaliar. Mas eles terão que aturar isso

Uma maneira de fazer rangeum lambda é apreciada, para que eu não precise executar nenhuma função (Shudder.).

Explicações:

  • m=lambda f,l:eval("["+"f(l.pop()),"*len(l)+"][::-1]")
    • Crie uma string que solte elementos da lista, envolva-a em uma lista, inverta-a e, finalmente, avalie-a!
  • n=lambda f,x,l:eval("f("*l+"*x"+")"*l)
    • Crie manualmente a sequência com o aninhamento e avalie-a!
  • r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
    • Crie uma string que, quando evaleditada, retorne [0]ou use recursão para obter os resultados anteriores e adicione o índice atual à lista. Avalia.
  • a=lambda f,a:eval("f(a["+r (len (a))[1:-1].replace(",","-1],a[")+"-1])")
    • Usa a função de intervalo para obter os índices 1 len (lista). Substitui as vírgulas na lista com strings por uma maneira de obter o índice correto da lista a. Avalia!
  • f=lambda f,x,l:eval("f("*len(l)+"x,["+r (len (l))[1:-1].replace(",","-1]),l[")+"-1])")
    • O mesmo que se aplica, exceto substitui as vírgulas por colchetes, vírgulas e inicia o índice da lista.
  • t=lambda f,n,x:eval("[f("+r (x) [n-1:].replace(",","),f(")[1:-1]+")]")
    • O mesmo que aplicar e dobrar, exceto substitui o término da função e a chamada da nova. Avalia!

Mapeie, aninhe, alcance, aplique, dobre, tabela.

Obrigado @Zgarb por um lambda para range!


Meu chefe terá minha cabeça em sua mesa :) Você poderia adicionar uma breve explicação também, por favor?
WizardOfMenlo

Que tal r=lambda i:[]if i<1 else r(i-1)+[i]? Sem loops, apenas recursão.
Zgarb 24/09/2015

11
Claro, eu vou levar isso para agora, mas as necessidades chefe mais evalpara mostrar-lhes como para loops não são tão ruins :)
azul

Ha! Outra versão usando e=eval:r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
Zgarb

você pode alterá-lo do bônus de 60% para 10%, por favor? Eu revisto a especificação questão, de modo a torná-lo mais justo
WizardOfMenlo

5

Javascript ES6, 197 * 0,9 = 177,3 bytes

M=(f,l)=>F((a,b)=>[...a,f(b)],[],l)
N=(f,x,n)=>f(--n?N(f,x,n):x)
A=(f,l)=>f(...l)
R=n=>n--?[...R(n),n+1]:[]
F=(f,x,l,n=l.length)=>n--?f(F(f,x,l,n),l[n]):x
T=(f,i)=>([n,x]=i,M(q=>f(q+n-1),R(x-n+1)))

Mapa ( M=(f,l)=>F((a,b)=>[...a,f(b)],[],l)):

Usa Fold para concaturar os resultados de faplicado a todos os membros lem uma lista vazia. O uso de funções integradas reduz o valor para M=(f,l)=>l.map(f)(não o utilizou porque parece barato ...?).

Ninho ( N=(f,x,n)=>f(--n?N(f,x,n):x)):

Aplique frecursivamente até ndiminuir para 0.

Aplicar ( A=(f,l)=>f(...l)):

Usa o spread ( ...operador) para aplicar lpara f.

Intervalo ( R=n=>n--?[...R(n),n+1]:[]):

Concat nna chamada recursiva do intervalo até que nseja diminuído para 0.

Dobra ( F=(f,x,l,n=l.length)=>n--?f(F(f,x,l,n),l[n]):x):

Aplica a chamada recursiva de Fold e o n'th elemento de lto faté né diminuído para 0. O uso de funções internas reduz isso para F=(f,x,l)=>l.reduce(f,x)(novamente, parecia barato ...).

Tabela ( T=(f,i)=>([n,x]=i,M(q=>f(q+n-1),R(x-n+1)))):

Inicializa primeiro ne xpara o iMin e o iMax usando destructuring ( [n,x]=i), depois usa Range para construir a tabela de valores do iMin ao iMax. fé então aplicado sobre a tabela usando Map e o resultado é retornado.


Quer conhecer minha filosofia? "Se for barato, compre." Não diz nas especificações que você ainda não pode usar os componentes internos, portanto, use-os!
Mama Fun Roll

4

Python 3, 218 bytes

A versão ilegível:

exec("P!:[f(_)for _ in x];Y!,z:Y(f,f(x),z-1)if z else x;T!:f(*x);H!=0:(H(f-1)if~-f else[])+[f];O!,z:O(f,f(x,z[0]),z[1:])if z else x;N!:(N(f,[x[0],x[1]-1])if x[1]-x[0]else[])+[f(x[1])]".replace("!","=lambda f,x"))

A versão (mais) legível:

P=lambda f,x:[f(_)for _ in x]
Y=lambda f,x,z:Y(f,f(x),z-1)if z else x
T=lambda f,x:f(*x)
H=lambda f,x=0:(H(f-1)if~-f else[])+[f]
O=lambda f,x,z:O(f,f(x,z[0]),z[1:])if z else x
N=lambda f,x:(N(f,[x[0],x[1]-1])if x[1]-x[0]else[])+[f(x[1])]

Indo embora um lambda de cada vez:

Função de mapa P

P=lambda f,x:[f(_)for _ in x]
Apenas um iterador simples. Não há muito a dizer aqui.

Função Nest Y

Y=lambda f,x,z:Y(f,f(x),z-1)if z else x
Repetindo até zatingir zero, aplicando fsempre. A cláusula if no final parece desajeitada; talvez haja uma maneira melhor de terminar a recursão.

Aplicar função T

T=lambda f,x:f(*x)
O Python tem um bom operador de expansão para fazer todo o trabalho pesado para mim.

Função de faixa H

H=lambda f,x=0:(H(f-1)if~-f else[])+[f]
Este foi mais difícil do que eu esperava. Acabou adotando uma abordagem recursiva. Novamente, a construção if-else ocupa muitos bytes e acho que pode ser melhorada. Por que ele tem um boneco x=0, você pergunta? É para que quando eu comprimo com o exec, eu possa substituir em =lambda f,xvez de apenas =lambda f.

Função de dobra O

O=lambda f,x,z:O(f,f(x,z[0]),z[1:])if z else x
Muito feliz com este. Apenas corta o primeiro elemento da matriz toda vez que ele se repete, até que não resta mais nada.

Função de tabela N

N=lambda f,x:(N(f,[x[0],x[1]-1])if x[1]-x[0]else[])+[f(x[1])]
Este é horrível e tenho certeza de que há espaço para melhorias. Tentou usar as funções de alcance e mapa definidas anteriormente para um map(f,range(x,y))tipo de construção, mas sem muito sucesso. Acabou fazendo uma terrível abordagem recursiva que compartilha alguma semelhança com a função range.

Todas as lambdas são agrupadas em um execcom a replacepara diminuir significativamente a contagem de bytes.


Eu estava prestes a comentário que [f(_)for _ in x]poderia ser reduzido para map(f,x), mas depois lembrei-me que o desafio era
Cyoce

4

Julia, 181 bytes

Nenhum bônus para mim; Eu usei loops liberalmente. Desculpe chefe, mas os loops em Julia são eficientes!

M(f,x)=[f(i...)for i=x]
N(f,x,n)=(for i=1:n x=f(x...)end;x)
A(f,x)=f(x...)
R(n)=(i=0;x={};while i<n push!(x,i+=1)end;x)
F(f,x,a)=(for b=a x=f(x,b)end;x)
T(f,i)=[f(j)for j=i[1]:i[2]]

Adicionar as elipses após um argumento a uma função quebra uma matriz, tupla ou o que você coloca nos argumentos da função regular. Caso contrário, a função pensará que você está tentando passar uma matriz (ou tupla, etc.). Não tem efeito para argumentos únicos.

Nomes de funções:

  • Mapa: M
  • Ninho: N
  • Aplique: A
  • Alcance: R
  • Dobra: F
  • Tabela: T

4

tinilisp , 325 * 0,9 = 292,5

A linguagem é mais nova que a pergunta, mas não vai ganhar de qualquer maneira.

(d @(q(a a)))(d Q(q((l)(i l(c(@(q q)(h l))(Q(t l)))l))))(d A(q((f a)(v(c(q f)(Q a))))))(d M(q((f l)(i l(c(A f(@(h l)))(M f(t l)))l))))(d N(q((f a x)(i x(A f(@(N f a(s x 1))))a))))(d ,(q((m a b)(i(l b a)m(,(c b m)a(s b 1))))))(d R(q((a)(,()1 a))))(d T(q((f r)(M f(A ,(c()r))))))(d F(q((f a l)(i l(F f(A f(@ a(h l)))(t l))a))))

Define as funções A(aplicar), M(mapa), N(aninhar), R(intervalo), T(tabela) e F(dobra), juntamente com algumas funções auxiliares. Tespera uma lista de dois números inteiros para seu segundo argumento.

Tinylisp nem sequer tem construções de loop; tudo é realizado usando recursão. Várias dessas funções não são recursivas de cauda , portanto, se você as chamar em grandes listas, elas provavelmente explodirão a pilha de chamadas. Todos eles poderiam ser implementados com recursão de cauda ... mas seriam necessários mais bytes, e isso é código de golfe.

Aqui está uma versão expandida com espaço em branco e palavras reais para nomes, que devem ser bem legíveis se você estiver familiarizado com o Lisp. (Alias ​​a maioria dos tinylisp embutidos, exceto q(quote) e i(if).)

(d define d)
(define cons c)
(define car h)
(define cdr t)
(define subtract s)
(define less l)
(define eval v)

(define lambda
  (q (()
      (arglist expr)
      (list arglist expr))))

(define list (lambda args args))

(define quote-all
  (lambda (lyst)
    (i lyst
       (cons
         (list (q q) (car lyst))
         (quote-all (cdr lyst)))
       lyst)))

(define Apply
  (lambda (func arglist)
    (eval (cons (q func) (quote-all arglist)))))

(define Map
  (lambda (func lyst)
    (i lyst
       (cons
         (Apply func (list (car lyst)))
         (Map func (cdr lyst)))
       lyst)))

(define Nest
  (lambda (func arg times)
    (i times
       (Apply func
              (list (Nest func arg (subtract times 1))))
       arg)))

(define range*
  (lambda (accumulator a b)
    (i (less b a)
       accumulator
       (range* (cons b accumulator) a (subtract b 1)))))

(define Range
  (lambda (x)
    (range* 1 x)))

(define Table
  (lambda (func iterator)
    (Map func
         (Apply range* (cons () iterator)))))

(define Fold
  (lambda (func arg lyst)
    (i lyst
       (Fold func
             (Apply func (list arg (car lyst)))
             (cdr lyst))
       arg)))

Mais explicações disponíveis mediante solicitação.

Saída de amostra

Usa o ambiente REPL da minha implementação de referência. Eu usei q(quote) para a função unária e s(subtrai) como a função binária desses exemplos, bem como a função @(definida neste código) que retorna uma lista de seus argumentos.

tl> [line of definitions goes here]
@
Q
A
M
N
,
R
T
F
tl> (A s (@ 10 7))
3
tl> (M q (@ 1 2 3 4))
((q 1) (q 2) (q 3) (q 4))
tl> (N q 123 4)
(q (q (q (q 123))))
tl> (R 5)
(1 2 3 4 5)
tl> (T q (@ 3 7))
((q 3) (q 4) (q 5) (q 6) (q 7))
tl> (F s 10 (@ 4 3 2))
1

2

Python 2.x: 450.6 bytes (493 bytes antes de 10% de desconto)

Resposta golfe:

y=len
z=lambda a,b:a.append(b)
_=lambda a:a if a is not None else[]
def M(a,b,c=None):
 c=_(c);d=y(b)
 if d:z(c,A(a,b[0]))
 return M(a,b[1:],c)if d else c
def N(a,b,c):d=A(a,b);return N(a,d,c-1)if c>1 else d
A=lambda a,b:a(*b)if type(b)is list else a(b)
def R(a,b=None):b=_(b);b.insert(0,a);return b if a<=1 else R(a-1,b)
def F(a,b,c):d=a(b,c[0]);return F(a,d,c[1:])if y(c)>1 else d
def T(a,b,c=None,d=None):
 if c is None:c=b[0];d=[]
 z(d,a(c));return T(a,b,c+1,d)if c<b[1]else d

Esta pergunta foi divertida. Decidi escrever minhas funções sem usar os equivalentes do Python (embora isso possa ter sido uma brecha válida) e escrever as funções como se o Python fosse compatível com a recursão da cauda. Para fazer isso funcionar, usei muitos parâmetros opcionais que permitem que as chamadas necessárias ainda funcionem.

Abaixo, tenho listagens ungolfed para cada função.

Apply:

A = lambda function, arguments: function(*arguments) if type(arguments) is list else function(arguments)

Map:

def M(function, arguments, result=None):
    result = result if result is not None else []
    length = len(arguments)
    if length != 0:
        result.append(A(function, arguments[0]))
    return M(function, arguments[1:], result) if length != 0 else result

Nest:

def N(function, arguments, times):
    result = A(function, arguments)
    return N(function, result, times - 1) if times > 1 else result

Observe que essa função requer que o passado functionseja capaz de representar vários argumentos de maneira variável. Outra abordagem seria impor que a função sempre recebesse uma lista única, mas isso exigiria que as funções passadas pudessem interpretar listas de argumentos. Havia suposições de qualquer maneira, então eu escolhi a que se encaixava melhor no resto do sistema.

Range:

def R(ceiling, result=None):
    result = result if result is not None else []
    result.insert(0, ceiling)
    return result if ceiling <= 1 else R(ceiling - 1, result)

Fold:

def F(function, initial, rest):
    result = function(initial, rest[0])
    return F(function, result, rest[1:] if len(rest) > 1 else result

Table:

def T(function, iterator, current=None, result=None):
    if current is None:
        current = iterator[0]
        result = []
    result.append(function(current))
    return T(function, iterator, current + 1, result) if current < iterator[1] else result

Aqui está um exemplo de saída usando as seguintes funções auxiliares:

square = lambda x: x * x
def add(*args):
    addTwo = lambda a, b: a + b
    if len(args) == 1 and type(args[0]) is list:
        return F(addTwo, 0, args[0])
    else:
        return F(addTwo, 0, args)

>>> M(square, R(10))
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> M(add, [R(i) for i in R(10)])
[1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
>>> T(square, [0, 10])
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> N(square, 2, 4)
65536
>>> N(lambda *args: F(lambda a, b: a * b, 1, args) if len(args) > 1 else str(args[0]) + 'a', R(5), 10)
'120aaaaaaaaa'

Uau, parece muito bom!
WizardOfMenlo

Isso parece um senso de estética distorcido; ) Eu sempre acho divertido ver o Python com golfe desde o primeiro livro em Python que li sobre como o Python impõe a legibilidade.
Sadakatsu

Eu realmente têm um senso distorcido de estética :)
WizardOfMenlo

Estou confuso com as pontuações de outras pessoas. Tirei 10% da pontuação de cada uma das funções necessárias que não usavam um loop (que eram todas elas), mas outras pessoas pegaram 10% de toda a pontuação de cada função que não usava um loop (que pode ser até 60% de desconto). Qual é a abordagem correta?
Sadakatsu

O seu é o caminho correto a seguir, eu tinha uma expectativa irrealista e, inicialmente, eu tinha em mente a abordagem de 60%, mas agora acho que os 10% serão mais estimulantes e mais fortes entre os dois
WizardOfMenlo

2

Ceilão, 370 * 0,9 = 333 364 * 0,9 = 327,4

A maioria dessas funções já está disponível no pacote de idiomas do Ceilão (embora às vezes com uma assinatura um pouco diferente), mas as definimos aqui como solicitado na pergunta.

alias I=>Integer;R[]m<A,R>(R(A)g,A[]l)=>f((R[]x,A y)=>x.append([g(y)]),[],l);A n<A>(A(A)g,A a,I t)=>f((A x,I y)=>g(x),a,r(t));R y<A,R>(Callable<R,A>g,A v)given A satisfies Anything[]=>g(*v);I[]r(I i)=>t((j)=>j,[1,i]);A f<A,O>(A(A,O)g,A a,O[]o)=>if(nonempty o)then f(g,g(a,o[0]),o.rest)else a;R[]t<R>(R(I)g,[I,I]i)=>i[1]<i[0]then[]else[g(i[0]),*t(g,[i[0]+1,i[1]])];

Na verdade, apenas duas das funções ( te f) estão realmente usando recursão (sobre listas e números inteiros, respectivamente), as outras são baseadas nelas. (O aplicativo é um pouco estranho, realmente não se relaciona com os outros.)

Interpreto "List" como o tipo Sequencial do Ceilão, que é uma sequência imutável de elementos (possivelmente vazios). [R*]significa Sequential<R>- por alguma razão, também podemos escrevê-lo R[], que é um byte mais curto.

Um tipo de função é Callable<R, A>, onde Aé um tipo de tupla para os argumentos, como [X, Y, Z](por exemplo, algum subtipo deAnything[] ). Como atalho, podemos escrever em R(X,Y,Z)vez de Callable<R,[X,Y,Z]>.

Eu alias Integer como Isalvar alguns bytes.

Aqui está uma versão formatada (e ligeiramente comentada):

// implement functional paradigms
//
// Question: http://codegolf.stackexchange.com/q/58588/2338
// My Answer: http://codegolf.stackexchange.com/a/64515/2338

alias I => Integer;

// map – based on fold.
R[] m<A, R>(R(A) g, A[] l) =>
        f((R[]x,A y) => x.append([g(y)]), [], l);

// nest – based on fold + range, throwing away the second
//        argument in a proxy function.
A n<A>(A(A) g, A a, I t) =>
        f((A x, I y) => g(x), a, r(t));

// apply – this looks quite heavy due to type safety.
//         This uses the "spread operator" *.
R y<A, R>(Callable<R,A> g, A v)
        given A satisfies Anything[] =>
        g(*v);

// range – based on table (using the identity function)
I[] r(I i) =>
        t((j) => j, [1, i]);

// fold – a plain list recursion.
A f<A, O>(A(A, O) g, A a, O[] o) =>
        if (nonempty o) then f(g, g(a, o[0]), o.rest) else a;

// table – an integer recursion.
//        (Not sure why the min/max parameters need
//         to be passed in one argument.)
R[] t<R>(R(I) g, [I, I] i) =>
        i[1] < i[0] then [] else [g(i[0]), *t(g, [i[0] + 1, i[1]])];

Usando "loops"

Tabela e Mapa podem ser implementados mais curtos usando loops (na verdade, uma compreensão de sequência):

// map – using a sequence comprehension:
R[] m<A, R>(R(A) g, A[] l) =>
        [for(a in l) g(a)];

// table – map with an integer range.
//        (Not sure why the min/max parameters need
//         to be passed in one argument.)
R[] t<R>(R(I) g, [I, I] i) =>
        m(g, i[0]..i[1]);

Embora eu não tenha certeza se o uso do ..operador para o intervalo inteiro conta como usando uma função interna. Se isso for permitido, o código resultante é este aqui, comprimento 312:

alias I=>Integer;R[]m<A,R>(R(A)g,A[]l)=>[for(a in l)g(a)];A n<A>(A(A)g,A a,I t)=>f((A x,I y)=>g(x),a,r(t));R y<A,R>(Callable<R,A>g,A v)given A satisfies Anything[]=>g(*v);I[]r(I i)=>t((j)=>j,[1,i]);A f<A,O>(A(A,O)g,A a,O[]o)=>if(nonempty o)then f(g,g(a,o[0]),o.rest)else a;R[]t<R>(R(I)g,[I,I]i)=>m(g,i[0]..i[1]);

(Pode ser ainda mais curto definindo r(I i) => 1..i , resultando na pontuação 301. Embora isso pareça ainda mais trapaça.)

Se ..não for permitido, teremos que implementá-lo novamente. Podemos usar essas implementações para re t(com o macima):

// range – based two-limit range 
I[] r(I i) =>
        q(1, i);

// two-limit range implemented recursively
I[] q(I i, I j) =>
        j < i then [] else [i, *q(i + 1, j)];


// table – map with an integer range.
//        (Not sure why the min/max parameters need
//         to be passed in one argument.)
R[] t<R>(R(I) g, [I, I] i) =>
        m(g, q(i[0], i[1]));

Isso resulta em 348 bytes, melhor que a versão completamente recursiva, mas não após a aplicação do bônus.


0

Groovy (146 bytes) (146 * 90% = 131,4)

PS: Eu não sei o que você está considerando como um 'loop' nesse contexto, só apliquei o bônus depois que me disseram nos comentários pelo OP e removerei se 2-3 usuários adicionais disserem que essas funções de coleção e iteradores são loops e que eu não mereço o bônus. Além disso, se você quiser me chamar para usar 1..it, faça-o e eu o retrabalharei / atualizo meu número de bytes.

m={f,l->l.collect{f(it)}}            // Map
n={f,x,n->n.times{x=f(x)};x}         // Nest
a={f,l->f(l)}                        // Apply
r={1..it}                            // Range (Is this cheating?)
f={f,x,l->l.each{x=f(x,it)};x}       // Fold
t={f,l->(l[0]..l[1]).collect{f(it)}} // Table

Exemplo de entrada / saída

f1={2*it}
f2={a,b,c,d,e->a*b*c*d*e}
f3={a,b->a*b}
l=[1,2,3,4,5]
l2=[1,9]
y=5
x=1
println m(f1,l)
println n(f1,x,y)
println a(f2,l)
println r(y)
println f(f3,x,l)
println t(f1,l2)

Saída

MAP:   [2, 4, 6, 8, 10]
NEST:  32
APPLY: 120
RANGE: [1, 2, 3, 4, 5]
FOLD:  120
TABLE: [2, 4, 6, 8, 10, 12, 14, 16, 18]

Experimente você mesmo: https://groovyconsole.appspot.com/edit/5203951758606336


Tecnicamente, isso não usa loops, então lembre-se do bônus! Senão, ótima resposta!
WizardOfMenlo 8/16

Tecnicamente sem loops ?! Sério?! .each {}. vezes {} .collect {} são iteradores.
Magic Octopus Urn
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.