Recientemente tuve el placer de escribir un programa Haskell que podía detectar si la NegativeLiterals
extensión estaba activada. Se me ocurrió lo siguiente:
data B=B{u::Integer}
instance Num B where{fromInteger=B;negate _=B 1}
main=print$1==u(-1)
Esto se imprimirá True
normalmente y de False
otra manera.
Ahora me divertí tanto haciendo esto que estoy extendiendo el desafío a todos ustedes. ¿Qué otras extensiones de lenguaje Haskell puedes descifrar?
Reglas
Para descifrar una extensión de idioma en particular, debe escribir un programa Haskell que compile con y sin la extensión de idioma (las advertencias están bien) y genera dos valores diferentes sin errores cuando se ejecuta con la extensión de idioma y se apaga (agregando el No
prefijo a la extensión del lenguaje). De esta manera, el código anterior se podría acortar a solo:
data B=B{u::Integer}
instance Num B where{fromInteger=B;negate _=B 1}
main=print$u(-1)
que imprime 1
y -1
.
Cualquier método que use para descifrar una extensión debe ser específico para esa extensión. Puede haber formas de detectar arbitrariamente qué indicadores del compilador o LanguageExtensions están habilitados, de ser así, dichos métodos no están permitidos. Puede habilitar extensiones de idioma adicionales o cambiar la optimización del compilador -O
sin costo alguno para el recuento de bytes.
Extensiones de idioma
No se puede romper cualquier extensión del lenguaje que no tiene una No
contraparte (por ejemplo Haskell98
, Haskell2010
, Unsafe
, Trustworthy
, Safe
), ya que éstos no entran en los términos antes expuestos. Cualquier otra extensión de idioma es un juego justo.
Tanteo
Se le otorgará un punto por cada extensión de idioma que sea la primera persona en descifrar y un punto adicional por cada extensión de idioma para la que tenga la grieta más corta (medida en bytes). Para el segundo punto, los lazos se romperán a favor de las presentaciones anteriores. Mayor puntaje es mejor
No podrá obtener un punto para la primera presentación en NegativeLiterals
o QuasiQuotes
porque ya los descifré y los incluí en el cuerpo de la publicación. Sin embargo, podrá obtener un punto por el crack más corto de cada uno de estos. Aquí está mi crack deQuasiQuotes
import Text.Heredoc
main=print[here|here<-""] -- |]
fuente
NondecreasingIndentation
por razones obviasWait, what language extension is this?
O algo completamente diferente?RelaxedPolyRec
, para una lo suficientemente antigua compilador que realmente apoyar apagarlo. (La opción estuvo pendiente, con documentación, durante algunos años después de que dejó de hacer nada.)Respuestas:
MagicHash, 30 bytes
-XMagicHash salidas 1, -XNoMagicHash salidas 2
MagicHash permite que los nombres de variables terminen en a
#
. Por lo tanto, con la extensión, esto define dos funcionesy#
yx#
cada una toma un valor y devuelve una constante2
, o1
.x#x
devolverá 1 (porque sex#
aplica a1
)Sin la extensión, esto define una función
#
que toma dos argumentos y devuelve2
. Elx#a=1
es un patrón que nunca se alcanza. Entoncesx#x
es1#1
, que devuelve 2.fuente
MagicHash
no permita hashes no finales. ¡Extraño!CPP,
3320 bytesImprime
0
con-XCPP
y1
con-XNoCPP
.Con
-XCPP
, una barra inclinada\
antes de una nueva línea elimina la nueva línea, por lo tanto, el código se conviertemain=print$0-- +1
y solo0
se imprime, ya+1
que ahora forma parte del comentario.Sin la bandera, el comentario se ignora y la segunda línea se analiza como parte de la línea anterior porque está sangrada.
Enfoque previo con
#define
También imprime
0
con-XCPP
y1
con-XNoCPP
.fuente
NumDecimals, 14 bytes
-XNumDecimals impresiones
10
. -XNoNumDecimals imprime10.0
.fuente
BinaryLiterals, 57 bytes
-XBinaryLiterals imprime una nueva línea. -XNoBinaryLiterals imprime a
1
.Estoy seguro de que hay una mejor manera de hacer esto. Si encuentra uno, publíquelo.
fuente
b
como una función (para que no se convierta en binariob(0, 1)
, pero se convierte en binario0b1
)?Restricción de monomorfismo + 7 más, 107 bytes
Esto usa TH que requiere la bandera
-XTemplateHaskell
en todo momento.Archivo T.hs, 81 + 4 bytes
Principal, 22 bytes
Compilar con el indicador MonomorphismRestriction fuerza el tipo de
p
aInteger -> Integer -> Integer
y, por lo tanto, produce el siguiente resultado:Compilar con la bandera NoMonomorphismRestriction deja el tipo de
p
a lo más general, es decir.Num a => a->a->a
- produciendo algo como (acortar losVarT
nombres aa
):¡Pruébalos en línea!
Alternativas
Dado que el código anterior simplemente imprime el tipo de
p
, esto se puede hacer con todas las banderas que de alguna manera influyen en cómo Haskell infiere los tipos. Solo especificaré la bandera y con qué reemplazar la funciónp
y, si es necesario, banderas adicionales (además-XTemplateHaskell
):Listas sobrecargadas, 106 bytes
Además necesita
-XNoMonomorphismRestriction
:¡O
p :: [a]
bienp :: IsList l => l
, pruébelos en línea!OverloadedStrings, 106 bytes
Además necesita
-XNoMonomorphismRestriction
:¡O
p :: String
bienp :: IsString s => s
, pruébelos en línea!PolyKinds, 112 bytes
Esto se debe completamente a @CsongorKiss:
¡O
P :: P a
bienP :: forall k (a :: k). P a
, pruébelos en línea!MonadComprehensions, 114 bytes
¡O
p :: [a] -> [a]
bienp :: Monad m => m a -> m a
, pruébelos en línea!NamedWildCards, 114 bytes
Este fue encontrado por @Laikoni, además requiere
-XPartialTypeSignatures
:Ambos tienen el tipo de guardado (
p :: a -> a
) pero GHC genera diferentes nombres para las variables, ¡ pruébelos en línea!ApplicativeDo, 120 bytes
¡O
p :: Monad m => m a -> m a
bienp :: Functor f => f a -> f a
, pruébelos en línea!OverloadedLabels, 120 bytes
Esto necesita la bandera adicional
-XFlexibleContexts
:¡Escribe como
p :: a -> b -> b
op :: IsLabel "id" (a->b) => a -> b
, pruébalos en línea!fuente
OverloadedStrings
oOverloadedLists
con seguridad y probablemente también con otros ...PolyKinds
: ¡ Pruébelo en línea!NamedWildCards
: ¡ Pruébelo en línea! (Requiere-XPartialTypeSignatures
)CPP,
2725Pruébalo en línea!
Imprime
()
por-XCPP
y1
para-XNoCPP
Versión previa:
Pruébalo en línea!
Imprime
[1]
con-XCPP
y de[1,2]
otra manera.Créditos: esto está inspirado en la respuesta de Laikoni, pero en lugar de una
#define
simplemente usa comentarios en C.fuente
ScopedTypeVariables,
162113 bytes-XScopedTypeVariables impresiones
""
(vacío), -XNoScopedTypeVariables imprime"[()]"
.Editar: solución actualizada gracias a sugerencias útiles en los comentarios
fuente
"T"
solo se puede reemplazar""
.T
con()
. Para evitar tener que definirlo. Pruébalo en línea!show
se puede cambiar para imprimirforall
le ahorrará algunos bytes. Sin embargo, dudo que cualquier solución que necesite instancias adicionales tenga muchas esperanzas de ganar.MonoLocalBinds, GADTs o TypeFamilies,
3632 bytesEDITAR:
(1.0,1)
.Con cualquiera de las banderas -XMonoLocalBinds , -XGADTs o -XTypeFamilies , imprime
(1.0,1.0)
.los
MonoLocalBinds
extensión existe para evitar alguna inferencia de tipo no intuitiva desencadenada por GADT y familias de tipos. Como tal, esta extensión se activa automáticamente por los otros dos.-XNoMonoLocalBinds
, este truco se supone que no lo hace.Al igual que su primo más conocido, la restricción de monomorfismo,
MonoLocalBinds
funciona evitando que algunos valores (en enlaces locales comoaparentemente también puede ocurrir en el nivel superior) sean polimórficos. A pesar de haberse creado para una inferencia de tipo más sensata, las reglas para cuando se dispara son, si es posible, aún más peludas que la MR.let
owhere
, por lo tanto, el nombreSin ninguna extensión, los anteriores infiere programar el tipo
f :: Num a => a -> a
, permitiendof pi
por defecto a unaDouble
yf 0
a unaInteger
.f :: Double -> Double
, yf 0
tiene que devolver unDouble
.a=0
es necesaria para activar las reglas técnicas:a
es afectada por la restricción de monomorfismo, ya
es una variable libre def
, lo que significa quef
el grupo de enlace no está completamente generalizado , lo que significa quef
no está cerrado y, por lo tanto, no se vuelve polimórfico.fuente
OverloadedStrings,
654832 bytesAprovechando RebindableSyntax, use nuestra propia versión de fromString para convertir cualquier cadena literal
"y"
.Debe ser compilado con
-XRebindableSyntax -XImplicitPrelude
.Sin
-XOverloadedStrings
huellas""
; con estampados"y"
.Además, recién ahora me di cuenta de que la misma técnica funciona con (por ejemplo) OverloadedLists:
Listas sobrecargadas, 27 bytes
Debe ser compilado con
-XRebindableSyntax -XImplicitPrelude
.Sin
-XOverloadedLists
huellas[0]
; con estampados[1,0]
.fuente
fromString a=['y']
.print "n"
también se puede soltar.="y"
, ¡pero=['y']
funciona bien!n
deprint"n"
-XImplicitPrelude
despuésRebindableSyntax
para evitar la línea de importación.BangPatterns, 32 bytes
-XBangPatterns imprime
1
mientras que -XNoBangPatterns imprime0
.Esto hace uso de que la bandera BangPatterns permite anotar patrones con una
!
evaluación forzada a WHNF, en ese caso9!1
usará la definición de nivel superior(!)=seq
. Si el indicador no está habilitado,f!_
define un nuevo operador(!)
y sombrea la definición de nivel superior.fuente
ApplicativeDo, 104 bytes
Pruébalo en línea!
Con
ApplicativeDo
esto imprimeSin ella, imprime
ZipList
es uno de los pocos tipos en las bibliotecas base con una instancia paraApplicative
pero no paraMonad
. Puede haber alternativas más cortas que acechan en alguna parte.fuente
Estricto,
87 8482 bytes-5 bytes gracias a dfeuer !
Podría ser menos
BlockArguments
salvando a los padres\_->print 1
:Ejecutar esto con -XStrict imprime a
1
mientras que ejecutarlo con -XNoStrict imprimirá a0
. Esto usa que Haskell por defecto es vago y no necesita evaluarerror""
ya que ya sabe que el resultado será0
cuando coincida con el primer argumento de(!)
, este comportamiento se puede cambiar con ese indicador, lo que obliga al tiempo de ejecución a evaluar ambos argumentos.Si no se permite imprimir nada en un caso, podemos reducirlo a 75 bytes reemplazando el principal por (también algunos bytes desactivados por dfeuer ):
StrictData,
106 9993 bytes-15 bytes gracias a dfeuer !
Básicamente, hace lo mismo, pero funciona con campos de datos:
Imprime
1
con el distintivo -XStrictData y0
con -XNoStrictData .Si no se permite imprimir nada en un caso, podemos reducirlo a 86 bytes reemplazando el principal por (19 bytes desactivados por dfeuer ):
Nota: Todas las soluciones requieren
TypeApplications
conjunto.fuente
pure()
.D{}
truco es genial! Afeitado otro usando enPartialTypeSignatures
lugar deScopedTypeVariables
:)-XBlockArguments
main=catch @ErrorCall(p$seq(D$error"")1)\_->p 3
ApplicativeDo, 146 bytes
Imprime 1 cuando ApplicativeDo está habilitado, 0 de lo contrario
Pruébalo en línea!
fuente
Applicative
yShow
guardar usando la sintaxis de registro, vea esto .BinaryLiterals,
3124 bytesEditar:
b12
variable.Un ajuste al método de H.PWiz , evitando la instancia de la función.
0b12
como0
b12
, imprimiendo 0 + 1 =1
.0b12
como0b1
2
, imprimiendo 1 + 2 =3
.fuente
ExtendedDefaultRules,
5453 bytesImprime
()
con-XExtendedDefaultRules
y0
con-XNoExtendedDefaultRules
.Este indicador está habilitado de manera predeterminada en GHCi, pero no en GHC, lo que recientemente me causó cierta confusión , aunque BMO pudo ayudarme rápidamente.
El código anterior es una versión de golf de un ejemplo en la Guía del usuario de GHC donde se explica el tipo predeterminado en GHCi .
-1 byte gracias a Ørjan Johansen !
fuente
toEnum 0::Num a=>Enum a=>a
.PartialTypeSignatures
:main=print(toEnum 0::_=>Num a=>a)
. Además, su enlace TIO está desactualizado.RebindableSyntax , 25 bytes
Estaba leyendo la Guía recientemente publicada sobre las Extensiones de GHC cuando noté una fácil que aún no recordaba haber visto aquí.
-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
.fuente
Strict, 52 bytes
-XStrict
-XNoStrict
With
-XStrict
, prints()
an extra time.Thanks to @Sriotchilism O'Zaic for two bytes.
fuente
StrictData, 58 bytes
(Los enlaces están un poco desactualizados; se solucionarán).
-XNoStrictData
-XStrictData
Requiere
MagicHash
(para permitirnos importar enGHC.Exts
lugar deUnsafe.Coerce
) y-O
(absolutamente obligatorio, para permitir el desempaquetado de campos estrictos pequeños).Con
-XStrictData
, imprime 3. De lo contrario, imprime el valor entero del puntero (probablemente etiquetado) a la copia preasignada de3::Integer
, que posiblemente no puede ser 3.Explicación
Será un poco más fácil de entender con una pequeña expansión, basada en el tipo predeterminado. Con las firmas, podemos descartar la adición.
Equivalentemente
¿Por qué alguna vez imprime 3? Esto parece sorprendente! Bueno, los
Integer
valores pequeños se representan de forma muy similar aInt
s, que (con datos estrictos) se representan igual queD
s. Terminamos ignorando la etiqueta que indica si el entero es pequeño o grande positivo / negativo.¿Por qué no puede imprimir 3 sin la extensión? Dejando de lado cualquier motivo de diseño de memoria, un puntero de datos con bits bajos (2 más bajos para 32 bits, 3 más bajos para 64 bits) de 3 debe representar un valor construido a partir del tercer constructor. En este caso, eso requeriría un número entero negativo .
fuente
UnboxedTuples, 52 bytes
Requires
-XTemplateHaskell
. PrintsConE GHC.Prim.(##)
with -XUnboxedTuples andUnboundVarE ##
with -XNoUnboxedTuples.fuente
-XTemplateHaskell
?OverloadedLists, 76 bytes
With -XOverloadedLists it prints
[()]
. With -XNoOverloadedLists it prints[]
This requires the additional flags:
-XFlexibleInstances
,-XIncoherentInstances
fuente
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.
fuente
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.fuente
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:fuente
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.fuente
id
can be used instead of!
.DeriveAnyClass, 104 bytes
Try it online (without extension)
Try it online (with extension)
Also requires
GeneralizedNewtypeDeriving
.fuente
StrictData, 97 bytes
Try it online (no strict data)
Try it online (strict data)
Also requires
DeriveGeneric
.fuente
UnicodeSyntax, 33 bytes
Try it online!
fuente
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!
fuente
$(...)
(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
.fuente
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!
fuente
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.