Implémenter des paradigmes de programmation fonctionnelle

21

Votre entreprise ne fait que commencer un projet, et pour la première fois vous avez décidé d'utiliser un style de code de programmation fonctionnel. Cependant, votre patron est vraiment méfiant et ne veut pas utiliser les fonctions intégrées, et vous oblige à implémenter vous-même les fonctions principales. En particulier , vous devez écrire les fonctions: Map, Nest, Apply, Range, Foldet Tabledans une langue de votre choix. Le patron est un homme très occupé, et il veut que les programmes soient aussi courts que possible, donc il ne perd pas de temps à lire. Il aimerait également que vous n'utilisiez pas de boucles, donc vous aurez une réduction de 10% sur le nombre d'octets pour ne pas utiliser de boucles.

Les exigences détaillées des fonctions sont ci-dessous:

Carte

La Mapfonction prend deux paramètres: fet listfest une fonction et listest une liste de valeurs. Il doit renvoyer l' fappliqué à chaque élément de list. Par conséquent, cela fonctionnera comme tel:

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

Retour

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

et

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

Retour

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

Nid

La Nestfonction prend trois paramètres ainsi: f, arg, timesfest une fonction, argest son argument de départ, et timesest combien de fois la fonction est appliquée. Il doit renvoyer une expression avec fdes timestemps appliqués à arg. Par conséquent, cela fonctionnera comme tel:

Nest(f, x, 3)

Retour

f(f(f(x)))

et

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

Retour

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

Appliquer

La Applyfonction prend deux paramètres: fet argsfest une fonction et argsune liste. Il devrait s'appliquer fau args. Donc:

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

Retour

f(a,b,c)

Gamme

La Rangefonction prend un entier ret génère les nombres entiers jusqu'à ce nombre. Donc:

Range(5)

Retour

{ 1, 2, 3, 4, 5}

Plier

La Foldfonction prend trois paramètres f, arg, othersfest une fonction, argest simple paramètre, et othersune liste. Cela fonctionnera comme tel:

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

Retour

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

Table

Les fonctions de table doivent prendre une fonction fet un paramètre appelé iteratorsous la forme: {iMin, iMax}iMinet iMaxsont des entiers. Vous devez appliquer fsur la plage spécifiée. Donc:

Table(f, {0, 5})

Retour

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

J'ai utilisé la définition de ces fonctions à partir de la page de programmation fonctionnelle de Mathematica , alors allez-y si vous avez besoin de plus d'informations. Notez que vous n'aurez pas besoin d'implémenter toutes les versions des fonctions présentées dans cette page, mais seulement celles écrites dans ce post.

Les échappatoires standard sont interdites comme d'habitude.

Dans le cas où votre langage ne permet pas de passer des fonctions comme arguments, vous devez implémenter cette fonctionnalité et l'ajouter à votre réponse. Cependant, le nombre d'octets de cette opération ne sera pas ajouté au total.

C'est le golf de code donc le code le plus court gagne. Bonne chance!!!

WizardOfMenlo
la source
C'est génial! +1 Cependant, je ne comprends pas vraiment comment cela Tablefonctionne ici. Votre exemple est-il censé être Table(f, {x, 0, 5})? Je ne comprends pas du tout le but x, car il applique simplement la fonction à la plage.
kirbyfan64sos
@ kirbyfan64sos Merci! Oui, c'était une faute de frappe, j'ai laissé x in comme référence à Mathemica, qui l'utilise comme une caractéristique symbolique, mais je pense que je peux le sortir
WizardOfMenlo
Encore une question: comment nommer les fonctions? Faut-il leur donner exactement les mêmes noms? Une seule lettre?
kirbyfan64sos
@ kirbyfan64sos Puisqu'il s'agit de code-golf, je vais autoriser les noms à une seule lettre, mais dans votre réponse, mettez un en-tête sur chaque fonction afin que nous sachions laquelle. N'utilisez pas non plus de lettres en collision.
WizardOfMenlo
Pourriez-vous être plus précis sur ce qui compte comme une boucle?
2015

Réponses:

9

Haskell, de nombreux octets précédents comptent 127 * 0,9 = 114,3 octets

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)

Pas de boucles, juste une récursivité.

#est la carte: (*2) # [1,2,3]->[2,4,6]

&est nid: ((*2) & 3) 4->48

iest appliquer: i (*2) 7->14

rest gamme: r 4->[1,2,3,4]

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

%est la table: (*2) % (2,4)->[4,6,8]

Comme demandé une version non golfée avec commentaires. Remarquez, &et ce ?sont des opérateurs d'infixe ternaire, qui nécessitent des parenthèses supplémentaires lorsqu'ils sont appelés ou que le modèle correspond.

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

