Реалізувати функціональні парадигми програмування


21

Ваша компанія тільки починає працювати над проектом, і ви вперше вирішили скористатися функціональним кодом в стилі програмування. Однак ваш начальник справді невпевнено і не хоче використовувати вбудовані функції, і вимагає від вас реалізувати основні функції. Зокрема , ви повинні написати функції: Map, Nest, Apply, Range, FoldіTable на мові , на ваш вибір. Бос - справді зайнята людина, і він хоче, щоб програми були якомога коротшими, тому він не витрачав час на читання. Він також хотів би, щоб ви не використовували цикли, тому у вас буде 10% зменшення кількості байтів за не використання циклів.

Детальні вимоги до функцій наведені нижче:

Карта

MapФункція приймає два параметри: fі , listде fфункція і listсписок значень. Він повинен повернути fзастосований до кожного елемента list. Тому вона працюватиме як така:

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

повертає

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

і

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

повертає

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

Гніздо

NestФункція приймає три параметри, а: f, arg, timesде fє функція, argє його початком аргументу, і timesскільки разів застосовуються функція. Він повинен повертати вираз із fзастосованими timesчасом до arg. Тому вона працюватиме як така:

Nest(f, x, 3)

повертає

f(f(f(x)))

і

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

повертає

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

Застосувати

ApplyФункція приймає два параметри: fі , argsде fфункція і argsсписок. Це має застосовуватися fдо args. Тому:

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

повертає

f(a,b,c)

Дальність

RangeФункція приймає одне ціле число rі виводить цілі числа до цього числа. Тому:

Range(5)

повертає

{ 1, 2, 3, 4, 5}

Складіть

FoldФункція приймає три параметри f, arg, othersде fє функція, argпросто параметр, і othersсписок. Він працюватиме як такий:

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

повертає

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

Таблиця

Функції таблиці повинні приймати функцію fта параметр, який називається iteratorу формі: {iMin, iMax}де iMinта iMaxє цілими числами. Ви повинні подати заявку fпонад вказаний діапазон. Тому:

Table(f, {0, 5})

повертає

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

Я використовував визначення цих функцій на сторінці функціонального програмування Mathematica , тому зверніться туди, якщо вам потрібні ще вказівки. Зауважте, що вам не потрібно буде реалізовувати всі версії функцій, показаних на цій сторінці, а лише ті, що написані в цій публікації.

Стандартні лазівки заборонено, як зазвичай.

Якщо ваша мова не дозволяє передавати функції як аргументи, вам потрібно реалізувати цю можливість та додати її у свою відповідь. Однак кількість байтів цієї операції не буде додано до загальної суми.

Це кодовий гольф, тому найкоротший код виграє. Удачі!!!


Це круто! +1 Однак я не дуже розумію, як Tableпрацює тут. Ваш приклад повинен бути Table(f, {x, 0, 5})? Я також зовсім не отримую мету x, оскільки вона просто застосовує функцію до діапазону.
kirbyfan64sos

@ kirbyfan64sos Дякую! Так, це був друкарський помилок, я залишив x у якості посилання на математику, яка використовує це як символічну особливість, проте, я думаю, я можу це вийти
WizardOfMenlo

Ще одне питання: як ми називаємо функції? Чи мусимо ми давати їм абсолютно однакові імена? Однолітерний?
kirbyfan64sos

@ kirbyfan64sos Оскільки це код-гольф, я дозволю назви з однієї літери, проте у вашій відповіді поставте заголовок над кожною функцією, щоб ми знали, що це. Також не використовуйте зіштовхувальні листи.
WizardOfMenlo

Чи можете ви бути більш конкретними щодо того, що вважається циклом?
xnor

Відповіді:


9

Haskell, багато попередніх байт нараховує 127 * 0,9 = 114,3 байт

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)

Ніяких циклів, просто рекурсія.

#це карта: (*2) # [1,2,3]->[2,4,6]

&є гніздо: ((*2) & 3) 4->48

iзастосовується: i (*2) 7->14

rє діапазон: r 4->[1,2,3,4]

?складаємо: ((+) ? 0) [1,2,3,4]->10

%є таблиця: (*2) % (2,4)->[4,6,8]

За запитом незворушена версія з коментарями. Зауважте, &і ?вони є потрійними операторами фіксації, які потребують додаткових дужок, коли викликаються або узгоджуються зразком.

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

Дякуємо @dfeuer та @ Zgarb за деякі корисні підказки


