Espera, ¿qué idioma es este?

37

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)

Pruébalo en línea!

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<-""] -- |]

Pruébalo en línea!

Asistente de trigo
fuente
3
Creo que esta es una lista de todas las opciones válidas
H.PWiz
1
Tenga en cuenta que mi comentario anterior no incluye NondecreasingIndentationpor razones obvias
H.PWiz
44
Creo que este título es engañoso, ya que el único idioma que puedes usar es Haskell. ¿Qué tal Wait, what language extension is this?O algo completamente diferente?
MD XF
1
Estoy bastante curiosidad por saber si es posible romper 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.)
dfeuer
1
@dfeuer Mirando este ticket parece que GHC 6.12.1 soportó apagarlo.
Ørjan Johansen

Respuestas:

24

MagicHash, 30 bytes

x=1
y#a=2
x#a=1
main=print$x#x

-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 funciones y#y x#cada una toma un valor y devuelve una constante 2, o 1. x#xdevolverá 1 (porque se x#aplica a 1)

Sin la extensión, esto define una función #que toma dos argumentos y devuelve 2. El x#a=1es un patrón que nunca se alcanza. Entonces x#xes 1#1, que devuelve 2.

H.PWiz
fuente
2
Ahora estoy cantando X Magic Hash al son de Dance Magic Dance . ¡Espero que estés orgulloso!
TRiG
Me sorprende que MagicHashno permita hashes no finales. ¡Extraño!
dfeuer
18

CPP, 33 20 bytes

main=print$0-- \
 +1

Imprime 0con -XCPPy 1con -XNoCPP.

Con -XCPP, una barra inclinada \antes de una nueva línea elimina la nueva línea, por lo tanto, el código se convierte main=print$0-- +1y solo 0se 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 #define

x=1{-
#define x 0
-}
main=print x

También imprime 0con -XCPPy1 con -XNoCPP.

Laikoni
fuente
2
Oh dios, hasta ahora pensé que GHC despojaría los comentarios de Haskell antes de pasar al CPP.
Cubic
@Cubic ¿No es un preprocesador ?
Bergi
1
@Bergi Claro, pero los preprocesadores no necesariamente significan "es lo primero que se ejecuta", especialmente porque GHC tiene que pasar primero por el archivo para encontrar incluso el pragma. Supongo que los comentarios se guardan en los documentos y en el trabajo similar después de que se realiza el CPP.
Cubic
14

BinaryLiterals, 57 bytes

b1=1
instance Show(a->b)where;show _=""
main=print$(+)0b1

-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.

H.PWiz
fuente
¿No se puede definir simplemente bcomo una función (para que no se convierta en binario b(0, 1), pero se convierte en binario 0b1)?
NoOneIsHere
12

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

module T where
import Language.Haskell.TH
p=(+)
t=reify(mkName"p")>>=stringE.show

Principal, 22 bytes

import T
main=print $t

Compilar con el indicador MonomorphismRestriction fuerza el tipo de pa Integer -> Integer -> Integery, por lo tanto, produce el siguiente resultado:

"VarI T.p (AppT (AppT ArrowT (ConT GHC.Integer.Type.Integer)) (AppT (AppT ArrowT (ConT GHC.Integer.Type.Integer)) (ConT GHC.Integer.Type.Integer))) Nothing"

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 los VarTnombres a a):

"VarI T.p (ForallT [KindedTV a StarT] [AppT (ConT GHC.Num.Num) (VarT a)] (AppT (AppT ArrowT (VarT a)) (AppT (AppT ArrowT (VarT a)) (VarT a)))) Nothing"

¡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ón py, si es necesario, banderas adicionales (además -XTemplateHaskell):

Listas sobrecargadas, 106 bytes

Además necesita -XNoMonomorphismRestriction:

p=[]

¡O p :: [a]bien p :: IsList l => l, pruébelos en línea!

OverloadedStrings, 106 bytes

Además necesita -XNoMonomorphismRestriction:

p=""

¡O p :: Stringbien p :: IsString s => s, pruébelos en línea!

PolyKinds, 112 bytes

Esto se debe completamente a @CsongorKiss:

