Советы по игре в гольф в Clean


17

Какие общие советы у вас есть для игры в гольф в Clean? Пожалуйста, публикуйте только идеи, которые могут быть применены к кодовым проблемам гольфа в целом, и, по крайней мере, несколько специфичны для Clean.

Если вы никогда не слышали о Чистоте, вы можете узнать больше здесь .
Или вы можете присоединиться к чату .

Ответы:


10

Избегайте, import StdEnvкогда это возможно

Чтобы получить доступ к встроенным функциям, даже , казалось бы , основные из них , как (==)и map, требуется оператор импорта, как правило , import StdEnvпотому , что она импортирует наиболее распространенные модули , как StdInt, StdBoolи так далее (см здесь для получения дополнительной информации о StdEnv).

Однако может быть возможно избежать этого импорта для некоторых проблем и просто использовать основные функции языка, такие как понимание списка и сопоставление с образцом.

Например, вместо

import StdEnv 
map f list

можно написать

[f x\\x<-list]

Список альтернатив:

Некоторые функции или вызовы функций, которые нуждаются import StdEnv, альтернатива, которая не требует импорта, и приблизительная оценка сохраненных байтов.

  • hd-> (\[h:_]=h)~ 6 байт
  • tl-> (\[_:t]=t)~ 6 байт
  • map f list-> [f x\\x<-list]~ 10 байт
  • filter p list-> [x\\x<-list|p x]~ 11 байт
  • (&&)-> %a b|a=b=a;%~ 6 байт
  • (||)-> %a b|a=a=b;%~ 6 байт
  • not-> %a|a=False=True;%~ 1 байт
  • and-> %[a:r]|a= %r=a;%_=True~ 0 байт
  • or-> %[a:r]|a=a= %r;%_=False~ 0 байт

Последние несколько вряд ли на самом деле сохранят байты, потому что прямая замена дает больше байтов, чем импорт, но это может быть возможно в тех случаях, когда рекурсия по списку необходима в любом случае.

Этот совет был успешно использован здесь .