Я новачок у haskell, він виглядає досить непогано, проте ви можете, будь ласка, додати пояснення до того, що ви робите?
WizardOfMenlo

1
@WizardOfMenlo: додав кілька коментарів
nimi

Тільки що зрозумів, наскільки елегантний Haskell, справді добре!
WizardOfMenlo

1
Чи не звертаючи уваги на нескінченні списки і ефективність m#q=reverse$f((:).m)[]q. Це така ж довжина, як і ваша, але читати набагато складніше.
dfeuer

Ви можете скоротити !, зробивши його ім'я замість оператора: i f=f.
dfeuer

5

Python 2, 305,1 байт (-10% 376 369 366 349 339 байт)

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

При розширенні еквівалентно:

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

Ніяких петель!

Що ж, це робить дуже багато, evalі якщо ваш начальник не витримає циклів, вони ненавиджу ненависть. Але їм доведеться миритися з цим

Оцінений спосіб зробити rangeлямбда, тому мені не потрібно виконувати жодних функцій (здригання.).

Пояснення:

  • m=lambda f,l:eval("["+"f(l.pop()),"*len(l)+"][::-1]")
    • Створіть рядок, який спливає елементи зі списку, загорніть його у список, переверніть його та нарешті зрівняйте!
  • n=lambda f,x,l:eval("f("*l+"*x"+")"*l)
    • Вручну створіть рядок за допомогою гніздування, і підніміть її!
  • r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
    • Створіть рядок, який під час evalредагування повертає [0]або використовує рекурсію для отримання попередніх результатів і додає поточний індекс до списку. Оцінює це.
  • a=lambda f,a:eval("f(a["+r (len (a))[1:-1].replace(",","-1],a[")+"-1])")
    • Використовує функцію діапазону, щоб отримати індекси 1-лена (список). Заміняє коси у списку, закреслені способом отримання правильного індексу списку a. Овалює це!
  • f=lambda f,x,l:eval("f("*len(l)+"x,["+r (len (l))[1:-1].replace(",","-1]),l[")+"-1])")
    • Те саме, що застосовується, за винятком того, що замінює коми закритими дужками, коми і починаючи індекс списку.
  • t=lambda f,n,x:eval("[f("+r (x) [n-1:].replace(",","),f(")[1:-1]+")]")
    • Те саме, що застосувати та скласти, за винятком заміни закінченням функції та викликом нової. Овалює це!

Карта, гніздо, діапазон, застосувати, скласти, таблицю.

Дякую @Zgarb за лямбда за асортимент!


У мого начальника буде голова на його столі :) Чи можете ви також додати коротке пояснення?
WizardOfMenlo

Як щодо r=lambda i:[]if i<1 else r(i-1)+[i]? Ніяких циклів, лише рекурсія.
Згарб

1
Звичайно, я візьму це на даний момент, але начальнику потрібно більше, evalщоб показати їм, як петлі не такі вже й погані :)
Blue

Га! Інша версія з використанням e=eval:r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
Zgarb

ви можете змінити його з 60% бонусу на 10% будь ласка? Я переглянув специфікацію питання, щоб зробити його справедливішим
WizardOfMenlo

5

Javascript ES6, 197 * 0,9 = 177,3 байт

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

Карта ( M=(f,l)=>F((a,b)=>[...a,f(b)],[],l)):

Використовуйте Fold, щоб сформулювати результати, fзастосовані до кожного учасника у lпорожньому списку. Використання вбудованих функцій зводить це до M=(f,l)=>l.map(f)(не використовував, тому що це здається дешевим ...?).

Гніздо ( N=(f,x,n)=>f(--n?N(f,x,n):x)):

Застосовувати fрекурсивно, поки nне зменшиться до 0.

Застосувати ( A=(f,l)=>f(...l)):

Використовує ...оператор спред ( ) для подання lна нього f.

Дальність (R=n=>n--?[...R(n),n+1]:[] ):

Повторіть nрекурсивний виклик діапазону, поки він nне зменшиться до 0.

Складіть ( F=(f,x,l,n=l.length)=>n--?f(F(f,x,l,n),l[n]):x):

Застосовує рекурсивний виклик Fold і n'-го елемента lдо fдо nзменшується до 0. Використання вбудованих функцій зводить це до F=(f,x,l)=>l.reduce(f,x)(знову здається, дешевим ...).

Таблиця (T=(f,i)=>([n,x]=i,M(q=>f(q+n-1),R(x-n+1))) ):

