Ваша компания только начинает работу над проектом, и вы впервые решили использовать стиль кода функционального программирования. Однако ваш начальник действительно неуверен в себе и не хочет использовать встроенные функции, а требует от вас реализации основных функций. В частности , вы должны написать функции: 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 , так что, если вам нужно больше руководств, отправляйтесь туда. Обратите внимание, что вам не нужно будет реализовывать все версии функций, показанных на этой странице, а только те, которые написаны в этом посте.
Стандартные лазейки запрещены как обычно.
Если ваш язык не позволяет передавать функции в качестве аргументов, вам необходимо реализовать эту возможность и добавить ее в свой ответ. Однако количество байтов этой операции не будет добавлено к итогу.
Это кодовый гольф, поэтому выигрывает самый короткий код. Удачи!!!
источник
Table
здесь работает. Ваш пример должен бытьTable(f, {x, 0, 5})
? Я также не понимаю целиx
, так как она просто применяет функцию к диапазону.Ответы:
Haskell,
много предыдущих байтов насчитывает127 * 0,9 = 114,3 байтаНикаких петель, только рекурсия.
#
это карта:(*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]
По просьбе разглаженной версии с комментариями. Обратите внимание,
&
и?
это троичные инфиксные операторы, которые требуют дополнительных скобок при вызове или сопоставлении с шаблоном.Спасибо @dfeuer и @Zgarb за полезные советы
источник
m#q=reverse$f((:).m)[]q
. Это такая же длина, как у вас, но намного сложнее для чтения.!
, сделав его имя вместо оператора:i f=f
.Python 2, 305,1 байта (-10%
376369366349339 байтов)Когда развернуто, эквивалентно:
Никаких петель!
Ну, это делает много,
eval
и если ваш босс не может стоять на петлях, то они будут ненавидеть Eval. Но им придется смириться с этимСпособ делать
range
лямбду очень важен, поэтому мне не нужно выполнять никаких функций (Shudder.).Пояснения:
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["+
г (LEN (а))[1:-1].replace(",","-1],a[")+"-1])")
a
. Извращает это!f=lambda f,x,l:eval("f("*len(l)+"x,["+
г (LEN (л))[1:-1].replace(",","-1]),l[")+"-1])")
t=lambda f,n,x:eval("[f("+
г (х) [п-1:].replace(",","),f(")[1:-1]+")]")
Карта, гнездо, дальность, применить, сложить, таблица.
Спасибо @Zgarb за лямбду за диапазон!
источник
r=lambda i:[]if i<1 else r(i-1)+[i]
? Никаких петель, только рекурсия.eval
чтобы показать им, что петли не так уж и плохи :)e=eval
:r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
Javascript ES6, 197 * 0,9 = 177,3 байта
Карта (
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]:[]
):Concat
n
к рекурсивному вызову Range, пока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
), затем использует Range для построения таблицы значений от iMin до iMax.f
Затем применяется к таблице с помощью Map, и результат возвращается.источник
Python 3, 218 байт
Нечитаемая версия:
(Более) читаемая версия:
Пройдя по одной лямбде за раз:
Функция карты
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]
Этот был сложнее, чем я ожидал. Закончилось рекурсивным подходом. Опять же, конструкция if-else занимает много байтов, и я чувствую, что ее можно улучшить.
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
a,replace
чтобы значительно сократить количество байтов.источник
[f(_)for _ in x]
можно сократить доmap(f,x)
, но потом я вспомнил, что это был за вызовЮлия, 181 байт
Нет бонуса для меня; Я использовал петли свободно. Извините босс, но петли в Юлии эффективны!
Добавление эллипсов после аргумента в функцию разбивает массив, кортеж или что-то еще на обычные аргументы функции. В противном случае функция будет думать, что вы пытаетесь передать массив (или кортеж и т. Д.). Это не влияет на отдельные аргументы.
Имена функций:
M
N
A
R
F
T
источник
тинилисп , 325 * 0,9 = 292,5
Язык новее, чем вопрос, но он все равно не победит.
Определяет функции
A
(применить),M
(карта),N
(гнездо),R
(диапазон),T
(таблица) иF
(сложить), а также несколько вспомогательных функций.T
ожидает список из двух целых чисел для своего второго аргумента.Тинилисп даже не имеет петлевых конструкций; все выполняется с помощью рекурсии. Некоторые из этих функций не являются хвостово-рекурсивными , поэтому, если вы вызываете их в больших списках, они, вероятно, сорвут стек вызовов. Все они могут быть реализованы с помощью хвостовой рекурсии ... но это заняло бы больше байтов, и это кодовый гольф.
Вот расширенная версия с пробелами и реальными словами для имен, которая должна быть довольно удобочитаемой, если вы знакомы с Lisp. (Я присвоил псевдоним большинству встроенных тинилиспов, за исключением
q
(цитата) иi
(если).)Дальнейшее объяснение доступно по запросу.
Образец вывода
Использует среду REPL из моей эталонной реализации. Я использовал
q
(цитата) для унарной функции иs
(вычитание) в качестве двоичной функции для этих примеров, а также функцию@
(определенную в этом коде), которая возвращает список ее аргументов.источник
Python 2.x: 450,6 байта (493 байта до 10% скидки)
Гольф ответ:
Этот вопрос был веселым. Я решил написать свои функции без использования эквивалентов Python (хотя это могло быть допустимой лазейкой) и написать функции, как будто Python поддерживает хвостовую рекурсию. Чтобы заставить это работать, я использовал много дополнительных параметров, которые позволяют требуемым вызовам все еще работать.
Ниже приведены списки для каждой функции.
Apply
:Map
:Nest
:Обратите внимание, что эта функция требует, чтобы передаваемый
function
элемент мог представлять несколько аргументов по-разному. Другой подход состоял бы в том, чтобы обеспечить, чтобы функция всегда получала один список, но для этого требовалось, чтобы переданные функции могли интерпретировать списки аргументов. В любом случае были предположения, поэтому я выбрал тот, который лучше соответствует остальной системе.Range
:Fold
:Table
:Вот пример вывода с использованием следующих вспомогательных функций:
источник
Цейлон,
370 * 0,9 = 333364 * 0,9 = 327,4Большинство из этих функций уже доступны в языковом пакете Цейлона (хотя иногда и с немного другой сигнатурой), но мы определяем их здесь, как указано в вопросе.
На самом деле только две функции (
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
для сохранения некоторых байт.Вот отформатированная (и слегка прокомментированная) версия:
Используя "петли"
Таблица и Карта могут быть реализованы короче, используя циклы (на самом деле, понимание последовательности):
Хотя я не уверен, считается ли использование
..
оператора для целочисленного диапазона встроенной функцией. Если это разрешено, результирующий код будет таким, длина 312:(Это можно сделать еще короче, определив
r(I i) => 1..i
результат, получив 301 балл. Хотя это больше похоже на обман.)Если
..
не разрешено, мы должны будем реализовать это снова. Мы можем использовать эти реализации дляr
иt
(сm
выше):В результате получается 348 байт, что лучше, чем полностью рекурсивная версия, но не после применения бонуса.
источник
Groovy (146 байт) (146 * 90% = 131,4)
PS Я не знаю, что вы рассматриваете как «цикл» в этом контексте, я применил бонус только после того, как мне сказали в комментариях OP и удалит, если 2-3 дополнительных пользователя скажут эти функции сбора и итераторы это петли и что я не заслуживаю бонуса. Кроме того, если вы хотите позвонить мне по поводу моего использования 1..it, пожалуйста, сделайте это, и я переработаю его / обновлю свой bytecount.
Пример ввода / вывода
Выход
Попробуйте сами: https://groovyconsole.appspot.com/edit/5203951758606336
источник