Недавно я имел удовольствие написать программу на Haskell, которая могла бы определить, NegativeLiterals
задействовано ли расширение. Я придумал следующее:
data B=B{u::Integer}
instance Num B where{fromInteger=B;negate _=B 1}
main=print$1==u(-1)
Это будет печатать True
нормально и в False
противном случае.
Теперь мне было очень весело делать это, и я передал вызов всем вам. Какие еще расширения языка Haskell вы можете взломать?
правила
Чтобы взломать конкретное расширение языка, вы должны написать программу на Haskell, которая компилируется как с расширением языка, так и без него (предупреждения в порядке) и выводит два разных значения, отличных от ошибок, при запуске с расширением языка и его отключением (добавляя No
префикс к расширение языка). Таким образом, приведенный выше код может быть сокращен до:
data B=B{u::Integer}
instance Num B where{fromInteger=B;negate _=B 1}
main=print$u(-1)
который печатает 1
и -1
.
Любой метод, который вы используете для взлома расширения, должен быть специфичным для этого расширения. Могут быть способы произвольного определения, какие флаги компилятора или LanguageExtensions включены, если такие методы не разрешены. Вы можете включить дополнительные языковые расширения или изменить оптимизацию компилятора, используя -O
бесплатный счетчик байтов.
Расширения языка
Вы не можете взломать любое расширение языка, не имеют No
аналогов (например Haskell98
, Haskell2010
, Unsafe
, Trustworthy
, Safe
) , потому что они не попадают в соответствии с условиями , изложенными выше. Любое другое языковое расширение является честной игрой.
счет
Вам будет начислено одно очко за каждое расширение языка, которое вы взломали первым, и одно дополнительное очко за каждое расширение языка, для которого у вас самый короткий взлом (измеренный в байтах). По второму пункту связи будут нарушены в пользу более ранних представлений. Чем выше балл, тем лучше
Вы не сможете набрать очко за первую отправку NegativeLiterals
или QuasiQuotes
потому, что я уже взломал их и включил в текст сообщения. Однако вы сможете набрать очко за самый короткий треск каждого из них. Вот мой трескQuasiQuotes
import Text.Heredoc
main=print[here|here<-""] -- |]
источник
NondecreasingIndentation
по понятным причинамWait, what language extension is this?
Или что-то совершенно другое.RelaxedPolyRec
компилятор, достаточно древний, чтобы фактически поддерживать его выключение. (Опция висела с документацией в течение нескольких лет после того, как она перестала что-либо делать.)Ответы:
MagicHash, 30 байт
-XMagicHash выводит 1, -XNoMagicHash выводит 2
MagicHash позволяет именам переменных заканчиваться на
#
. Поэтому с расширением, это определяет две функции ,y#
иx#
которой каждый принимать значение и возвращает константу2
, или1
.x#x
вернет 1 (потому что онx#
применяется к1
)Без расширения это определяет одну функцию,
#
которая принимает два аргумента и возвращает2
. Этоx#a=1
шаблон, который никогда не будет достигнут. Тогдаx#x
есть1#1
, который возвращает 2.источник
MagicHash
не допускает непереключающиеся хэши. Weird!CPP,
3320 байтПечать
0
с-XCPP
и1
с-XNoCPP
.С
-XCPP
помощью косой черты\
перед новой строкой удаляется новая строка, таким образом, код становитсяmain=print$0-- +1
и только0
печатается, поскольку+1
теперь является частью комментария.Без флага комментарий игнорируется, а вторая строка анализируется как часть предыдущей строки, поскольку она имеет отступ.
Предыдущий подход с
#define
Также печатает
0
с-XCPP
и1
с-XNoCPP
.источник
NumDecimals, 14 байтов
-XNumDecimals печатает
10
. -XNoNumDecimals печатает10.0
.источник
BinaryLiterals, 57 байт
-XBinaryLiterals печатает одну новую строку . -XNoBinaryLiterals печатает
1
.Я уверен, что есть лучший способ сделать это. Если вы найдете один, пожалуйста, опубликуйте его.
источник
b
как функцию (поэтому двоичный код не становитсяb(0, 1)
, а двоичный становится0b1
)?Мономорфизм ограничение + 7 других, 107 байт
Это использует TH, который требует флаг
-XTemplateHaskell
все время.Файл T.hs, 81 + 4 байта
Main, 22 байта
Компиляция с флагом MonomorphismRestriction заставляет тип
p
toInteger -> Integer -> Integer
вызывать следующий вывод:Компиляция с флагом NoMonomorphismRestriction оставляет тип типа
p
самое общее, т.е.Num a => a->a->a
- производить что-то вроде (сокращенныеVarT
имена доa
):Попробуйте их онлайн!
альтернативы
Поскольку приведенный выше код просто выводит тип
p
, это можно сделать со всеми флагами, которые каким-то образом влияют на то, как Haskell выводит типы. Я буду только указывать флаг и на что заменить функциюp
и при необходимости дополнительные флаги (кроме-XTemplateHaskell
):Перегруженные списки, 106 байт
Дополнительно необходимо
-XNoMonomorphismRestriction
:Либо
p :: [a]
илиp :: IsList l => l
, попробовать их в Интернете!OverloadedStrings, 106 байт
Дополнительно необходимо
-XNoMonomorphismRestriction
:Либо
p :: String
илиp :: IsString s => s
, попробовать их в Интернете!PolyKinds, 112 байт
Это полностью связано с @CsongorKiss:
Либо
P :: P a
илиP :: forall k (a :: k). P a
, попробовать их в Интернете!MonadComprehensions, 114 байтов
Либо
p :: [a] -> [a]
илиp :: Monad m => m a -> m a
, попробовать их в Интернете!NamedWildCards, 114 байт
Этот был найден @Laikoni, он дополнительно требует
-XPartialTypeSignatures
:Они оба имеют тип сохранения (
p :: a -> a
), но GHC генерирует разные имена для переменных, попробуйте их онлайн!ApplicativeDo, 120 байт
Либо
p :: Monad m => m a -> m a
илиp :: Functor f => f a -> f a
, попробовать их в Интернете!Перегруженные метки, 120 байт
Для этого нужен дополнительный флаг
-XFlexibleContexts
:Или типа как
p :: a -> b -> b
илиp :: IsLabel "id" (a->b) => a -> b
, попробовать их в Интернете!источник
OverloadedStrings
илиOverloadedLists
наверняка, а также, возможно, с другими ...PolyKinds
: Попробуйте онлайн!NamedWildCards
: Попробуйте онлайн! (Требуется-XPartialTypeSignatures
)CPP,
2725Попробуйте онлайн!
Принты
()
для-XCPP
и1
для-XNoCPP
Предыдущая версия:
Попробуйте онлайн!
Печать
[1]
с-XCPP
и в[1,2]
противном случае.Кредиты: Это вдохновлено ответом Лайкони, но вместо него
#define
он просто использует комментарии С.источник
ScopedTypeVariables,
162113 байт-XScopedTypeVariables печатает
""
(пусто), -XNoScopedTypeVariables печатает"[()]"
.Редактировать: обновленное решение благодаря полезным предложениям в комментариях
источник
"T"
можно просто заменить на""
.T
с()
. Чтобы избежать необходимости определять это. Попробуйте онлайн!show
можно изменить для печатиforall
сэкономит вам несколько байтов. Я сомневаюсь, что у любого решения, которое нуждается в дополнительных инстанциях, есть большая надежда на победу.MonoLocalBinds, GADT или TypeFamilies,
3632 байтаРЕДАКТИРОВАТЬ:
(1.0,1)
.С любым из флагов -XMonoLocalBinds , -XGADTs или -XTypeFamilies он печатает
(1.0,1.0)
.MonoLocalBinds
Расширение существует , чтобы предотвратить некоторое неинтуитивное умозаключение типа , спровоцированный GADTs и семьями типа. Таким образом, это расширение автоматически включается двумя другими.-XNoMonoLocalBinds
, этот прием предполагает , что вы не делаете.Как и его более известный двоюродный брат, ограничение мономорфизма
MonoLocalBinds
работает, предотвращая некоторые значения (в локальных привязках, таких какполиморфностьlet
илиwhere
, таким образом, название, по-видимому, также может происходить на верхнем уровне). Несмотря на то, что они созданы для логического вывода, правила, когда это срабатывает , по возможности, даже более пугающие, чем MR.Без какого-либо расширения, вышеуказанная программа выводит тип
f :: Num a => a -> a
, позволяяf pi
по умолчанию aDouble
иf 0
aInteger
.f :: Double -> Double
иf 0
должен возвращатьDouble
.a=0
необходима , чтобы вызвать технические правила:a
удар по ограничению мономорфизма, иa
является свободным переменным изf
, что означает , чтоf
«ы связывания группа не полностью генерализованный , что означаетf
не закрыто , и , таким образом , не становится полиморфными.источник
ПерегруженныеСтроки,
654832 байтаИспользуя преимущества RebindableSyntax, используйте нашу собственную версию fromString, чтобы превратить любой строковый литерал в
"y"
.Должен быть скомпилирован с
-XRebindableSyntax -XImplicitPrelude
.Без
-XOverloadedStrings
отпечатков""
; с принтами"y"
.Кроме того, только сейчас меня поразило, что та же самая техника работает с (например) OverloadedLists:
Перегруженные списки, 27 байт
Должен быть скомпилирован с
-XRebindableSyntax -XImplicitPrelude
.Без
-XOverloadedLists
отпечатков[0]
; с принтами[1,0]
.источник
fromString a=['y']
.print "n"
также может быть отброшено.="y"
, но=['y']
работает отлично!n
изprint"n"
-XImplicitPrelude
после,RebindableSyntax
чтобы избежать строки импорта.BangPatterns, 32 байта
-XBangPatterns печатает,
1
тогда как -XNoBangPatterns печатает0
.Это использует то, что флаг BangPatterns позволяет аннотировать шаблоны с помощью
!
принудительной оценки в WHNF, в этом случае9!1
будет использоваться определение верхнего уровня(!)=seq
. Если флаг не активирован,f!_
определяет новый оператор(!)
и скрывает определение верхнего уровня.источник
ApplicativeDo, 104 байта
Попробуйте онлайн!
С
ApplicativeDo
этим печатаетБез него печатает
ZipList
является одним из немногих типов в базовых библиотеках с экземпляром для,Applicative
но не дляMonad
. Возможно, где-то есть более короткие альтернативы.источник
Строгий,
87 8482 байта-5 байт благодаря dfeuer !
Может быть меньше с
BlockArguments
сохранением паренов вокруг\_->print 1
:Выполнение этого с -XStrict печатает a,
1
тогда как выполнение этого с -XNoStrict будет печатать a0
. При этом используется то, что Haskell по умолчанию является ленивым и не нуждается в оценке,error""
так как он уже знает, что результат будет,0
когда он соответствует первому аргументу(!)
этого результата это поведение можно изменить с помощью этого флага, что заставит среду выполнения оценить оба аргумента.Если в одном случае разрешено ничего не печатать, мы можем уменьшить его до 75 байт, заменив основной на (также некоторые байты отключены dfeuer ):
StrictData,
106 9993 байта-15 байт благодаря dfeuer !
Это в основном то же самое, но вместо этого работает с полями данных:
Печать
1
с флагом -XStrictData и0
с -XNoStrictData .Если в одном случае разрешено печатать ничего, мы можем уменьшить его до 86 байт, заменив основной на (19 байтов выключено dfeuer ):
Примечание: все решения требуют
TypeApplications
установки.источник
pure()
.D{}
трюк довольно крутой! Побрил еще один, используяPartialTypeSignatures
вместоScopedTypeVariables
:)-XBlockArguments
:main=catch @ErrorCall(p$seq(D$error"")1)\_->p 3
ApplicativeDo, 146 байт
Печатает 1, когда ApplicativeDo включен, 0 в противном случае
Попробуйте онлайн!
источник
Applicative
иShow
сохранить используя синтаксис записи, смотрите это .BinaryLiterals,
3124 байтаРедактировать:
b12
переменную.Корректировка метода H.PWiz , избегая экземпляра функции.
0b12
как0
b12
, печать 0 + 1 =1
.0b12
как0b1
2
, печать 1 + 2 =3
.источник
ExtendedDefaultRules,
5453 байтаПечать
()
с-XExtendedDefaultRules
и0
с-XNoExtendedDefaultRules
.Этот флаг включен по умолчанию в GHCi, но не в GHC, что недавно вызвало у меня некоторую путаницу , хотя BMO быстро помогло.
Приведенный выше код является версией для гольфа, приведенной в примере в Руководстве пользователя GHC, где поясняется тип по умолчанию в GHCi .
-1 байт благодаря Эрджану Йохансену !
источник
toEnum 0::Num a=>Enum a=>a
.PartialTypeSignatures
:main=print(toEnum 0::_=>Num a=>a)
. Кроме того, ваша ссылка TIO устарела.RebindableSyntax , 25 байтов
Я читал недавно опубликованное « Руководство по расширениям GHC», когда заметил простое, которое я еще не помню, видя здесь.
-1
.1
.Также требуется
-XImplicitPrelude
или, альтернативно,import Prelude
в самом коде.-XRebindableSyntax
изменяет поведение некоторого синтаксического сахара в Haskell, чтобы сделать возможным его переопределение.-1
является синтаксическим сахаром дляnegate 1
.negate
являетсяPrelude.negate
, но с расширением его « в зависимости от тогоnegate
находится в области видимости в точке использования», который определяется какid
.Prelude
модуля, оно автоматически отключает обычный неявный импорт этого, но здесь необходимы другиеPrelude
функции (напримерprint
), поэтому его снова включают с-XImplicitPrelude
.источник
Строгий, 52 байта
-XStrict
-XNoStrict
С
-XStrict
, печатает()
дополнительное время.Спасибо @Sriotchilism О'Зайку за два байта.
источник
StrictData, 58 байт
(Ссылки немного устарели; исправят.)
-XNoStrictData
-XStrictData
Требуется
MagicHash
(чтобы мы могли импортироватьGHC.Exts
вместоUnsafe.Coerce
) и-O
(абсолютно необходимо, чтобы разрешить распаковку небольших строгих полей).С
-XStrictData
, печатает 3. В противном случае печатает целочисленное значение (возможно, с тегами) указателя на предварительно выделенную копию3::Integer
, которая не может быть 3.объяснение
Это будет немного легче понять с небольшим расширением, основанным на типе по умолчанию. С помощью подписей мы можем отказаться от сложения.
Эквивалентное
Почему он печатает 3? Это кажется удивительным! Ну, маленькие
Integer
значения представлены очень похоже наInt
s, которые (со строгими данными) представлены так же, какD
s. В итоге мы игнорируем тег, указывающий, является ли целое число маленьким или большим положительным / отрицательным.Почему он не может напечатать 3 без расширения? Оставляя в стороне любые причины размещения памяти, указатель данных с младшими битами (2 младших для 32-битных, 3 младших для 64-битных), равный 3, должен представлять значение, построенное из третьего конструктора. В этом случае для этого потребуется отрицательное целое число.
источник
UnboxedTuples, 52 байта
Требуется
-XTemplateHaskell
. ПечатаетсяConE GHC.Prim.(##)
с -XUnboxedTuples иUnboundVarE ##
с -XNoUnboxedTuples .источник
-XTemplateHaskell
?Перегруженные списки, 76 байт
С -XOverloadedLists это печатает
[()]
. С -XNoOverloadedLists печатает[]
Это требует дополнительных флагов:
-XFlexibleInstances
,-XIncoherentInstances
источник
HexFloatLiterals ,
4925 байт-24 байта благодаря Орджану Йохансену.
Печать
0.0
с-XHexFloatLiterals
и0
с-XNoHexFloatLiterals
.Нет ссылок на TIO, потому что HexFloatLiterals был добавлен в ghc 8.4.1, но TIO имеет ghc 8.2.2.
источник
main|(.)<-seq=print$0x0.0
избегает сокрытия импортаmain|let _._=0=print$0x0.0
может быть проще для полиглота, хотя.ScopedTypeVariables, 37 байт
Это также требует
UnicodeSyntax
,PartialTypeSignatures
,GADTs
иExplicitForAll
.Попробуйте онлайн (без расширения)
Попробуйте онлайн (с расширением)
объяснение
Частичные подписи типа предназначены только для сохранения байтов. Мы можем заполнить их так:
С переменными типа scoped тип
a
in1
должен бытьa
типом inmain
, который сам должен бытьFloat
. Без переменных типа с областью видимости по1
умолчаниюInteger
. Так какFloat
иInteger
значения отображаются по-разному, мы можем их различать.Спасибо @ ÖrjanJohansen за колоссальные 19 байтов! Он понял, что гораздо лучше использовать разницу между
Show
экземплярами разных числовых типов, чем различия в их арифметике. Он также понял, что было бы нормально оставить типmain
«синтаксически неоднозначным», потому что ограничение фактически устраняет его. Избавление от локальной функции также освободило меня от удаления сигнатуры типа дляmain
(смещения ее в RHS), чтобы сохранить еще пять байтов.источник
DeriveAnyClass,
121113 байтСпасибо dfeuer за довольно много байтов!
-XDeriveAnyClass печатает,
1
тогда как -XNoDeriveAnyClass печатаетM 0
.Это использует тот факт, что DeriveAnyClass является стратегией по умолчанию, когда включены и DeriveAnyClass, и GeneralizedNewtypeDeriving, как вы можете видеть из предупреждений. Этот флаг будет счастливо генерировать пустые реализации для всех методов , но GeneralizedNewtypeDeriving на самом деле достаточно умен , чтобы использовать реализацию базового типа и с тех пор
Int
являетсяNum
его не подведет и в этом случае.Если ничего не печатать в случае, если флаг включен, замена
main
на следующее будет 109 байтов :источник
runhaskell
это фактически печатаетM 1
с-XDeriveAnyClass
, из - за лени ...1
:)PostfixOperators, 63 байта
Попробуйте онлайн (без расширения)
Попробуйте онлайн (с расширением)
Это урезанная версия полиглота Hugs / GHC, которую я написал . Смотрите этот пост для объяснения. Спасибо @ ÖrjanJohansen за понимание, что я мог использовать
id
вместо пользовательского оператора, сохраняя четыре байта.источник
id
можно использовать вместо!
.DeriveAnyClass, 104 байта
Попробуйте онлайн (без расширения)
Попробуйте онлайн (с расширением)
Также требуется
GeneralizedNewtypeDeriving
.источник
StrictData, 97 байт
Попробуйте онлайн (без строгих данных)
Попробуйте онлайн (строгие данные)
Также требуется
DeriveGeneric
.источник
UnicodeSyntax, 33 байта
Попробуйте онлайн!
источник
TemplateHaskell,
14091 байтПросто скопировал с mauke с небольшими изменениями. Я не знаю, что происходит.
-49 байтов благодаря Орджану Йохансену.
Попробуйте онлайн!
источник
$(...)
(без пробела) синтаксис оценки шаблона, когда TH включен, иTupE[]
("пустой кортеж") дает()
. ИспользованиеShow
может хорошо сработать для полиглота, хотя для этой конкретной задачи мне не очень удобно определять значение для печати в виде пустой строки ...MonomorphismRestriction,
3129 байтРедактировать:
-XMonomorphismRestriction печатает
0
. -XNoMonomorphismRestriction печатает18446744073709551616
.f
принудительно должны быть одного типа, поэтому программа печатает2^2^6 = 2^64
как 64-битныйInt
(на 64-битных платформах), которая переполняется до0
.2^64
как бигнумInteger
.источник
f=(2^);main=print$f$f(64::Int)
спас бы байт. Но это не будет реально прекратить64=2^6
, это еще один байт.ScopedTypeVariables,
11997 байтПросто скопировал с mauke с небольшими изменениями.
В настоящее время есть два других ответа для ScopedTypeVariables: 113 байтов Csongor Kiss и 37 байтов dfeuer . Это представление отличается тем, что не требует других расширений Haskell.
-22 байта благодаря Орджану Йохансену.
Попробуйте онлайн!
источник
IO()/print
в полиглоте трюк не сработает).Num
. Я думаю, чтоclass(Show a,Floating a)=>K a where{k::a->String;k=pure$ show(f pi)where f=id::a->a};
должно работать, удобно использовать этоFloat
иDouble
отображатьpi
с различной точностью.