Перші инициализирует nі xдо Imin і Imax , використовуючи DESTRUCTURING ( [n,x]=i), а потім використовує діапазон побудувати таблицю значень з Imin до Imax. fпотім застосовується над таблицею за допомогою Map, і результат повертається.


Хочете знати мою філософію? "Якщо це дешево, купіть його". У специфікаціях не сказано, що ви не можете використовувати вбудовані (поки), тому використовуйте їх!
Mama Fun Roll

4

Python 3, 218 байт

Нечитабельна версія:

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

(Більш) читана версія:

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

Хоча хоч це одна лямбда за один раз:

Функція карти P

P=lambda f,x:[f(_)for _ in x]
Просто простий ітератор. Тут мало що сказати.

Функція гнізда Y

Y=lambda f,x,z:Y(f,f(x),z-1)if z else x
Повторюється, поки не потрапить до zнуля, застосовуючиf кожен раз. Застереження if в кінці відчуває незграбність; можливо, є кращий спосіб припинити рекурсію.

Застосувати функцію T

T=lambda f,x:f(*x)
У Python є чудовий оператор розширення, який виконує всі важкі підйоми для мене.

Функція діапазону H

H=lambda f,x=0:(H(f-1)if~-f else[])+[f]
Цей був важче, ніж я очікував. Закінчився з рекурсивним підходом. Знову ж таки, якщо інша конструкція займає багато байт, і я вважаю, що її можна вдосконалити. Чому у нього пустушка x=0, запитаєте ви? Це так, що коли я стискаю його з exec, я можу замінити, =lambda f,xа не просто =lambda f.

Функція складання O

O=lambda f,x,z:O(f,f(x,z[0]),z[1:])if z else x
Досить задоволений цим. Просто вимикайте перший елемент масиву кожен раз, коли він повторюється, поки нічого не залишиться.

Функція таблиці N

N=lambda f,x:(N(f,[x[0],x[1]-1])if x[1]-x[0]else[])+[f(x[1])]
Це жахливо, і я впевнений, що є місце для вдосконалення. Намагався використовувати функції діапазону та карти, визначені раніше для свого map(f,range(x,y))роду конструкції, але без особливого успіху. Закінчив робити страшне рекурсивний підхід, який поділяє деяку схожість з функцією діапазону.

Всі лямбдахи загорнуті в execа, replaceщоб значно скоротити кількість байтів.


Я збирався прокоментувати, що [f(_)for _ in x]можна було б скоротити map(f,x), але тоді я згадав, у чому полягає проблема
Cyoce

4

Юлія, 181 байт

Для мене немає бонусу; Я використовував петлі вільно. Вибачте начальнику, але петлі в Джулії ефективні!

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

Додавання еліпсів після аргументу до функції розбиває масив, кортеж або те, що є у вас, у звичайні аргументи функції. Інакше функція подумає, що ви намагаєтеся передати масив (або кортеж тощо). Це не впливає на окремі аргументи.

Назви функцій:

  • Карта: M
  • Гніздо: N
  • Застосувати: A
  • Діапазон: R
  • Складіть: F
  • Таблиця: T

4

тинілісп , 325 * 0,9 = 292,5

Мова новітня, ніж питання, але все одно перемогти не збирається.

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

Визначає функції A(застосувати), M(карта), N(гніздо), R(діапазон), T(таблиця) та F(скласти) разом з парою допоміжних функцій.Tочікує список двох цілих чисел для другого аргументу.

Tinylisp навіть не має певних конструкцій; все здійснюється за допомогою рекурсії. Деякі з цих функцій не є рекурсивними , тому, якщо ви будете викликати їх у великих списках, вони, ймовірно, підірвуть стек викликів. Всі вони могли бути реалізовані з хвостовою рекурсією ... але це займе більше байтів, і це кодовий гольф.

Ось розширена версія з пробілами та реальними словами для імен, які повинні бути досить читабельними, якщо ви знайомі з Lisp. (Я відчув більшість вбудованих тінілісп, за винятком q(цитата) та i(якщо).)

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

Подальше пояснення надається на запит.

Вибірка зразка

Використовує середовище REPL з моєї базової реалізації. Я використовував q(цитата) для функції unry та s(віднімання) як бінарну функцію для цих прикладів, а також функцію @(визначену в цьому коді), яка повертає список її аргументів.

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 байт (493 байти до знижки 10%)

Відповідь на гольф:

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