Merci à @dfeuer et @Zgarb pour quelques conseils utiles

nimi
la source
Je suis nouveau sur haskell, ça a l'air plutôt bien, mais pourriez-vous s'il vous plaît ajouter une explication à ce que vous faites?
WizardOfMenlo
1
@WizardOfMenlo: a ajouté quelques commentaires
nimi
Je viens de réaliser à quel point Haskell est élégant, vraiment bien!
WizardOfMenlo
1
Ignorer les listes infinies et l' efficacité, m#q=reverse$f((:).m)[]q. C'est la même longueur que la vôtre, mais beaucoup plus difficile à lire.
dfeuer
Vous pouvez raccourcir !en faisant un nom au lieu d'un opérateur: i f=f.
dfeuer
5

Python 2, 305.1 octets (-10% 376 369 366 349 339 octets)

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(")

Une fois développé, équivalent à:

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]+")]")

Pas de boucles!

Eh bien, cela fait beaucoup de travail evalet si votre patron ne supporte pas les boucles, alors il déteste l'évaluation. Mais ils vont devoir le supporter

Une façon de faire rangedans un lambda est appréciée donc je n'ai pas à faire de fonctions (Shudder.).

Explications:

  • m=lambda f,l:eval("["+"f(l.pop()),"*len(l)+"][::-1]")
    • Créez une chaîne qui fait apparaître des éléments de la liste, enveloppez-la dans une liste, inversez-la et enfin évaluez-la!
  • n=lambda f,x,l:eval("f("*l+"*x"+")"*l)
    • Créez manuellement la chaîne avec l'imbrication et évaluez-la!
  • r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
    • Créez une chaîne qui, lorsqu'elle est evaléditée, renvoie [0]ou utilise la récursivité pour obtenir les résultats précédents et ajoute l'index en cours à la liste. Evals it.
  • a=lambda f,a:eval("f(a["+r (len (a))[1:-1].replace(",","-1],a[")+"-1])")
    • Utilise la fonction range pour obtenir les index 1-len (liste). Remplace les virgules de la liste stringified par un moyen d'obtenir l'index correct de la liste a. Evals it!
  • f=lambda f,x,l:eval("f("*len(l)+"x,["+r (len (l))[1:-1].replace(",","-1]),l[")+"-1])")
    • Identique à Appliquer, mais remplace les virgules par des crochets de fermeture, des virgules et le démarrage de l'index de liste.
  • t=lambda f,n,x:eval("[f("+r (x) [n-1:].replace(",","),f(")[1:-1]+")]")
    • Identique à appliquer et plier sauf remplace en mettant fin à la fonction et en appelant la nouvelle. Evals it!

Carte, nid, plage, application, pli, table.

Merci @Zgarb pour un lambda pour la portée!

Bleu
la source
Mon patron aura la tête sur son bureau :) Pourriez-vous également ajouter une brève explication?
WizardOfMenlo
Et alors r=lambda i:[]if i<1 else r(i-1)+[i]? Pas de boucles, seulement récursivité.
Zgarb
1
Bien sûr, je vais prendre ça pour le moment mais le patron a besoin de plus evalpour leur montrer comment les boucles ne sont pas si mauvaises :)
Blue
Ha! Une autre version utilisant e=eval:r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
Zgarb
pouvez-vous le changer du bonus de 60% à un 10% s'il vous plaît? J'ai révisé la spécification de la question, donc pour la rendre plus juste
WizardOfMenlo
5

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

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)))

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

Utilise Fold pour concaténer les résultats de fappliqué à chaque membre de lsur une liste vide. L'utilisation de fonctions intégrées réduit ce paramètre à M=(f,l)=>l.map(f)(ne l'a pas utilisé car il semble bon marché ...?).

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

Appliquer frécursivement jusqu'à ce qu'il nsoit décrémenté à 0.

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

Utilise la propagation ( ...opérateur) à appliquer lsur f.

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

Concat nà l'appel récursif de Range jusqu'à ce qu'il nsoit décrémenté à 0.

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

Applique l'appel récursif de Fold et l' nélément 'th de lto fjusqu'à nest décrémenté à 0. L'utilisation de fonctions intégrées réduit cela à F=(f,x,l)=>l.reduce(f,x)(encore une fois, semblait bon marché ...).

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

Initialise d'abord net xà iMin et iMax en utilisant destructuring ( [n,x]=i), puis utilise Range pour construire la table de valeurs d'iMin à iMax. fest ensuite appliqué sur la table à l'aide de Map et le résultat est renvoyé.

Dendrobium
la source
Tu veux connaître ma philosophie? "Si c'est bon marché, achète-le." Cela ne dit pas dans les spécifications que vous ne pouvez pas (encore) utiliser de fonctions intégrées, alors utilisez-les!
Mama Fun Roll
4

