Recentemente, tive o prazer de escrever um programa Haskell que pudesse detectar se a NegativeLiterals
extensão estava envolvida. Eu vim com o seguinte:
data B=B{u::Integer}
instance Num B where{fromInteger=B;negate _=B 1}
main=print$1==u(-1)
Isso será impresso True
normalmente e False
caso contrário.
Agora eu me diverti muito fazendo isso, estou estendendo o desafio para todos vocês. Quais outras extensões de idioma Haskell você pode quebrar?
Regras
Para quebrar uma extensão de idioma específica, você deve escrever um programa Haskell que compila com e sem a extensão de idioma (os avisos são bons) e gera dois valores diferentes de erro quando executados com a extensão de idioma e desativados (adicionando o No
prefixo a a extensão do idioma). Dessa maneira, o código acima pode ser reduzido para apenas:
data B=B{u::Integer}
instance Num B where{fromInteger=B;negate _=B 1}
main=print$u(-1)
que imprime 1
e -1
.
Qualquer método usado para quebrar uma extensão deve ser específico a essa extensão. Pode haver maneiras de detectar arbitrariamente quais sinalizadores do compilador ou LanguageExtensions estão habilitados, se esses métodos não forem permitidos. Você pode ativar extensões de idioma adicionais ou alterar a otimização do compilador usando -O
sem nenhum custo a sua contagem de bytes.
Extensões de idioma
Você não pode quebrar qualquer extensão de linguagem que não tem uma No
contrapartida (por exemplo Haskell98
, Haskell2010
, Unsafe
, Trustworthy
, Safe
) porque estas não se enquadram nos termos descritos acima. Qualquer outra extensão de idioma é um jogo justo.
Pontuação
Você receberá um ponto por cada extensão de idioma que você é a primeira pessoa a quebrar e um ponto adicional por cada extensão de idioma para a qual você tem o menor crack (medido em bytes). Para o segundo ponto, os laços serão quebrados em favor de envios anteriores. Maior pontuação é melhor
Você não poderá marcar um ponto para a primeira submissão NegativeLiterals
ou QuasiQuotes
porque eu já os decifrei e os incluí no corpo da postagem. No entanto, você será capaz de marcar um ponto pelo menor crack de cada um deles. Aqui está o meu crackQuasiQuotes
import Text.Heredoc
main=print[here|here<-""] -- |]
fonte
NondecreasingIndentation
, por razões óbviasWait, what language extension is this?
ou algo completamente diferente.RelaxedPolyRec
, para um compilador antigo o suficiente para realmente suportá-lo. (A opção pendurados, com a documentação, para alguns anos depois de ter parado de fazer qualquer coisa.)Respostas:
MagicHash, 30 bytes
-XMagicHash gera 1, -XNoMagicHash gera 2
MagicHash permite que nomes de variáveis terminem em a
#
. Portanto, com a extensão, isso define duas funçõesy#
ex#
cada uma pega um valor e retorna uma constante2
, ou1
.x#x
retornará 1 (porque éx#
aplicado a1
)Sem a extensão, isso define uma função
#
que recebe dois argumentos e retorna2
. Ox#a=1
é um padrão que nunca é alcançado. Entãox#x
é1#1
, que retorna 2.fonte
MagicHash
não permita hashes não seguidos. Esquisito!CPP,
3320 bytesImprime
0
com-XCPP
e1
com-XNoCPP
.Com
-XCPP
, uma barra\
antes de uma nova linha remove a nova linha, assim o código se tornamain=print$0-- +1
e somente0
é impresso como o+1
agora faz parte do comentário.Sem a sinalização, o comentário é ignorado e a segunda linha é analisada como parte da linha anterior, porque é recuada.
Abordagem anterior com
#define
Também imprime
0
com-XCPP
e1
com-XNoCPP
.fonte
NumDecimals, 14 bytes
-XNumDecimals imprime
10
. -XNoNumDecimals imprime10.0
.fonte
Literais binários, 57 bytes
-XBinaryLiterals imprime uma única nova linha. -XNoBinaryLiterals imprime a
1
.Estou certo de que existe uma maneira melhor de fazer isso. Se você encontrar um, por favor poste.
fonte
b
como uma função (para que nenhum binário se torneb(0, 1)
, mas binário se torne0b1
)?MonomorfismoRestrição + 7 others, 107 bytes
Isso usa TH, que requer a bandeira o
-XTemplateHaskell
tempo todo.Arquivo T.hs, 81 + 4 bytes
Principal, 22 bytes
Compilar com o sinalizador MonomorphismRestriction força o tipo de
p
paraInteger -> Integer -> Integer
e, portanto, produz a seguinte saída:Compilar com a bandeira NoMonomorphismRestriction deixa o tipo de
p
no mais geral, ie.Num a => a->a->a
- produzindo algo como (reduziu osVarT
nomes paraa
):Experimente-os online!
Alternativas
Como o código acima simplesmente imprime o tipo de
p
, isso pode ser feito com todos os sinalizadores que de alguma forma influenciam a maneira como Haskell deduz os tipos. Especificarei apenas o sinalizador e com o que substituir a funçãop
e, se necessário, sinalizadores adicionais (além de-XTemplateHaskell
):OverloadedLists, 106 bytes
Além disso precisa
-XNoMonomorphismRestriction
:Ou ,
p :: [a]
oup :: IsList l => l
experimentá-los online!OverloadedStrings, 106 bytes
Além disso precisa
-XNoMonomorphismRestriction
:De qualquer
p :: String
oup :: IsString s => s
, experimentá-los online!PolyKinds, 112 bytes
Isso se deve inteiramente ao @CsongorKiss:
De qualquer
P :: P a
ouP :: forall k (a :: k). P a
, experimentá-los online!MônadasCompreensões, 114 bytes
De qualquer
p :: [a] -> [a]
oup :: Monad m => m a -> m a
, experimentá-los online!NamedWildCards, 114 bytes
Este foi encontrado pelo @Laikoni, além disso requer
-XPartialTypeSignatures
:Ambos têm o tipo save (
p :: a -> a
), mas o GHC gera nomes diferentes para as variáveis, experimente-os online!ApplicativeDo, 120 bytes
De qualquer
p :: Monad m => m a -> m a
oup :: Functor f => f a -> f a
, experimentá-los online!OverloadedLabels, 120 bytes
Isso precisa do sinalizador adicional
-XFlexibleContexts
:Escreva como
p :: a -> b -> b
oup :: IsLabel "id" (a->b) => a -> b
, experimente-os online!fonte
OverloadedStrings
ouOverloadedLists
com certeza e provavelmente outros, bem ..PolyKinds
: Experimente online!NamedWildCards
: Experimente online! (Requer-XPartialTypeSignatures
)CPP,
2725Experimente online!
Imprime
()
para-XCPP
e1
para-XNoCPP
Versão anterior:
Experimente online!
Impressões
[1]
com-XCPP
e de[1,2]
outra forma.Créditos: isso é inspirado na resposta de Laikoni, mas em vez de
#define
simplesmente usa comentários em C.fonte
ScopedTypeVariables,
162113 bytes-XScopedTypeVariables imprime
""
(vazio), -XNoScopedTypeVariables imprime"[()]"
.Edit: solução atualizada graças a sugestões úteis nos comentários
fonte
"T"
pode ser substituído por""
.T
com()
. Para evitar ter que defini-lo. Experimente online!show
pode ser alterado para impressãoforall
economizará alguns bytes. Duvido que qualquer solução que precise de instâncias extras tenha muita esperança de vencer.MonoLocalBinds, GADTs ou TypeFamilies,
3632 bytesEDITAR:
(1.0,1)
.Com qualquer um dos sinalizadores -XMonoLocalBinds , -XGADTs ou -XTypeFamilies , ele imprime
(1.0,1.0)
.o
MonoLocalBinds
extensão existe para evitar alguma inferência de tipo não intuitiva acionada por GADTs e famílias de tipos. Como tal, esta extensão é ativada automaticamente pelas outras duas.-XNoMonoLocalBinds
, este truque assume que você não.Como seu primo mais conhecido, a restrição de monomorfismo,
MonoLocalBinds
funciona impedindo que alguns valores (em ligações locais comoaparentemente também possa acontecer em nível superior) sejam polimórficos. Apesar de terem sido criadas para inferência de tipo mais saudável, as regras para quando são acionadas são, se possível, ainda mais peludas que a RM.let
ouwhere
, portanto, o nomeSem qualquer extensão, os infere programa acima o tipo
f :: Num a => a -> a
, permitindo quef pi
para o padrão para umDouble
ef 0
para umInteger
.f :: Double -> Double
ef 0
também deve retornar umDouble
.a=0
é necessária para acionar as regras técnicas:a
é atingida pela restrição de monomorfismo ea
é uma variável livre def
, o que significa quef
o grupo de ligação desse grupo não é totalmente generalizado , o que significa quef
não é fechado e, portanto, não se torna polimórfico.fonte
OverloadedStrings,
654832 bytesAproveitando o RebindableSyntax, use nossa própria versão do fromString para transformar qualquer string literal em
"y"
.Deve ser compilado com
-XRebindableSyntax -XImplicitPrelude
.Sem
-XOverloadedStrings
impressões""
; com estampas"y"
.Além disso, apenas agora me ocorreu que a mesma técnica funciona com (por exemplo) OverloadedLists:
OverloadedLists, 27 bytes
Deve ser compilado com
-XRebindableSyntax -XImplicitPrelude
.Sem
-XOverloadedLists
impressões[0]
; com impressões[1,0]
.fonte
fromString a=['y']
.print "n"
também pode ser descartado.="y"
, mas=['y']
funciona bem!n
deprint"n"
-XImplicitPrelude
depoisRebindableSyntax
para evitar a linha de importação.BangPatterns, 32 bytes
-XBangPatterns imprime
1
enquanto -XNoBangPatterns imprime0
.Isso faz com que o sinalizador BangPatterns permita anotar padrões com um
!
para forçar a avaliação ao WHNF; nesse caso9!1
, usará a definição de nível superior(!)=seq
. Se o sinalizador não estiver ativado,f!_
define um novo operador(!)
e oculta a definição de nível superior.fonte
ApplicativeDo, 104 bytes
Experimente online!
Com
ApplicativeDo
, isso imprimeSem ele, imprime
ZipList
é um dos poucos tipos nas bibliotecas base com uma instância para,Applicative
mas não paraMonad
. Pode haver alternativas mais curtas à espreita em algum lugar.fonte
Rigoroso,
87 8482 bytes-5 bytes graças ao dfeuer !
Pode ser menos com o
BlockArguments
salvamento dos parênteses\_->print 1
:A execução com -XStrict imprime um,
1
enquanto a execução com -XNoStrict imprime a0
. Isso usa que Haskell, por padrão, é preguiçoso e não precisa avaliar,error""
pois já sabe que o resultado será0
quando corresponder ao primeiro argumento de(!)
, esse comportamento pode ser alterado com esse sinalizador - forçando o tempo de execução a avaliar os dois argumentos.Se não for permitido imprimir nada em um caso, podemos reduzi -lo a 75 bytes, substituindo o principal por (também alguns bytes desativados pelo dfeuer ):
StrictData,
106 9993 bytes-15 bytes graças ao dfeuer !
Isso basicamente faz o mesmo, mas funciona com campos de dados:
Imprime
1
com o sinalizador -XStrictData e0
com -XNoStrictData .Se nada for permitido em um caso, podemos reduzi -lo para 86 bytes, substituindo o principal por (19 bytes desativados pelo dfeuer ):
Nota: Todas as soluções requerem
TypeApplications
conjunto.fonte
pure()
.D{}
truque é bem legal! Raspou outro usando emPartialTypeSignatures
vez deScopedTypeVariables
:)-XBlockArguments
:main=catch @ErrorCall(p$seq(D$error"")1)\_->p 3
ApplicativeDo, 146 bytes
Prints 1 when ApplicativeDo is enabled, 0 otherwise
Try it online!
fonte
Applicative
andShow
to save using record syntax, see this.BinaryLiterals,
3124 bytesEdit:
b12
variable.An adjustment to H.PWiz's method, avoiding the function instance.
0b12
lexes as0
b12
, printing 0+1 =1
.0b12
lexes as0b1
2
, printing 1+2 =3
.fonte
ExtendedDefaultRules,
5453 bytesPrints
()
with-XExtendedDefaultRules
and0
with-XNoExtendedDefaultRules
.This flag is enabled by default in GHCi, but not in GHC, which recently caused some confusion for me, though BMO was quickly able to help.
The above code is a golfed version of an example in the GHC User Guide where type defaulting in GHCi is explained.
-1 byte thanks to Ørjan Johansen!
fonte
toEnum 0::Num a=>Enum a=>a
.PartialTypeSignatures
:main=print(toEnum 0::_=>Num a=>a)
. Also, your TIO link is out of date.RebindableSyntax, 25 bytes
I was reading the recently posted Guide to GHC's Extensions when I noticed an easy one that I didn't recall seeing here yet.
-1
.1
.Also requires
-XImplicitPrelude
, or alternativelyimport Prelude
in the code itself.-XRebindableSyntax
changes the behavior of some of Haskell's syntactic sugar to make it possible to redefine it.-1
is syntactic sugar fornegate 1
.negate
isPrelude.negate
, but with the extension it's "whichevernegate
is in scope at the point of use", which is defined asid
.Prelude
module, it automatically disables the usual implicit import of that, but otherPrelude
functions (likeprint
) are needed here, so it is re-enabled with-XImplicitPrelude
.fonte
Strict, 52 bytes
-XStrict
-XNoStrict
With
-XStrict
, prints()
an extra time.Thanks to @Sriotchilism O'Zaic for two bytes.
fonte
StrictData, 58 bytes
(Links are slightly outdated; will fix.)
-XNoStrictData
-XStrictData
Requires
MagicHash
(to let us importGHC.Exts
instead ofUnsafe.Coerce
) and-O
(absolutely required, to enable unpacking of small strict fields).With
-XStrictData
, prints 3. Otherwise, prints the integer value of the (probably tagged) pointer to the pre-allocated copy of3::Integer
, which can't possibly be 3.Explanation
It will be a bit easier to understand with a little expansion, based on type defaulting. With signatures, we can drop the addition.
Equivalently,
Why does it ever print 3? This seems surprising! Well, small
Integer
values are represented very much likeInt
s, which (with strict data) are represented just likeD
s. We end up ignoring the tag indicating whether the integer is small or large positive/negative.Why can't it print 3 without the extension? Leaving aside any memory layout reasons, a data pointer with low bits (2 lowest for 32-bit, 3 lowest for 64-bit) of 3 must represent a value built from the third constructor. In this case, that would require a negative integer.
fonte
UnboxedTuples, 52 bytes
Requires
-XTemplateHaskell
. PrintsConE GHC.Prim.(##)
with -XUnboxedTuples andUnboundVarE ##
with -XNoUnboxedTuples.fonte
-XTemplateHaskell
?OverloadedLists, 76 bytes
With -XOverloadedLists it prints
[()]
. With -XNoOverloadedLists it prints[]
This requires the additional flags:
-XFlexibleInstances
,-XIncoherentInstances
fonte
HexFloatLiterals,
4925 bytes-24 bytes thanks to Ørjan Johansen.
Prints
0.0
with-XHexFloatLiterals
and0
with-XNoHexFloatLiterals
.There are no TIO links because HexFloatLiterals was added in ghc 8.4.1, but TIO has ghc 8.2.2.
fonte
main|(.)<-seq=print$0x0.0
avoids the import hiding.main|let _._=0=print$0x0.0
might be easier for the polyglot though.ScopedTypeVariables, 37 bytes
This also requires
UnicodeSyntax
,PartialTypeSignatures
,GADTs
, andExplicitForAll
.Try it online (without extension)
Try it online (with extension)
Explanation
The partial type signatures are just to save bytes. We can fill them in like so:
With scoped type variables, the
a
in the type of1
is constrained to be thea
in the type ofmain
, which itself is constrained to beFloat
. Without scoped type variables,1
defaults to typeInteger
. SinceFloat
andInteger
values are shown differently, we can distinguish them.Thanks to @ØrjanJohansen for a whopping 19 bytes! He realized that it was much better to take advantage of the difference between
Show
instances of different numerical types than differences in their arithmetic. He also realized that it was okay to leave the type ofmain
"syntactically ambiguous" because the constraint actually disambiguates it. Getting rid of the local function also freed me up to remove the type signature formain
(shifting it to the RHS) to save five more bytes.fonte
DeriveAnyClass,
121113 bytesThanks to dfeuer for quite some bytes!
-XDeriveAnyClass prints
1
whereas -XNoDeriveAnyClass printsM 0
.This is exploiting the fact that DeriveAnyClass is the default strategy when both DeriveAnyClass and GeneralizedNewtypeDeriving are enabled, as you can see from the warnings. This flag will happily generate empty implementations for all methods but GeneralizedNewtypeDeriving is actually smart enough to use the underlying type's implementation and since
Int
is aNum
it won't fail in this case.If printing nothing in case the flag is enabled replacing the
main
by the following would be 109 bytes:fonte
runhaskell
, this actually printsM 1
with-XDeriveAnyClass
, due to laziness...1
:)PostfixOperators, 63 bytes
Try it online (without extension)
Try it online (with extension)
This is a cut-down version of a Hugs/GHC polyglot I wrote. See that post for explanation. Thanks to @ØrjanJohansen for realizing I could use
id
instead of a custom operator, saving four bytes.fonte
id
can be used instead of!
.DeriveAnyClass, 104 bytes
Try it online (without extension)
Try it online (with extension)
Also requires
GeneralizedNewtypeDeriving
.fonte
StrictData, 97 bytes
Try it online (no strict data)
Try it online (strict data)
Also requires
DeriveGeneric
.fonte
UnicodeSyntax, 33 bytes
Try it online!
fonte
TemplateHaskell,
14091 bytesJust copied from mauke with small modifications. I don't know what's going on.
-49 bytes thanks to Ørjan Johansen.
Try it online!
fonte
$(...)
(no space) is template evaluation syntax when TH is enabled, andTupE[]
("empty tuple") gives()
. UsingShow
might work well for the polyglot, although for this particular challenge I feel a bit bad about defining a value to print as an empty string...MonomorphismRestriction,
3129 bytesEdit:
-XMonomorphismRestriction prints
0
. -XNoMonomorphismRestriction prints18446744073709551616
.f
are forced to be the same type, so the program prints2^2^6 = 2^64
as a 64-bitInt
(on 64-bit platforms), which overflows to0
.2^64
as a bignumInteger
.fonte
f=(2^);main=print$f$f(64::Int)
would save a byte. But it won't realistically terminate64=2^6
, which saves yet another byte.ScopedTypeVariables,
11997 bytesJust copied from mauke with small modifications.
Currently there are two other answers for ScopedTypeVariables: 113 bytes by Csongor Kiss and 37 bytes by dfeuer. This submission is different in that it does not require other Haskell extensions.
-22 bytes thanks to Ørjan Johansen.
Try it online!
fonte
IO()/print
trick won't work in the polyglot).Num
. I thinkclass(Show a,Floating a)=>K a where{k::a->String;k=pure$ show(f pi)where f=id::a->a};
should work, conveniently using thatFloat
andDouble
displaypi
with different precision.