Recientemente tuve el placer de escribir un programa Haskell que podía detectar si la NegativeLiteralsextensió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á Truenormalmente y de Falseotra 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 Noprefijo 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 1y -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 -Osin costo alguno para el recuento de bytes.
Extensiones de idioma
No se puede romper cualquier extensión del lenguaje que no tiene una Nocontraparte (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 NegativeLiteralso QuasiQuotesporque 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

NondecreasingIndentationpor 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#xdevolverá 1 (porque sex#aplica a1)Sin la extensión, esto define una función
#que toma dos argumentos y devuelve2. Elx#a=1es un patrón que nunca se alcanza. Entoncesx#xes1#1, que devuelve 2.fuente
MagicHashno permita hashes no finales. ¡Extraño!CPP,
3320 bytesImprime
0con-XCPPy1con-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-- +1y solo0se imprime, ya+1que 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
#defineTambién imprime
0con-XCPPy1con-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
bcomo 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
-XTemplateHaskellen todo momento.Archivo T.hs, 81 + 4 bytes
Principal, 22 bytes
Compilar con el indicador MonomorphismRestriction fuerza el tipo de
paInteger -> Integer -> Integery, por lo tanto, produce el siguiente resultado:Compilar con la bandera NoMonomorphismRestriction deja el tipo de
pa lo más general, es decir.Num a => a->a->a- produciendo algo como (acortar losVarTnombres 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ónpy, 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 :: Stringbienp :: IsString s => s, pruébelos en línea!PolyKinds, 112 bytes
Esto se debe completamente a @CsongorKiss:
¡O
P :: P abienP :: 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 abienp :: 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 -> bop :: IsLabel "id" (a->b) => a -> b, pruébalos en línea!fuente
OverloadedStringsoOverloadedListscon 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-XCPPy1para-XNoCPPVersión previa:
Pruébalo en línea!
Imprime
[1]con-XCPPy de[1,2]otra manera.Créditos: esto está inspirado en la respuesta de Laikoni, pero en lugar de una
#definesimplemente 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"".Tcon(). Para evitar tener que definirlo. Pruébalo en línea!showse puede cambiar para imprimirforallle 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
MonoLocalBindsextensió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,
MonoLocalBindsfunciona 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.letowhere, por lo tanto, el nombreSin ninguna extensión, los anteriores infiere programar el tipo
f :: Num a => a -> a, permitiendof pipor defecto a unaDoubleyf 0a unaInteger.f :: Double -> Double, yf 0tiene que devolver unDouble.a=0es necesaria para activar las reglas técnicas:aes afectada por la restricción de monomorfismo, yaes una variable libre def, lo que significa quefel grupo de enlace no está completamente generalizado , lo que significa quefno 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
-XOverloadedStringshuellas""; 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
-XOverloadedListshuellas[0]; con estampados[1,0].fuente
fromString a=['y'].print "n"también se puede soltar.="y", ¡pero=['y']funciona bien!ndeprint"n"-XImplicitPreludedespuésRebindableSyntaxpara evitar la línea de importación.BangPatterns, 32 bytes
-XBangPatterns imprime
1mientras que -XNoBangPatterns imprime0.Esto hace uso de que la bandera BangPatterns permite anotar patrones con una
!evaluación forzada a WHNF, en ese caso9!1usará 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
ApplicativeDoesto imprimeSin ella, imprime
ZipListes uno de los pocos tipos en las bibliotecas base con una instancia paraApplicativepero 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
BlockArgumentssalvando a los padres\_->print 1:Ejecutar esto con -XStrict imprime a
1mientras 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á0cuando 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
1con el distintivo -XStrictData y0con -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
TypeApplicationsconjunto.fuente
pure().D{}truco es genial! Afeitado otro usando enPartialTypeSignatureslugar deScopedTypeVariables:)-XBlockArgumentsmain=catch @ErrorCall(p$seq(D$error"")1)\_->p 3ApplicativeDo, 146 bytes
Imprime 1 cuando ApplicativeDo está habilitado, 0 de lo contrario
Pruébalo en línea!
fuente
ApplicativeyShowguardar usando la sintaxis de registro, vea esto .BinaryLiterals,
3124 bytesEditar:
b12variable.Un ajuste al método de H.PWiz , evitando la instancia de la función.
0b12como0b12, imprimiendo 0 + 1 =1.0b12como0b12, imprimiendo 1 + 2 =3.fuente
ExtendedDefaultRules,
5453 bytesImprime
()con-XExtendedDefaultRulesy0con-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 Preludein the code itself.-XRebindableSyntaxchanges the behavior of some of Haskell's syntactic sugar to make it possible to redefine it.-1is syntactic sugar fornegate 1.negateisPrelude.negate, but with the extension it's "whichevernegateis in scope at the point of use", which is defined asid.Preludemodule, it automatically disables the usual implicit import of that, but otherPreludefunctions (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.Extslugar 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
Integervalores pequeños se representan de forma muy similar aInts, que (con datos estrictos) se representan igual queDs. 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,-XIncoherentInstancesfuente
HexFloatLiterals,
4925 bytes-24 bytes thanks to Ørjan Johansen.
Prints
0.0with-XHexFloatLiteralsand0with-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.0avoids the import hiding.main|let _._=0=print$0x0.0might 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
ain the type of1is constrained to be theain the type ofmain, which itself is constrained to beFloat. Without scoped type variables,1defaults to typeInteger. SinceFloatandIntegervalues 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
Showinstances 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
1whereas -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
Intis aNumit won't fail in this case.If printing nothing in case the flag is enabled replacing the
mainby the following would be 109 bytes:fuente
runhaskell, this actually printsM 1with-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
idinstead of a custom operator, saving four bytes.fuente
idcan 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(). UsingShowmight 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.fare forced to be the same type, so the program prints2^2^6 = 2^64as a 64-bitInt(on 64-bit platforms), which overflows to0.2^64as 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()/printtrick 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 thatFloatandDoubledisplaypiwith different precision.