Python 3, 218 octets

La version illisible:

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"))

La version (plus) lisible:

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])]

En y allant un lambda à la fois:

Fonction carte P

P=lambda f,x:[f(_)for _ in x]
Un simple itérateur. Pas grand chose à dire ici.

Fonction Nest Y

Y=lambda f,x,z:Y(f,f(x),z-1)if z else x
Récursif jusqu'à ce qu'il atteigne zzéro, s'appliquant à fchaque fois. La clause if à la fin semble maladroite; il y a peut-être une meilleure façon de mettre fin à la récursivité.

Appliquer la fonction T

T=lambda f,x:f(*x)
Python a un bon opérateur d'expansion pour faire tout le gros du travail pour moi.

Fonction de gamme H

H=lambda f,x=0:(H(f-1)if~-f else[])+[f]
Celui-ci était plus difficile que ce à quoi je m'attendais. A fini par adopter une approche récursive. Encore une fois, la construction if-else prend beaucoup d'octets, et je pense qu'elle peut être améliorée. Pourquoi at-il un mannequin x=0, demandez-vous? C'est pour que lorsque je le comprime avec le exec, je puisse le remplacer =lambda f,xau lieu de juste =lambda f.

Fonction de pliage O

O=lambda f,x,z:O(f,f(x,z[0]),z[1:])if z else x
Assez content avec celui-ci. Élimine simplement le premier élément du tableau à chaque fois qu'il revient, jusqu'à ce qu'il ne reste plus rien.

Fonction de table N

N=lambda f,x:(N(f,[x[0],x[1]-1])if x[1]-x[0]else[])+[f(x[1])]
Celui-ci est horrible et je suis sûr qu'il y a place à amélioration. J'ai essayé d'utiliser les fonctions de plage et de carte précédemment définies pour une map(f,range(x,y))sorte de construction, mais sans grand succès. J'ai fini par faire une terrible approche récursive qui partage une certaine similitude avec la fonction de plage.

Tous les lambdas sont enveloppés dans un execavec un replacepour raccourcir considérablement le nombre d'octets.

Tryth
la source
J'étais sur le point de faire un commentaire qui [f(_)for _ in x]pourrait être raccourci map(f,x), mais je me suis alors souvenu du défi
Cyoce
4

Julia, 181 octets

Pas de bonus pour moi; J'ai utilisé des boucles généreusement. Désolé patron, mais les boucles de Julia sont efficaces!

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]]

L'ajout d'ellipses après un argument à une fonction casse un tableau, un tuple ou ce que vous avez en arguments de fonction réguliers. Sinon, la fonction pensera que vous essayez de passer un tableau (ou un tuple, etc.). Il n'a aucun effet pour les arguments uniques.

Noms des fonctions:

  • Carte: M
  • Nid: N
  • Appliquer: A
  • Gamme: R
  • Plier: F
  • Table: T
Alex A.
la source
4

tinylisp , 325 * 0,9 = 292,5

La langue est plus récente que la question, mais elle ne gagnera pas de toute façon.

(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))))

Définit les fonctions A(appliquer), M(carte), N(imbriquer), R(plage), T(table) et F(replier), ainsi que quelques fonctions d'assistance. Tattend une liste de deux entiers pour son deuxième argument.

Tinylisp n'a même aucune construction de boucle; tout est accompli en utilisant la récursivité. Plusieurs de ces fonctions ne sont pas récursives , donc si vous les appelez sur de grandes listes, elles feront probablement exploser la pile d'appels. Ils pourraient tous être implémentés avec une récursivité de queue ... mais cela prendrait plus d'octets, et c'est le code golf.

Voici une version étendue avec des espaces et de vrais mots pour les noms, qui devraient être assez lisibles si vous êtes familier avec Lisp. (J'ai alias la plupart des commandes internes de tinylisp à l'exception de q(citation) et i(si).)

(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)))

Plus d'explications disponibles sur demande.

Exemple de sortie

Utilise l'environnement REPL de mon implémentation de référence. J'ai utilisé q(quote) pour la fonction unaire et s(soustraire) comme fonction binaire pour ces exemples, ainsi que la fonction @(définie dans ce code) qui renvoie une liste de ses arguments.

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
DLosc
la source
2

Python 2.x: 450,6 octets (493 octets avant 10% de réduction)

Réponse golfée:

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

Cette question était amusante. J'ai décidé d'écrire mes fonctions sans utiliser les équivalents Python (bien que cela ait pu être une faille valide) et d'écrire les fonctions comme si Python supporte la récursivité de la queue. Pour que cela fonctionne, j'ai utilisé de nombreux paramètres facultatifs qui permettent aux appels requis de continuer à fonctionner.

