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!


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.


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.


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.


¿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!


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


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


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.

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


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.


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.


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.


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!


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

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 !


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.

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.


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 .


5

UnboxedTuples, 52 bytes

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

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


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


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.


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.



@Ø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->_)

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 :)
ბიმო



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!


$(...) (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.

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!


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.