Відповіді:
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 байтОстанні кілька навряд чи дійсно збережуть байти, оскільки пряма заміна дає більше байтів, ніж імпорт, але це може бути можливим у випадках, коли рекурсія над списком все-таки потрібна.
Ця порада була успішно використаний тут .
map f list -> [f x\\x<-list] (11 bytes saved)(або чогось подібного)).
Зрештою, як може хтось гольфу мовою, якою він не може користуватися!
Інтернет
Clean не є відомою або добре задокументованою мовою, і це ім'я, безумовно, не дозволяє легко знайти дуже потрібні ресурси для усунення цих проблем ... чи це?
Спочатку Clean називався Concurrent Clean , який досі використовується в передмові майже кожного документа, пов’язаного з Clean - тому, якщо ви шукаєте Clean, шукайте замість Concurrent Clean.
Однією з найбільш чудових схожностей Clean з Haskell (яких існує багато) є існування Cloogle , яка є пошуковою функцією, що охоплює бібліотеки, з якими Clean Ship .
Місцево
Бібліотеки, з якими «Очищується», мають форму пристойно коментованих, дещо самодокументованих файлів «Чистий вихід», які можна переглядати за допомогою IDE.
(Він також поставляється з повним прикладом програм, під $INSTALL/Examples.)
Якщо говорити про це, то версія Windows Clean Clean оснащена IDE - хоча вона досить обмежена сучасними стандартами, це світ краще, ніж використання текстового редактора та командного рядка.
Дві найкорисніші функції (в контексті навчання):
[Ctrl]+[D]щоб відкрити файл визначення (або використовувати [Ctrl]+[I]для файлу реалізації), а також перемикатися між файлом визначення та реалізацією за допомогою[Ctrl]+[/]Компілятор Clean не переймається тим, яке кодування, на вашу думку, зберегло вихідний файл, як і значення байтів у файлі. Це має деякі акуратні наслідки.
У тілі вихідного коду дозволено лише байти з кодовими точками, що відповідають друкованим символам ASCII, крім тих, для яких \t\r\n.
Література:
В Stringі [Char]літерали ( "stuff"і ['stuff']відповідно), будь-які байти , крім 0 допускається, із застереженням , що "і 'повинні бути екрановані (для Stringі , [Char]відповідно), і що нові рядки і провізна повертається повинні бути замінені \nі \r(також відповідно).
У Charлітералах дозволений будь-який байт, крім 0 , тобто:
'\n'
'
'
Ті самі, але другий на один байт коротший.
Втеча:
За винятком стандартних пробілів літер \t\r\n(тощо), всі нечислові послідовності відхилення в «Чистому» - це або для косої риски, або для цитати, що використовується для обмеження прямої літери .
Для числових послідовностей виходу число трактується як вісімкове значення, що закінчується після трьох цифр. Це означає, що якщо ви хочете, щоб нуль супроводжувався символом 1у a String, вам потрібно використовувати "\0001"(або "\0\61"), а не "\01" . Однак якщо слідкувати за втечею будь-чим, крім цифр, ви можете опустити провідні нулі.
Наслідки:
Ця химерність того, як Clean обробляє вихідні файли, дозволяє Stringі ['Char']ефективно стати послідовностями базових 256 одноцифрових чисел - яка має безліч застосувань для коду-гольфу, таких як зберігання індексів (до 255, звичайно).
При визначенні функції часто коротше використовувати якусь комбінацію, !@$%^&*~-+=<:|>.?/\ніж використовувати буквено-цифрові символи, оскільки це дозволяє опускати пробіл між ідентифікаторами.
Наприклад: ?a=a^2коротше f a=a^2, а виклик також коротше.
Однак :
Якщо ідентифікатор функції використовується поруч з іншими символами, які можуть поєднуватися, утворюючи інший, але дійсний ідентифікатор, всі вони будуть проаналізовані як один ідентифікатор, і ви побачите помилку.
Наприклад: ?a+?bрозбирає як? a +? b
Додатково:
Можна імпортувати імпортовані ідентифікатори в Очистити, і тому єдиними односимвольними ідентифікаторами символів, які ще не використовуються, StdEnvє @$?. Переписування ^-+(тощо) може бути корисним, якщо вам потрібні більше символічних ідентифікаторів, але будьте обережні, щоб не перезаписати той, який ви використовуєте.
Деякі з найсильніших конструкцій (для гольфу) на функціональних мовах є let ... in ....
Чисто, звичайно, є це, і щось краще - своє #.
Що таке вузол?
Clean's #і всюдисущий |(захист шаблону) обидва відомі як "вирази вузлів".
В Зокрема, вони дозволяють програмувати 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і т.д.
Stringви повинні використовуватиTextПеретворення на струни та маніпулювання струнами ( {#Char}/ Stringвид, а не [Char]вид) досить тривалий і поганий для гольфу. У Textмодулі виправляє це.
Конверсія:
Textвизначає оператор <+для будь-яких двох типів, які були toStringвизначені.
Цей оператор, який використовується як a<+bі те саме, toString a+++toString b- зберігає принаймні 19 байт . Навіть якщо ви включите додатковий імпорт, ,Textі використовуєте його лише один раз, він все одно економить 14 байт!
Маніпуляція:
Textвизначає кілька скоб для маніпуляції з рядками, яких немає у StdEnv:
+для рядків, який значно коротший, ніж +++(від StdEnv)indexOf, з С-подібною поведінкою повернення -1замість Nothingвідмовиconcat, що об'єднує список рядківjoin, яка приєднується до списку рядків, використовуючи розділовий рядокsplit, який розбиває рядок на список рядків на підрядкуІноді ви опиняєтесь, використовуючи лямбдаський вираз (переходити до 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 -> ...)остання з яких ідентична =варіанту, і перша з яких існує чомусь і часто виглядає так, що ви намагаєтесь отримати доступ до властивості чогось, а не визначати лямбду, так що не використовую.
\a=... був звичайний синтаксис Clean в лямбда: P
->і =для лямбдів однакові, що стосується компілятора ( ->це старий синтаксис). Тільки .інше (але я не знаю точно як).
on(<)length, хоча Data.Funcімпорт порушить вас, якщо вам це вже не потрібно.
#) в лямбдах.
Список літери є скороченим способом писати що - щось на зразок , ['h','e','l','l','o']як ['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!']codeкоротшеУ стандартних бібліотеках Clean є дуже багато корисних функцій, деякі з яких неймовірно багатослівні для використання без доступу *World, а використання *Worldв коді-гольфу взагалі погана ідея.
Щоб подолати цю проблему, часто 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"
}
Інші види використання
На додаток до цих двох, які, мабуть, є основними для цього в коді-гольф, ви можете викликати будь-яку названу функцію (включаючи, але не обмежуючись кожним систематичним викликом), вбудовувати довільну збірку instruction <byte>та вставляти код для машини ABC.
import StdEnv+a and b(21 байт) менше%[a:r]|a= %r=a;%_=True(22 байти)? Або це було бimport StdEnv+a=True and b=True(31 байт), в такому випадку він дійсно коротше? (Я ніколи не програмував у Clean, btw.)