data P a=P 

¡O P :: P abien P :: forall k (a :: k). P a, pruébelos en línea!

MonadComprehensions, 114 bytes

p x=[i|i<-x]

¡O p :: [a] -> [a]bien p :: Monad m => m a -> m a, pruébelos en línea!

NamedWildCards, 114 bytes

Este fue encontrado por @Laikoni, además requiere -XPartialTypeSignatures:

p=id::_a->_a

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

p x=do i<-x;pure i

¡O p :: Monad m => m a -> m abien p :: Functor f => f a -> f a, pruébelos en línea!

OverloadedLabels, 120 bytes

Esto necesita la bandera adicional -XFlexibleContexts:

p x=(#id)x
(#)=seq

¡Escribe como p :: a -> b -> bo p :: IsLabel "id" (a->b) => a -> b, pruébalos en línea!

ბიმო
fuente
¿Algo similar funciona para otras banderas?
H.PWiz
Sí, podrías hacerlo con OverloadedStringso OverloadedListscon seguridad y probablemente también con otros ...
ბიმო
2
También funciona con PolyKinds: ¡ Pruébelo en línea!
Csongor Kiss
1
También parece funcionar con NamedWildCards: ¡ Pruébelo en línea! (Requiere -XPartialTypeSignatures)
Laikoni
10

CPP, 27 25

main=print({-/*-}1{-*/-})

Pruébalo en línea!

Imprime ()por -XCPPy 1para-XNoCPP

Versión previa:

main=print[1{-/*-},2{-*/-}]

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.

celtschk
fuente
9

ScopedTypeVariables, 162 113 bytes

instance Show[()]where show _=""
p::forall a.(Show a,Show[a])=>a->IO()
p a=(print::Show a=>[a]->IO())[a]
main=p()

-XScopedTypeVariables impresiones"" (vacío), -XNoScopedTypeVariables imprime "[()]".

Editar: solución actualizada gracias a sugerencias útiles en los comentarios

Beso Csongor
fuente
1
Ah, ya veo. En general, es mejor incluir su código en el cuerpo, pero las versiones sin golf también son agradables. También me doy cuenta de que "T"solo se puede reemplazar "".
Wheat Wizard
2
Otra cosa que puede hacer es reemplazar su tipo de datos Tcon (). Para evitar tener que definirlo. Pruébalo en línea!
Wheat Wizard
1
Buena captura, me acabo de dar cuenta de que el pragma incoherente se puede incluir como una bandera: ¡ Pruébelo en línea!
Csongor Kiss
2
Además show se puede cambiar para imprimir
H.PWiz
La sintaxis Unicode para forallle ahorrará algunos bytes. Sin embargo, dudo que cualquier solución que necesite instancias adicionales tenga muchas esperanzas de ganar.
dfeuer
9

MonoLocalBinds, GADTs o TypeFamilies, 36 32 bytes

EDITAR:

  • -4 bytes: Stasoid incorporó una versión de esto en la gran cadena políglota , que me sorprendió al poner todas las declaraciones en el nivel más alto. Aparentemente, desencadenar esta restricción no requiere enlaces locales reales .
a=0
f b=b^a
main=print(f pi,f 0)
  • Sin extensiones , este programa imprime (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.

  • que es posible apagarlo de nuevo explícitamente-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 como leto where, por lo tanto, el nombre aparentemente 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.

  • Sin ninguna extensión, los anteriores infiere programar el tipo f :: Num a => a -> a, permitiendo f pipor defecto a una Doubleyf 0 a una Integer.

  • Con las extensiones, el tipo inferido se convierte en f :: Double -> Double, yf 0 tiene que devolver unDouble .
  • La variable separada a=0es necesaria para activar las reglas técnicas: aes afectada por la restricción de monomorfismo, y aes una variable libre de f, lo que significa que fel grupo de enlace no está completamente generalizado , lo que significa que fno está cerrado y, por lo tanto, no se vuelve polimórfico.
Ørjan Johansen
fuente
9

OverloadedStrings, 65 48 32 bytes

Aprovechando RebindableSyntax, use nuestra propia versión de fromString para convertir cualquier cadena literal "y".

main=print""
fromString _=['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

main=print[0]
fromListN=(:)

Debe ser compilado con -XRebindableSyntax -XImplicitPrelude .

Sin -XOverloadedListshuellas [0]; con estampados [1,0].

Felixphew
fuente
1
Puedes acortar la última línea a fromString a=['y'].
Ørjan Johansen el
El espacio print "n"también se puede soltar.
Laikoni
@ ØrjanJohansen gracias! Me estaba fallando ="y", ¡pero =['y']funciona bien!
Felixphew
1
Puedes quitar el segundo ndeprint"n"
Wheat Wizard
1
También puede usar -XImplicitPreludedespués RebindableSyntaxpara evitar la línea de importación.
dfeuer
8

BangPatterns, 32 bytes

(!)=seq
main|let f!_=0=print$9!1

-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 caso 9!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
7

ApplicativeDo, 104 bytes

import Control.Applicative
z=ZipList
instance Monad ZipList where _>>=_=z[]
main=print$do a<-z[1];pure a

Pruébalo en línea!

Con ApplicativeDoesto imprime

ZipList {getZipList = [1]}

Sin ella, imprime

ZipList {getZipList = []}

ZipListes uno de los pocos tipos en las bibliotecas base con una instancia para Applicativepero no para Monad. Puede haber alternativas más cortas que acechan en alguna parte.

Zgarb
fuente
7

Estricto, 87 84 82 bytes

-5 bytes gracias a dfeuer !

Podría ser menos BlockArgumentssalvando a los padres \_->print 1:

import Control.Exception
0!_=0
main=catch @ErrorCall(print$0!error"")(\_->print 1)

Ejecutar esto con -XStrict imprime a 1mientras que ejecutarlo con -XNoStrict imprimirá a 0. Esto usa que Haskell por defecto es vago y no necesita evaluar error""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 ):

main=catch @ErrorCall(print$0!error"")mempty

StrictData, 106 99 93 bytes

-15 bytes gracias a dfeuer !

Básicamente, hace lo mismo, pero funciona con campos de datos:

import Control.Exception
data D=D()
main=catch @ErrorCall(p$seq(D$error"")0)(\_->p 1);p=print

Imprime 1con el distintivo -XStrictData y 0con -XNoStrictData .

Si no se permite imprimir nada en un caso, podemos reducirlo a 86 bytes reemplazando el principal por (19 bytes desactivados por dfeuer ):

main=catch @ErrorCall(print$seq(D$error"")0)mempty

Nota: Todas las soluciones requieren TypeApplicationsconjunto.

ბიმო
fuente
Puede reducir esto fácilmente a 98 bytes, lo que coincide exactamente con mi solución (muy diferente). TIO .
dfeuer
En realidad, puede hacerlo aún mejor: en lugar de imprimir en el controlador de excepciones, simplemente utilícelo pure().
dfeuer
1
@dfeuer: Bien, ¡el D{}truco es genial! Afeitado otro usando en PartialTypeSignatureslugar de ScopedTypeVariables:)
ბიმო
1
@dfeuer: eché un vistazo e intenté algunas cosas, pero nunca usé genéricos, así que probablemente no soy la persona adecuada.
ბიმო
1
Puede hacerlo aún mejor con GHC de -XBlockArgumentsmain=catch @ErrorCall(p$seq(D$error"")1)\_->p 3
última generación
6

ApplicativeDo, 146 bytes

newtype C a=C{u::Int}
instance Functor C where fmap _ _=C 1
instance Applicative C
instance Monad C where _>>=_=C 0
main=print$u$do{_<-C 0;pure 1}

Imprime 1 cuando ApplicativeDo está habilitado, 0 de lo contrario

Pruébalo en línea!

oisdk
fuente
1
¡Gracias! Ah, creo que estoy en una versión anterior de GHC (el "no aplicativo" fue una advertencia en mi sistema)
oisdk
3
Usando -XDeriveAnyClass puede derivar Applicativey Showguardar usando la sintaxis de registro, vea esto .
ბიმო
6

BinaryLiterals, 31 24 bytes

Editar:

  • -7 bytes: H.PWiz sugirió ajustarlo aún más usando una sola b12variable.

Un ajuste al método de H.PWiz , evitando la instancia de la función.

b12=1
main=print$(+)0b12
Ørjan Johansen
fuente
6

ExtendedDefaultRules, 54 53 bytes

instance Num()
main=print(toEnum 0::Num a=>Enum a=>a)

Imprime ()con -XExtendedDefaultRulesy 0con -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 !

Laikoni
fuente
Mientras miraba este código prestado en el políglota (donde los paréntesis dan algunos problemas), recordé que GHC admite la sintaxis más corta de un byte toEnum 0::Num a=>Enum a=>a.
Ørjan Johansen
Se puede conseguir hasta 48 bytes con PartialTypeSignatures: main=print(toEnum 0::_=>Num a=>a). Además, su enlace TIO está desactualizado.
dfeuer
6

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í.

main|negate<-id=print$ -1

Also requires -XImplicitPrelude, or alternatively import 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 for negate 1.
  • Normally this negate is Prelude.negate, but with the extension it's "whichever negate is in scope at the point of use", which is defined as id.
  • Because the extension is meant to be used to make replacements for the Prelude module, it automatically disables the usual implicit import of that, but other Prelude functions (like print) are needed here, so it is re-enabled with -XImplicitPrelude.
Ørjan Johansen
fuente
6

Strict, 52 bytes

import GHC.IO
f _=print()
main=f$unsafePerformIO$f()

-XStrict

-XNoStrict

With -XStrict, prints () an extra time.

Thanks to @Sriotchilism O'Zaic for two bytes.

dfeuer
fuente
6

StrictData, 58 bytes

import GHC.Exts
data D=D Int
main=print$unsafeCoerce#D 3+0

(Los enlaces están un poco desactualizados; se solucionarán).

-XNoStrictData

-XStrictData

Requiere MagicHash(para permitirnos importar en GHC.Extslugar de Unsafe.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 de 3::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.

main=print
  (unsafeCoerce# D (3::Integer)
    :: Integer)

Equivalentemente

main=print
  (unsafeCoerce# $
    D (unsafeCoerce# (3::Integer))
    :: Integer)

¿Por qué alguna vez imprime 3? Esto parece sorprendente! Bueno, los Integervalores pequeños se representan de forma muy similar a Ints, que (con datos estrictos) se representan igual que Ds. 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 .

dfeuer
fuente
5

UnboxedTuples, 52 bytes

import Language.Haskell.TH
main=runQ[|(##)|]>>=print

Requires -XTemplateHaskell. Prints ConE GHC.Prim.(##) with -XUnboxedTuples and UnboundVarE ## with -XNoUnboxedTuples.

Laikoni
fuente
Shouldn't there be another +16 in the score for the required option -XTemplateHaskell?
celtschk
2
@celtschk I did not count it because the current meta consensus on command line flags says they are not counted but constitute a new language instead. Though upon thinking about it I see that in the context of this challenge which only allows Haskell answers but also the use of other flags it is not quite clear what todo. I'll ask OP about it.
Laikoni
I wasn't aware that the consensus on this has changed. Thank you for the pointer. Asking the OP is a good idea for sure.
celtschk
5

OverloadedLists, 76 bytes

import GHC.Exts
instance IsList[()]where fromList=(():)
main=print([]::[()])

With -XOverloadedLists it prints [()]. With -XNoOverloadedLists it prints []

This requires the additional flags: -XFlexibleInstances, -XIncoherentInstances

H.PWiz
fuente
You can get away with overlapping instances.
dfeuer
5

HexFloatLiterals, 49 25 bytes

-24 bytes thanks to Ørjan Johansen.

main|(.)<-seq=print$0x0.0

Prints 0.0 with -XHexFloatLiterals and 0 with -XNoHexFloatLiterals.

There are no TIO links because HexFloatLiterals was added in ghc 8.4.1, but TIO has ghc 8.2.2.

stasoid
fuente
main|(.)<-seq=print$0x0.0 avoids the import hiding.
Ørjan Johansen
main|let _._=0=print$0x0.0 might be easier for the polyglot though.
Ørjan Johansen
5

ScopedTypeVariables, 37 bytes

main=print(1::_=>a):: a.a~Float=>_

This also requires UnicodeSyntax,PartialTypeSignatures, GADTs, and ExplicitForAll.

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:

main=print(1::(Num a, Show a)=>a):: a.a~Float=>IO ()

With scoped type variables, the a in the type of 1 is constrained to be the a in the type of main, which itself is constrained to be Float. Without scoped type variables, 1 defaults to type Integer. Since Float and Integer 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 of main "syntactically ambiguous" because the constraint actually disambiguates it. Getting rid of the local function also freed me up to remove the type signature for main (shifting it to the RHS) to save five more bytes.

dfeuer
fuente
45 bytes
Ørjan Johansen
@ØrjanJohansen, nice.
dfeuer
@ØrjanJohansen, should I make the edit, or would you prefer to add your own?
dfeuer
Edit, it was a gradual evolution from yours.
Ørjan Johansen
@ØrjanJohansen, thanks, that was beautiful.
dfeuer
5

DeriveAnyClass, 121 113 bytes

Thanks to dfeuer for quite some bytes!

import Control.Exception
newtype M=M Int deriving(Show,Num)
main=handle h$print(0::M);h(_::SomeException)=print 1

-XDeriveAnyClass prints 1 whereas -XNoDeriveAnyClass prints M 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 a Num 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:

main=print(0::M)`catch`(mempty::SomeException->_)
ბიმო
fuente
At least in runhaskell, this actually prints M 1 with -XDeriveAnyClass, due to laziness...
ceased to turn counterclockwis
@ceasedtoturncounterclockwis: Yes in GHCi as well, but when compiling on TIO (and my machine) & then running it results in 1 :)
ბიმო
113 bytes
dfeuer
109 bytes
dfeuer
1
I got it down to 104 in a completely different way, so I added my own answer.
dfeuer
3

TemplateHaskell, 140 91 bytes

Just copied from mauke with small modifications. I don't know what's going on.

-49 bytes thanks to Ørjan Johansen.

import Language.Haskell.TH
instance Show(Q a)where show _=""
main=print$(pure$TupE[]::ExpQ)

Try it online!

stasoid
fuente
$(...) (no space) is template evaluation syntax when TH is enabled, and TupE[] ("empty tuple") gives (). Using Show 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...
Ørjan Johansen
2

MonomorphismRestriction, 31 29 bytes

Edit:

  • -2 bytes with an improvement by H.PWiz
f=(2^)
main=print$f$f(6::Int)

-XMonomorphismRestriction prints 0. -XNoMonomorphismRestriction prints 18446744073709551616.

  • With the restriction, the two uses of f are forced to be the same type, so the program prints 2^2^6 = 2^64 as a 64-bit Int (on 64-bit platforms), which overflows to 0.
  • Without the restriction, the program prints 2^64 as a bignum Integer.
Ørjan Johansen
fuente
1
I think f=(2^);main=print$f$f(64::Int) would save a byte. But it won't realistically terminate
H.PWiz
@H.PWiz Fortunately 64=2^6, which saves yet another byte.
Ørjan Johansen
1

ScopedTypeVariables, 119 97 bytes

Just 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.

class(Show a,Num a)=>S a where s::a->IO();s _=print$(id::a->a)0
instance S Float
main=s(0::Float)

Try it online!

stasoid
fuente
97 bytes (although the IO()/print trick won't work in the polyglot).
Ørjan Johansen
@ØrjanJohansen I added ScopedTypeVariables, but broke ExtendedDefaultRules. How it can be fixed? I already had such error before, but I am unable to apply your explanation here. The ScopedTypeVariables code I added is this.
stasoid
I see, the codes use similar defaulting tricks, and they interfer with each other. One solution is to let the new one use a more restricted class than Num. I think class(Show a,Floating a)=>K a where{k::a->String;k=pure$ show(f pi)where f=id::a->a}; should work, conveniently using that Float and Double display pi with different precision.
Ørjan Johansen
@ØrjanJohansen Wow, it fits right in. Thank you.
stasoid