Aspetta, che lingua è questa?


37

Di recente ho avuto il piacere di scrivere un programma Haskell in grado di rilevare se l' NegativeLiteralsestensione era attiva. Ho pensato a quanto segue:

data B=B{u::Integer}
instance Num B where{fromInteger=B;negate _=B 1}
main=print$1==u(-1)

Provalo online!

Questo verrà stampato Truenormalmente e Falsealtrimenti.

Ora mi sono divertito così tanto a estendere la sfida a tutti voi. Quali altre estensioni di lingua Haskell puoi decifrare?

Regole

Per decifrare una determinata estensione del linguaggio è necessario scrivere un programma Haskell che compili sia con che senza l'estensione del linguaggio (gli avvisi vanno bene) e genera due differenti valori non di errore quando eseguito con l'estensione del linguaggio e disattivato (aggiungendo il Noprefisso a l'estensione della lingua). In questo modo il codice sopra potrebbe essere abbreviato in solo:

data B=B{u::Integer}
instance Num B where{fromInteger=B;negate _=B 1}
main=print$u(-1)

quale stampa 1e -1.

Qualsiasi metodo utilizzato per decodificare un'estensione deve essere specifico per tale estensione. Ci possono essere modi per rilevare arbitrariamente quali flag del compilatore o LanguageExtensions sono abilitate, se così non sono consentiti tali metodi. È possibile abilitare estensioni di lingua aggiuntive o modificare l'ottimizzazione del compilatore utilizzando gratuitamente -Oil conteggio dei byte.

Estensioni di lingua

Non si può rompere qualsiasi estensione linguaggio che non ha una Nocontroparte (ad esempio Haskell98, Haskell2010, Unsafe, Trustworthy, Safe) perché questi non rientrano nei termini di cui sopra. Ogni altra estensione linguistica è un gioco equo.

punteggio

Ti verrà assegnato un punto per ogni estensione di lingua che sei la prima persona a decifrare e un punto aggiuntivo per ogni estensione di lingua per cui hai il crack più breve (misurato in byte). Per il secondo punto i legami verranno interrotti a favore di precedenti invii. Il punteggio più alto è migliore

Non sarai in grado di segnare un punto per il primo invio NegativeLiteralso QuasiQuotesperché li ho già decifrati e li ho inclusi nel corpo del post. Sarai comunque in grado di segnare un punto per il crack più breve di ognuno di questi. Ecco il mio crack diQuasiQuotes

import Text.Heredoc
main=print[here|here<-""] -- |]

Provalo online!


3
Penso che questo sia un elenco di tutte le opzioni valide
H.Pwiz,

1
Nota che il mio commento sopra non include NondecreasingIndentationper ovvi motivi
H.Pwiz,

4
Penso che questo titolo sia fuorviante, poiché l'unica lingua che puoi usare è Haskell. Che ne dici di Wait, what language extension is this?qualcosa di completamente diverso?
MD XF,