Це питання було веселим. Я вирішив написати свої функції, не використовуючи еквівалентів Python (хоча це, можливо, була дійсною лазівкою) і записати функції так, ніби Python підтримує хвостову рекурсію. Щоб зробити цю роботу, я використав безліч додаткових параметрів, які дозволяють потрібним дзвінкам все ще працювати.

Нижче я маю списки для неробочого переліку для кожної функції.

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

Зауважте, що ця функція вимагає, щоб переданий functionміг представляти кілька аргументів по-різному. Іншим підходом було б встановлення того, що функція завжди отримувала єдиний список, але це вимагало б, щоб передані функції могли інтерпретувати списки аргументів. Були припущення в будь-якому випадку, тож я вибрав той, який краще відповідає решті системи.

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

Ось зразок виводу з використанням таких допоміжних функцій:

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'

Ого, виглядає дуже добре!
WizardOfMenlo

Це здається перекошеним естетичним почуттям; ) Мені завжди цікаво бачити гольф Python з моменту першої книги про Python, яку я прочитав, розповідав про те, як Python забезпечує читання.
sadakatsu

У мене справді перекошене почуття естетики :)
WizardOfMenlo

Мене бентежать оцінки інших людей. Я взяв 10% балу кожної з необхідних функцій, які не використовували цикл (який був у них усіх), але інші люди брали 10% від усієї оцінки за кожну функцію, яка не використовувала цикл (що може бути до 60% знижки). Який правильний підхід?
садакацу

З вами - це правильний шлях, я очікував нереально, тому спочатку я мав на увазі підхід на 60%, але зараз я думаю, що 10% будуть більш стимулюючими і більш жорсткими між ними
WizardOfMenlo

2

Цейлон, 370 * 0,9 = 333 364 * 0,9 = 327,4

Більшість цих функцій вже доступні в мовному пакеті Цейлону (хоча іноді і з дещо іншим підписом), але ми визначаємо їх тут, як просили у питанні.

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

Насправді лише дві функції ( tі f) фактично використовують рекурсію (над списками та цілими числами відповідно), інші засновані на них. (Застосовувати це трохи чуже, це насправді не стосується інших.)

Я трактую "Список" як тип послідовного Цейлону, який є незмінною упорядкованою (можливо, порожньою) послідовністю елементів. [R*]означає Sequential<R>- чомусь ми можемо також записати його R[], що на один байт коротше.

Тип функції Callable<R, A>, де Aтип кортежу для аргументів, як [X, Y, Z](тобто деякого підтипу Anything[]). Як ярлик ми можемо писати R(X,Y,Z)замість Callable<R,[X,Y,Z]>.

Я псевдонім Integer, Iщоб зберегти кілька байт.

Ось відформатована (та злегка коментована) версія:

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

Використання "циклів"

Таблиця та карта можуть бути реалізовані коротше за допомогою циклів (власне, розуміння послідовності):

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

Хоча я не впевнений, чи буде використання .. оператора для цілого діапазону вважається використанням вбудованої функції. Якщо це дозволено, отриманий код такий тут, довжина 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]);

(Це може бути ще коротше, визначившись r(I i) => 1..i, в результаті чого вийде оцінка 301. Хоча це навіть більше нагадує обман.)

Якщо ..це не дозволено, нам доведеться реалізувати його ще раз. Ми можемо використовувати ці реалізації для rта tmвищезазначеним):

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

Це призводить до отримання 348 байт, що краще, ніж повністю рекурсивна версія, але не після застосування бонусу.


0

Groovy (146 байт) (146 * 90% = 131,4)

PS Я не знаю, що ви розглядаєте як "цикл" у цьому контексті, я застосував бонус лише після того, як мені сказали в коментарях ОП, і видаляю, якщо 2-3 додаткові користувачі скажуть ці функції збору та ітератори це петлі, і що я не заслуговую премії. Крім того, якщо ви хочете зателефонувати мені на використання 1..it, будь ласка, зробіть це, і я перероблю його / оновлю свій обліковий запис.

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

Приклад введення / виводу

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)

Вихідні дані

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]

Спробуйте самі: https://groovyconsole.appspot.com/edit/5203951758606336


Це технічно не використовує циклів, тому пам’ятайте про бонус! Ще, чудова відповідь!
WizardOfMenlo

Технічно немає петель ?! Дійсно ?! .each {}. times {} .collect {} - ітератори.
Чарівна урва восьминога
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.