Разве import StdEnv+ a and b(21 байт) не меньше %[a:r]|a= %r=a;%_=True(22 байт)? Или это будет import StdEnv+ a=True and b=True(31 байт), и в этом случае он действительно определенно будет короче? (
Между

@KevinCruijssen Мы только что обсуждали это в чате . Это правда, что они вряд ли сохранят байты, за исключением, может быть, когда программе все равно нужно пересмотреть список.
Лайкони

4
Ах хорошо. Возможно, было бы также полезно указать, сколько байтов сохранено с альтернативой (то есть map f list -> [f x\\x<-list] (11 bytes saved)(или что-то подобное)).
Кевин Круйссен

@KevinCruijssen Готово.
Лайкони

5

Знать, как выучить язык

В конце концов, как любой может играть в гольф на языке, который они не могут использовать!

В сети

Чистый язык не является общеизвестным или хорошо документированным языком, и название определенно не облегчает поиск столь необходимых ресурсов для устранения этих проблем ... или так?

Первоначально Clean назывался Concurrent Clean , который до сих пор используется в предисловии почти к каждому документу, связанному с Clean, поэтому, если вы ищете Clean, вместо этого ищите Concurrent Clean.

Одним из наиболее примечательных сходств Clean с Haskell (из которых их много) является существование Cloogle , функции поисковой системы, охватывающей библиотеки, с которыми поставляется Clean.

в местном масштабе

Библиотеки, с которыми поставляется Clean, представлены в виде прилично прокомментированных, несколько самодокументированных исходных файлов Clean, которые можно просматривать с помощью IDE.
(Это также идет с полными примерами программ, под $INSTALL/Examples.)

Говоря об этом, версия Clean для Windows поставляется с IDE - хотя она довольно ограничена современными стандартами, она лучше, чем использование текстового редактора и командной строки.
Две наиболее полезные функции (в контексте обучения):

  • Вы можете дважды щелкнуть по ошибке, чтобы увидеть, какая строка
  • Вы можете выделить имя модуля и нажать, [Ctrl]+[D]чтобы открыть файл определения (или использовать [Ctrl]+[I]для файла реализации), и переключаться между файлом определения и реализацией с помощью[Ctrl]+[/]

4

Забудьте о кодировке символов

Компилятору Clean не важно, в какой кодировке вы сохранили исходный файл, просто в значениях байтов в файле. Это имеет некоторые аккуратные последствия.

В теле исходного кода разрешены только байты с кодовыми точками, соответствующими печатным символам ASCII, в дополнение к тем, для которых \t\r\n.

литералы:

В Stringи [Char]Литералы ( "stuff"и ['stuff']соответственно) разрешены любые байты, кроме 0 , с оговоркой, что "и 'должны быть экранированы (для Stringи [Char]соответственно), и что новые строки и возвраты Carraige должны быть заменены на \nи \r(также соответственно).

В Charлитералах допускается любой байт, кроме 0 , что означает, что:

'\n'

'
'

То же самое, но второй на один байт короче.

Экранирование:

Кроме стандартных экранированных букв \t\r\n(и т. Д.), Все нечисловые экранирующие последовательности в Clean предназначены либо для косой черты, либо для кавычки, используемой для разграничения литерала, внутри которого находится экранированная буква .

Для числовых escape-последовательностей число обрабатывается как восьмеричное значение, оканчивающееся после трех цифр. Это означает, что если вы хотите, чтобы за нулем следовал символ 1в String, вам нужно использовать "\0001"(или "\0\61"), а не "\01" . Однако, если вы следите за выходом с чем-либо, кроме чисел, вы можете опустить ведущие нули.

Последствия:

Эта причуда с тем, как Clean обрабатывает свои исходные файлы, позволяет Stringи ['Char']эффективно превращается в последовательности из однозначных чисел с 256 базовыми числами, которые имеют множество применений для игры в код, например, для хранения индексов (конечно, до 255).


3

Имя функции с символами

При определении функции часто короче использовать некоторую комбинацию, !@$%^&*~-+=<:|>.?/\чем алфавитно-цифровые символы, потому что она позволяет пропустить пробел между идентификаторами.

Например: ?a=a^2короче f a=a^2, и вызов его также короче.

Однако :

Если идентификатор функции используется рядом с другими символами, которые могут объединяться для формирования другого, но действительного идентификатора, все они будут проанализированы как один идентификатор, и вы увидите ошибку.

Например: ?a+?bразбирает как? a +? b

Дополнительно:

В Clean можно перезаписать импортированные идентификаторы, поэтому единственными символьными идентификаторами символов, которые еще не используются, StdEnvявляются @$?. Перезапись ^-+(и т. Д.) Может быть полезна, если вам нужно больше символических идентификаторов, но будьте осторожны, чтобы не перезаписать тот, который вы используете.


3

Знай своих K узлов

Некоторые из самых сильных конструкций (для игры в гольф) на функциональных языках let ... in ....
Чисто конечно, есть это, а что-то лучше - то #.

Что такое узел?

Чистые #и вездесущие |(pattern guard) оба известны как «выражения узла».
В частности, они позволяют программировать imperatively- МОГ в Clean (что очень хорошо здесь!).

#(Пусть-раньше):

Они оба вычисляют значение целого числа, заданного в виде строки, умноженного на сумму его символов

f s=let i=toInt s;n=sum[toInt c\\c<-:s]in n*i

f s#i=toInt s
#s=sum[toInt c\\c<-:s]
=s*i

Обратите внимание, как версия с #короче, и как мы можем переопределить s. Это полезно, если нам не нужно значение, которое имеет переменная, когда мы ее получаем, поэтому мы можем просто повторно использовать имя. ( letможет возникнуть проблемы, когда вы это сделаете)

Но использовать letлегче, когда вам нужно что-то вродеflip f = let g x y = f y x in g

|(Шаблон охранник):

Защита шаблона Clean может использоваться как во многих других функциональных языках - однако она также может использоваться как императив if ... else .... И более короткая версия троичного выражения.

Например, все они возвращают знак целого числа:

s n|n<>0|n>0=1= -1
=0

s n=if(n<>0)if(n>0)1(-1)0

s n|n>0=1|n<0= -1=0

Конечно, последний, который традиционно использует охрану, является самым коротким, но первый показывает, что вы можете вкладывать их (но только две безусловные предложения возврата могут появляться в одной строке в правиле макета), а второй показывает, что Первый делает логически.

Заметка:

Вы можете использовать эти выражения в основном где угодно. В лямбды, case ... of, let ... inи т.д.


1

Если вы используете, Stringвы должны использоватьText

Преобразование в струны и манипулирование струнами ( {#Char}/ Stringвид, а не [Char]вид) довольно длительное и плохо для игры в гольф. В Textмодуле исправляет это.

Конверсия:

Textопределяет оператор <+для любых двух типов, которые были toStringопределены.
Этот оператор используется так a<+bже, как toString a+++toString b- сохранение как минимум 19 байтов . Даже если вы включите дополнительный импорт ,Textи используете его только один раз, он все равно сохранит 14 байтов!

Манипуляция:

Textопределяет несколько скобок для работы со строками, которые отсутствуют в StdEnv:

  • Оператор +для строк, который намного короче +++(из StdEnv)
  • indexOfс C-подобным поведением возврата -1вместо Nothingсбоя
  • concat, который объединяет список строк
  • join, который соединяет список строк, используя строку разделителя
  • split, который разбивает строку в список строк на подстроке

1

Используйте более короткие лямбды

Иногда вы обнаруживаете, что используете лямбда-выражение (для передачи mapили sortBy, и т. Д.). Когда вы делаете это (пишете лямбды), есть множество способов сделать это.

Правильный путь:

Это sortByс идиоматическими лямбда-сортировочными списками от самого длинного до самого короткого

sortBy (\a b = length a > length b)

Другой правильный путь:

Если вы используете Data.Func, вы также можете сделать

sortBy (on (>) length)

Короткий путь:

Это то же самое, но с синтаксисом игрока в гольф

sortBy(\a b=length a>length b)

Другой способ:

Использование композиции на этот раз не короче, но иногда может быть короче

sortBy(\a=(>)(length a)o length)

Другой способ:

Хотя это немного надумано, вы можете использовать охрану в лямбдах

sortBy(\a b|length a>length b=True=False)

А также дай-до выражения узла

sortBy(\a b#l=length
=l a>l b)

Заметка:

Есть еще две формы лямбды, (\a b . ...)и (\a b -> ...)последняя из которых идентична =варианту, а первая существует по какой-то причине и часто выглядит так, будто вы пытаетесь получить доступ к свойству чего-то, а не определяете лямбду, так что Не используй это.


1
После просмотра некоторых из ваших golfed программ, я получил впечатление , \a=... был обычный синтаксис Clean в лямбда: P
Ørjan Йохансен

Вы также можете добавить охрану в лямбду, как здесь . Это недокументировано (даже противоречит языку отчета), но работает. Кроме того, ->и =для лямбды идентичны, поскольку компилятор обеспокоен ( ->это старый синтаксис). Только .отличается (но я не знаю точно, как).

И в этом конкретном примере вы могли бы рассмотреть возможность использования on(<)length, хотя Data.Funcимпорт сломает вас, если вам это уже не нужно.

@ Килан Круто. Я обновлю это позже сегодня. Я думаю, что вы также можете использовать let-before ( #) в лямбдах.
Οurous

Да, вы можете :-)

0

Использовать литералы списка символов

Литерал списка символов - это сокращенный способ написать что-то вроде ['h','e','l','l','o']as ['hello'].

Это не предел обозначений, например:

  • repeat'c'становится ['c','c'..]становится['cc'..]
  • ['z','y'..'a'] становится ['zy'..'a']
  • ['beginning']++[a,b,c]++['end'] становится ['beginning',a,b,c,'end']
  • ['prefix']++suffix становится ['prefix':suffix]

Они работают в соответствии тоже:

  • ['I don't care about the next character',_,'but I do care about these ones!']

0

Иногда codeкороче

Clean имеет множество действительно полезных функций в стандартных библиотеках, некоторые из которых невероятно многословны для использования без доступа *Worldи использования.*World в code-golf - вообще плохая идея.

Чтобы обойти эту проблему, часто ccallможно codeвместо этого использовать внутри блоков.

Несколько примеров:

Системное время

import System.Time,System._Unsafe
t=toInt(accUnsafe(time))

Выше 58 байтов, но вы можете сэкономить 17 байтов (до 40 + 1) с:

t::!Int->Int
t _=code{ccall time "I:I"
}

Случайные числа

Этот не сохраняет байты сам по себе, но избегает необходимости передавать список из genRandInt

s::!Int->Int
s _=code{ccall time "I:I"ccall srand "I:I"
}
r::!Int->Int
r _=code{ccall rand "I:I"
}

Другое использование

В дополнение к этим двум, которые, вероятно, являются основным использованием для этого в code-golf, вы можете вызывать любую именованную функцию (включая, но не ограничиваясь каждым системным вызовом), вставлять произвольную сборку instruction <byte>и вставлять код для машины ABC.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.