1
Sono abbastanza curioso di sapere se è possibile decifrare RelaxedPolyRec, per un compilatore abbastanza antico da supportare effettivamente lo spegnimento. (L'opzione è rimasta in giro, con la documentazione, per alcuni anni dopo aver smesso di fare qualsiasi cosa.)
dfeuer

1
@dfeuer Guardando questo biglietto sembra che GHC 6.12.1 abbia supportato lo spegnimento.
Ørjan Johansen

Risposte:


24

MagicHash, 30 byte

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

-XMagicHash output 1, -XNoMagicHash output 2

MagicHash consente di terminare i nomi delle variabili in a #. Pertanto, con l'estensione, ciò definisce due funzioni y#e x#ciascuna delle quali assume un valore e restituisce una costante 2, oppure 1. x#xrestituirà 1 (perché è x#applicato a 1)

Senza l'estensione, definisce una funzione #che accetta due argomenti e restituisce 2. Il x#a=1è un modello che non viene mai raggiunto. Quindi x#xè 1#1, che restituisce 2.


2
Ora sto cantando X Magic Hash sulla melodia di Dance Magic Dance . Spero tu sia orgoglioso!
TRiG

Sono stupito che MagicHashnon consenta hash non finali. Strano!
martedì

18

CPP, 33 20 byte

main=print$0-- \
 +1

Stampa 0con -XCPPe 1con-XNoCPP .

Con -XCPP, una barra \prima di una nuova riga rimuove la nuova riga, quindi il codice diventa main=print$0-- +1e 0viene stampato solo come+1 ora fa parte del commento.

Senza il flag il commento viene ignorato e la seconda riga viene analizzata come parte della riga precedente perché è rientrata.


Approccio precedente con #define

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

Stampa anche 0con -XCPPe 1con -XNoCPP.


2
Oddio, fino ad ora ho pensato che GHC avrebbe spogliato i commenti di Haskell prima di passare al CPP.
Cubico

@Cubic Non è un pre-processore ?
Bergi,

1
@Bergi Certo, ma i pre-processori non significano necessariamente "è la prima cosa che viene eseguita", soprattutto perché GHC deve prima passare un file sul file per trovare anche il pragma. Immagino che i commenti siano mantenuti in commenti doc e simili dopo il CPP.
Cubico,


14

BinaryLiterals, 57 byte

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

-XBinaryLiterals stampa una nuova riga. -XNoBinaryLiterals stampa a 1.

Sono sicuro che esiste un modo migliore per farlo. Se ne trovi uno, ti preghiamo di pubblicarlo.


Non puoi semplicemente definire buna funzione (quindi non diventa binario b(0, 1), ma diventa binario 0b1)?
NoOneIsHere

12

MonomorphismRestriction + 7 altri, 107 byte

Questo utilizza TH che richiede sempre la bandiera -XTemplateHaskell.

File T.hs, 81 + 4 byte

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

Principale, 22 byte

import T
main=print $t

Compilando con il flag MonomorphismRestriction forza il tipo di pto Integer -> Integer -> Integere quindi produce il seguente output:

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

Compilare con il flag NoMonomorphismRestriction lascia il tipo di ppiù generale, vale a dire. Num a => a->a->a- produrre qualcosa come (abbreviato i VarTnomi in 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"

Provali online!


alternative

Dato che il codice sopra riportato stampa semplicemente il tipo di p, questo può essere fatto con tutte le bandiere che in qualche modo influenzano il modo in cui Haskell deduce i tipi. Specifico solo il flag e con cosa sostituire la funzione pe, se necessario, flag aggiuntivi (oltre -XTemplateHaskell):

Liste sovraccariche, 106 byte

Inoltre ha bisogno di -XNoMonomorphismRestriction:

p=[]

O p :: [a]oppure p :: IsList l => l, provali online!

OverloadedStrings, 106 byte

Inoltre ha bisogno di -XNoMonomorphismRestriction:

p=""

O p :: Stringoppure p :: IsString s => s, provali online!

PolyKinds, 112 byte

Ciò è interamente dovuto a @CsongorKiss:

data P a=P 

O P :: P aoppure P :: forall k (a :: k). P a, provali online!

Comprensioni Monad, 114 byte

p x=[i|i<-x]

O p :: [a] -> [a]oppure p :: Monad m => m a -> m a, provali online!

NamedWildCards, 114 byte

Questo è stato trovato da @Laikoni, inoltre richiede -XPartialTypeSignatures:

p=id::_a->_a

Entrambi hanno il tipo di salvataggio ( p :: a -> a) ma GHC genera nomi diversi per le variabili, provali online!

ApplicativoDo, 120 byte

p x=do i<-x;pure i

O p :: Monad m => m a -> m aoppure p :: Functor f => f a -> f a, provali online!

Sovraccarico di etichette, 120 byte

Ciò richiede il flag aggiuntivo -XFlexibleContexts:

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

Digita come p :: a -> b -> bo p :: IsLabel "id" (a->b) => a -> b, provali online!


Una cosa simile funziona per altre bandiere?
H.Piz,

Sì, potresti farlo con OverloadedStringso OverloadedListsdi sicuro e probabilmente anche altri ..
ბიმო

2
Funziona anche con PolyKinds: provalo online!
Csongor Kiss,

1
Sembra funzionare anche con NamedWildCards: provalo online! (Richiede -XPartialTypeSignatures)
Laikoni

10

CPP, 27 25

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

Provalo online!

Stampa ()per -XCPPe 1per-XNoCPP

Versione precedente:

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

Provalo online!

Stampa [1]con -XCPPe in [1,2]altro modo.

Riconoscimenti: questo si ispira alla risposta di Laikoni, ma invece di uno #defineusa semplicemente i commenti C.


9

ScopedTypeVariables, 162 113 byte

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

-XScopedTypeVariables stampe ""(vuoto), -XNoScopedTypeVariables stampe "[()]".

Modifica: soluzione aggiornata grazie a suggerimenti utili nei commenti


1
Ah capisco È generalmente più bello includere il tuo codice nel corpo, ma anche le versioni ungolf sono belle. Sto anche notando che "T"può essere semplicemente sostituito "".
Wheat Wizard

2
Un'altra cosa che puoi fare è sostituire il tuo tipo Tdi dati con (). Per evitare di doverlo definire. Provalo online!
Wheat Wizard

1
Bella cattura, mi sono appena reso conto che il pragma incoerente può essere incluso come una bandiera: provalo online!
Csongor Kiss,

2
Inoltre show può essere modificato per la stampa
H.Pwiz

La sintassi Unicode per forallti farà risparmiare qualche byte. Dubito che qualsiasi soluzione che necessiti di ulteriori istanze abbia comunque molte speranze di vincere.
dfeuer

9

MonoLocalBinds, GADTs o TypeFamilies, 36 32 byte

MODIFICARE:

  • -4 byte: una versione di questo è stata incorporata nella grande catena poliglotta dallo stasoid, che mi ha sorpreso mettendo tutte le dichiarazioni al massimo livello. Apparentemente l'attivazione di questa restrizione non richiede vincoli locali effettivi .
a=0
f b=b^a
main=print(f pi,f 0)
  • Con estensioni , questo programma stampa (1.0,1).
  • Con una delle bandiere -XMonoLocalBinds , -XGADTs o -XTypeFamilies , stampa (1.0,1.0).

  • L' MonoLocalBindsestensione esiste per impedire un'inferenza di tipo non intuitiva innescata da GADT e famiglie di tipi. Pertanto, questa estensione viene attivata automaticamente dalle altre due.

  • Lo è possibile spegnerlo nuovamente esplicitamente -XNoMonoLocalBinds, questo trucco presuppone che non lo fanno.
  • Come il suo cugino più noto, la restrizione del monomorfismo, MonoLocalBindsfunziona impedendo che alcuni valori ( in legami locali come leto where, quindi il nome apparentemente può capitare anche ai massimi livelli) siano polimorfici. Nonostante sia stato creato per un'inferenza di tipo più sano, le regole per quando si innesca sono possibilmente anche più pelose dell'MR.

  • Senza alcuna estensione, il programma sopra menziona il tipo f :: Num a => a -> a, consentendo f pidi default a Doubleef 0 a Integer.

  • Con le estensioni, il tipo inferito diventa f :: Double -> Doubleef 0 deve restituire anche un Double.
  • La variabile separata a=0è necessaria per innescare le regole tecniche: aè colpita dalla restrizione del monomorfismo ed aè una variabile libera di f, il che significa che fil gruppo di legame non è completamente generalizzato , il che significa che fnon è chiuso e quindi non diventa polimorfico.

9

Stringhe sovraccaricate, 65 48 32 byte

Sfruttando RebindableSyntax, usa la nostra versione di fromString per trasformare qualsiasi stringa letterale in "y".

main=print""
fromString _=['y']

Deve essere compilato con -XRebindableSyntax -XImplicitPrelude.

Senza -XOverloadedStringsstampe ""; con stampe "y".

Inoltre, solo ora mi ha colpito il fatto che la stessa tecnica funziona con (ad esempio) Liste sovraccaricate:

Liste sovraccaricate, 27 byte

main=print[0]
fromListN=(:)

Deve essere compilato con -XRebindableSyntax -XImplicitPrelude.

Senza -XOverloadedListsstampe [0]; con stampe [1,0].


1
È possibile abbreviare l'ultima riga a fromString a=['y'].
Ørjan Johansen,

Lo spazio in print "n"può anche essere lasciato cadere.
Laikoni,

@ ØrjanJohansen grazie! Stavo fallendo ="y", ma =['y']funziona benissimo!
Felixphew,

1
Puoi rimuovere il secondo ndaprint"n"
Wheat Wizard il

1
È inoltre possibile utilizzare -XImplicitPreludedopo RebindableSyntaxper evitare la riga di importazione.
dfeuer

8

BangPatterns, 32 byte

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

-XBangPatterns stampa 1mentre -XNoBangPatterns stampa0 .

Questo fa uso del fatto che il flag BangPatterns consente di annotare i pattern con una !forzatura di valutazione a WHNF, in tal caso 9!1utilizzerà la definizione di livello superiore (!)=seq. Se il flag non è abilitato, f!_definisce un nuovo operatore (!)e ombreggia la definizione di livello superiore.


7

ApplicativoDo, 104 byte

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

Provalo online!

Con ApplicativeDo, questo stampa

ZipList {getZipList = [1]}

Senza di essa, stampa

ZipList {getZipList = []}

ZipListè uno dei pochi tipi nelle librerie di base con un'istanza per Applicativema non per Monad. Potrebbero esserci alternative più brevi in ​​agguato da qualche parte.


7

Rigido, 87 84 82 byte

-5 byte grazie a dfeuer !

Potrebbe essere meno con il BlockArgumentssalvataggio dei genitori in giro \_->print 1:

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

Eseguire questo con -XStrict stampa a 1mentre eseguendolo con -XNoStrict verrà stampato a 0. Questo utilizza che Haskell per impostazione predefinita è pigro e non deve essere valutato error""poiché sa già che il risultato sarà0 quando corrisponderà al primo argomento di(!) , questo comportamento può essere cambiato con quel flag - costringendo il runtime a valutare entrambi gli argomenti.

Se non è consentito stampare nulla in un caso, è possibile ridurlo a 75 byte sostituendo il principale con (anche alcuni byte di dfeuer ):

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

StrictData, 106 99 93 byte

-15 byte grazie a dfeuer !

Questo sostanzialmente fa lo stesso ma funziona invece con i campi dati:

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

Stampa 1con il flag -XStrictData e 0con -XNoStrictData .

Se non è consentito stampare nulla in un caso, è possibile ridurlo a 86 byte sostituendo il principale con (19 byte di dfeuer ):

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

Nota: tutte le soluzioni richiedono TypeApplicationsset.


Puoi ridurlo abbastanza facilmente a 98 byte, il che corrisponde esattamente alla mia (molto diversa) soluzione. TIO .
Dfeuer

In realtà, puoi fare ancora meglio: invece di stampare nel gestore delle eccezioni, basta usare pure().
Dfeuer

1
@dfeuer: bello, il D{}trucco è piuttosto bello! PartialTypeSignaturesScopedTypeVariables
Ne hai

1
@dfeuer: ho dato un'occhiata e provato alcune cose, ma non ho mai usato Generics, quindi probabilmente non sono la persona giusta.
ბიმო

1
Puoi fare ancora meglio con il margine emorragico GHC e -XBlockArguments:main=catch @ErrorCall(p$seq(D$error"")1)\_->p 3
dfeuer

6

ApplicativoDo, 146 byte

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}

Stampa 1 quando ApplicativeDo è abilitato, 0 altrimenti

Provalo online!


1
Grazie! Ah, penso di essere su una versione precedente di GHC (il "no applicativo" era un avvertimento sul mio sistema)
oisdk

3
Utilizzando -XDeriveAnyClass è possibile derivare Applicativee Showsalvare utilizzando la sintassi dei record, vedere questo .
ბიმო

6

BinaryLiterals, 31 24 byte

Modificare:

  • -7 byte: H.PWiz ha suggerito di modificarlo ulteriormente utilizzando una singola b12variabile.

Una regolazione del metodo di H.PWiz , evitando l'istanza della funzione.

b12=1
main=print$(+)0b12

6

ExtendedDefaultRules, 54 53 bytes

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

Prints () with -XExtendedDefaultRules and 0 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!


While looking at this code borrowed into the polyglot (where the parentheses give some trouble), I remembered that GHC supports the one byte shorter syntax toEnum 0::Num a=>Enum a=>a.
Ørjan Johansen

You can get it down to 48 bytes with PartialTypeSignatures: main=print(toEnum 0::_=>Num a=>a). Also, your TIO link is out of date.
dfeuer

6

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.

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

(Links are slightly outdated; will fix.)

-XNoStrictData

-XStrictData

Requires MagicHash (to let us import GHC.Exts instead of Unsafe.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 of 3::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.

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

Equivalently,

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

Why does it ever print 3? This seems surprising! Well, small Integer values are represented very much like Ints, which (with strict data) are represented just like Ds. 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.


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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.