Ci-dessous, j'ai des listes non golfées pour chaque fonction.

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

Notez que cette fonction nécessite que le passé functionpuisse représenter plusieurs arguments de manière variable. Une autre approche aurait consisté à faire en sorte que la fonction reçoive toujours une seule liste, mais cela aurait nécessité que les fonctions passées soient capables d'interpréter des listes d'arguments. Il y avait des hypothèses de toute façon, alors j'ai choisi celle qui convenait mieux au reste du système.

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

Voici un exemple de sortie utilisant les fonctions d'assistance suivantes:

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'
sadakatsu
la source
Wow, ça a l'air vraiment bien!
WizardOfMenlo
Cela semble être un sens asymétrique de l'esthétique; ) Je trouve toujours amusant de voir Python jouer au golf depuis que le premier livre sur Python que j'ai lu parlait de la façon dont Python renforce la lisibilité.
sadakatsu
J'ai en effet un sens asymétrique de l'esthétique :)
WizardOfMenlo
Je suis confus par les scores des autres. J'ai pris 10% du score de chacune des fonctions requises qui n'utilisaient pas de boucle (qui étaient toutes), mais d'autres personnes ont pris 10% du score total pour chaque fonction qui n'a pas utilisé de boucle (qui peut être jusqu'à 60% de réduction). Quelle est la bonne approche?
sadakatsu
La vôtre est la bonne façon de procéder, j'avais une attente irréaliste et donc au départ, j'avais en tête l'approche de 60%, mais maintenant je pense que les 10% seront plus stimulants et plus justes entre les deux
WizardOfMenlo
2

Ceylan, 370 * 0,9 = 333 364 * 0,9 = 327,4

La plupart de ces fonctions sont déjà disponibles dans le package de langue de Ceylan (bien que parfois avec une signature un peu différente), mais nous les définissons ici comme demandé dans la question.

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]])];

En fait, seules deux des fonctions ( tet f) utilisent réellement la récursivité (sur des listes et des entiers, respectivement), les autres sont basées sur celles-ci. (Appliquer est un peu aberrant, il n'a pas vraiment de rapport avec les autres.)

J'interprète "List" comme le type séquentiel de Ceylan, qui est une séquence d'éléments ordonnée (éventuellement vide) immuable. [R*]signifie Sequential<R>- pour une raison quelconque, nous pouvons également l'écrire R[], qui est un octet plus court.

Un type de fonction est Callable<R, A>, où Aest un type de tuple pour les arguments, comme [X, Y, Z](c'est-à-dire un sous-type de Anything[]). Comme raccourci, nous pouvons écrire à la R(X,Y,Z)place de Callable<R,[X,Y,Z]>.

J'Aliased Integerque Ide sauver quelques octets.

Voici une version formatée (et légèrement commentée):

// 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]])];

Utilisation de "boucles"

Table et Map peuvent être implémentés plus rapidement en utilisant des boucles (en fait, une compréhension de séquence):

// 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]);

Bien que je ne sais pas si l'utilisation de l' ..opérateur pour la plage d'entiers compte comme une fonction intégrée. Si cela est autorisé, le code résultant est le suivant, longueur 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]);

(Il pourrait être encore plus court en le définissant r(I i) => 1..i, ce qui donnerait le score 301. Bien que cela ressemble encore plus à de la triche.)

Si ..n'est pas autorisé, nous devrons l'implémenter à nouveau. Nous pouvons utiliser ces implémentations pour ret t(avec ce qui mprécède):

// 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]));

Cela donne 348 octets, mieux que la version complètement récursive, mais pas après avoir appliqué le bonus.

Paŭlo Ebermann
la source
0

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

PS Je ne sais pas ce que vous considérez comme une `` boucle '' dans ce contexte, je n'ai appliqué le bonus qu'après avoir été informé dans les commentaires par OP et je supprimerai si 2-3 utilisateurs supplémentaires disent ces fonctions de collecte et itérateurs sont des boucles et que je ne mérite pas le bonus. De plus, si vous voulez m'appeler sur mon utilisation de 1..it, faites-le et je vais le retravailler / mettre à jour mon bytecount.

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

Exemple d'entrée / sortie

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)

Production

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]

Essayez-le vous-même: https://groovyconsole.appspot.com/edit/5203951758606336

Urne de poulpe magique
la source
Techniquement, cela n'utilise pas de boucles, alors n'oubliez pas le bonus! Sinon, bonne réponse!
WizardOfMenlo
Techniquement pas de boucles?! Vraiment?! .chaque {} .times {} .collect {} sont des itérateurs.
Urne de poulpe magique du