У Haskell есть кортежи, которые можно записать как
(a,b,c)
Однако это просто синтаксический сахар для
(,,)a b c
В общем случае n- кортеж может быть сформирован с n-1 ,
s между (
..., )
за которым следуют его элементы, разделенные пробелами. Например, 7-кортеж, (1,2,3,4,5,6,7)
может быть сформирован
(,,,,,,)1 2 3 4 5 6 7
Поскольку в Haskell нет 1-кортежей, они не могут быть сформированы. Вы также не будете нести ответственность за пустые кортежи.
Вложенные кортежи могут быть сформированы с помощью паренов, чтобы переопределить порядок операций.
((1,2),3) == (,)((,)1 2)3
В рамках нашего стремления удалить весь синтаксический сахар из Haskell, я попрошу вас написать программу, которая также удаляет синтаксический сахар из кортежей Haskell.
Ваша программа должна принимать кортеж, массив или строку, представляющую сахарный кортеж, и выводить строку, представляющую кортеж «без сахара». Входные кортежи будут содержать только натуральные числа или другие кортежи.
Так как мы здесь играем в гольф, ваш результат должен быть коротким. Не должно содержать ненужных
Пространства. Пробелы должны использоваться только для разделения аргументов функций кортежа и не должны появляться после
)
или перед(
Круглые скобки. Скобки следует использовать только при формировании функций кортежей или при вложении кортежей.
Это вопрос кода игры в гольф, поэтому ответы будут оцениваться в байтах, причем меньше байтов будет лучше.
Контрольные примеры
(1,2) -> (,)1 2
(1,2,3) -> (,,)1 2 3
((1,2),3) -> (,)((,)1 2)3
(1,2,3,4) -> (,,,)1 2 3 4
(1,(2,3)) -> (,)1((,)2 3)
(10,1) -> (,)10 1
,
((1,(2,3)),4,(5,6))
и(1,(2,3),4)
.Ответы:
Haskell ,
169148 байтПопробуйте онлайн! Принимает кортеж как строку.
init.tail.fst.([]%)
это анонимная основная функция. Привязать его к напримерf
и использовать какf "(3,(14,1),4,7)"
, что дает"(,,,)3((,)14 1)4 7"
.Вы спрашиваете, почему вход не представлен как кортеж Haskell? Поскольку Haskell строго типизирован, кортеж
(1,2)
имеет тип(Int,Int)
1, а кортеж(1,(2,3))
имеет тип(Int,(Int,Int))
. Таким образом, функция, которая принимает кортежи первого типа, не может быть применена ко второму типу, и, в особенности, не может быть функции, которая принимает произвольный кортеж 2 .Объяснение:
p:k="(,"
короткий путь , чтобы назначитьp
на'('
иk
на","
.(%)
является рекурсивной функцией анализа и преобразования. Первый аргумент - это список уже проанализированных записей кортежа, второй аргумент - остаток исходной строки. Каждый вызов возвращает кортеж текущего преобразованного кортежа (в виде строки и заключенного в скобки) и остаток строки.l%('(':r)
Если строка начинается с открывающей скобки, нам нужно проанализировать новую запись кортежа.(y,x:s)<-[]%r
Мы рекурсивно применяем%
и получаем запись кортежа,y
а оставшаяся строка разбивается на следующий символx
и остальную часть строкиs
.m<-y:l
Мы добавляем новую записьy
в текущий список уже найденных записейl
и вызываем результатm
.x
теперь является запятой,
или закрывающей скобкой)
. Этоlast$ <B> :[ <A> |x<',']
просто более короткий способ написанияif x == ')' then <A> else <B>
.,
следующее, нам нужно рекурсивно проанализировать следующую запись:m%(p:s)
мы добавляем открывающую скобку, чтобы оказаться в правильном регистре и пропустить список уже найденных записейm
.x == ')'
, мы закончили текущий кортеж и должны выполнить требуемое преобразование:(p:p:(l>>k)++x:foldl(\r x->x++[' '|x>k,r>k]++r)[x]m,s)
p:p:(l>>k)++x:
Если мы обнаружили , п записи, тоm
есть п элементов иy
, список , прежде чем добавить самый последний найденный элемент, имеет п-1 записей. Это очень удобно, так как нам нужен n-1,
дляn
кортежа элемента, и онl>>k
работает со списками как «объединяет списокk
с самим собой столько раз, сколькоy
имеет элементы» . Таким образом, эта первая часть дает строку вроде"((,,,)"
.foldl(\r x->x++[' '|x>k,r>k]++r)[x]m
объединяет элементыm
(в обратном порядке, потому что путем добавления новых записей кm
самому фронту был построен в обратном порядке), добавляя только пробелы между двумя элементами, если они оба являются числами:[' '|x>k,r>k]
мы проверяем, являются ли текущие записиx
иr
являются числами, путем лексикографического сравнения их","
- если они не являются числами, они уже являются представлением кортежа, заключенным в скобки, и'(' < ','
содержат их.l%('(':r)
в самом начале не удастся, то мы в конечном итоге на последней строке:l%r=lex r!!0
. Это означает, что нам нужно проанализировать число и вернуть число и остаток строки. К счастью, естьlex
функция, которая делает именно это (она анализирует следующий действительный токен Haskell, а не только числа). Однако полученный кортеж обернут в список, поэтому мы используем,!!0
чтобы получить первый элемент списка.init.tail.fst.([]%)
является основной функцией, которая принимает строку и применяет%
к ней пустой список. Например, для ввода"(1,2)"
, применяя([]%)
выходы("((,)1 2)","")
, поэтому внешний кортеж и скобки должны быть удалены.fst
получает первый элемент кортежа,tail
удаляет закрывающую скобку иinit
открывающую.Редактировать: Большое спасибо @ Örjan Johansen за гольф в общей сложности 21 байт !
1 На самом деле тип (Num t1, Num t) => (t, t1) , но это другая история.
2 Игнорирование полиморфных функций, таких как id , которые фактически не могут работать с их вводом.
источник
Desugarable
, но один должен был бы заявить о случаях дляInt
и всех типов кортежей.g
может быть сокращено доfoldr1(\x r->x++[' '|x>k,r>k]++r)
и встроено.show (1,2,3,4,5,6,7,8,9,0,1,2,3,4,5)
в GHCi, затем добавьте a,6
в конце и попробуйте снова.)m<-y:l
, сверните влево вместо правого и используйте в[x]
качестве начального значения. Попробуйте онлайн!f
может быть анонимным:init.tail.fst.([]%)
.Haskell,
141 байт138 байт (спасибо Эрджану Йохансену)f
имеет типExp -> String
.Входные данные: шаблонная версия Haskell
Exp
(т. Е. Стандартное представление AST значений Haskell произвольного типа - в основном, анализ кода Haskell перед проверкой типа); должен представлять кортеж, содержащий только неотрицательные целые числа и другие подобные кортежи.Выход: строка, содержащая синтаксис desugared для этого выражения кортежа.
Демо-версия:
источник
")"++
его')':
в двух местах и сэкономить место послеtail
, переместив его за пределы скобок.Haskell , 119 байт
Попробуйте онлайн! Это использует пользовательский тип данных
T
для представления кортежей, то есть кортеж((1,2),3)
представляется какU[U[I 1,I 2],I 3]
. Пример использования:init.tail.f $ U[U[I 1,I 2],I 3]
доходность(,)((,)1 2)3
.источник
Python 2 , 110 байт
Попробуйте онлайн!
Принимает
tuple
.источник
GNU sed,
14982 + 2 = 84 байта+2 байта за
-r
флаг.Попробуйте онлайн!
объяснение
источник
((1,(2,3)),4,(5,6))
и(1,(2,3),4)
.JavaScript, 75 байт
Входной массив номера | массив, выходная строка.
Благодаря Нилу, сэкономьте 2 байта
источник
(1/t?' ':0)+v
может быть1/t?' '+v:v
.Mathematica, 94 байта
Содержит непечатную
U+F4A1
, встроеннуюFunction
функцию.Принимает
List
целое числоString
s. Если это не разрешено, это может быть исправлено путем добавления еще 10 байт (эта версия занимаетList
отList
s /Integer
s):источник
Пип , 45 байт
Это функция, которая принимает список в качестве аргумента. Попробуйте онлайн!
Комментируемая версия
источник
JavaScript (ES6),
8884 байтаПринимает массив целых чисел и массивов. Редактировать: 1 байт сохранен с использованием
s+=
вместо двух отдельныхs+
. Сохранено еще 3 байта теперь, когда я могу упростить внутреннюю троицу. Если я украду идеи @ tsh, то смогу уменьшить их до 76 байт:источник
Your program should take either a tuple or a string representing a sugary tuple
Я бы предположил, что массив массивов / целых чисел должен быть в порядке.R, 316 байт?
(Нужно выходить на улицу и не знать, как правильно считать байты ... плюс, это не очень хорошее решение, но я хотел опубликовать его, так как я потратил время на его создание ...)
Тестовые случаи:
источник
JavaScript (ES6), 72 байта
Ввод: массив, содержащий числа и / или массивы
Вывод: строка
Использование: f ([...])
Завершает все тестовые случаи, улучшения приветствуются
источник
C, 308 или 339 байтов
308 или 339 байт, в зависимости от того, разрешен или нет указатель на конец входной строки; последняя строка предназначена только для прямой передачи строкового литерала без вычисления его длины.
объяснение
Довольно простой алгоритм. Он подсчитывает количество запятых на текущей глубине, печатает их как конструктор кортежа, затем рекурсивно проверяет аргументы кортежа (пробелы между числами, вложенные кортежи между скобками).
Тестовые случаи и применение
источник