Wait, what language is this?

Recently I had the pleasure of writing a Haskell program that could detect if the NegativeLiterals extension was engaged. I came up with the following:

data B=B{u::Integer}
instance Num B where{fromInteger=B;negate _=B 1}
main=print$1==u(-1)  Try it online! This will print True normally and False otherwise. Now I had so much fun doing this I'm extending the challenge to all of you. What other Haskell language extensions can you crack? Rules To crack a particular language extension you must write a Haskell program that compiles both with and without the language extension (warnings are fine) and outputs two different non-error values when run with the language extension and it turned off (by adding the No prefix to the language extension). In this way the code above could be shortened to just: data B=B{u::Integer} instance Num B where{fromInteger=B;negate _=B 1} main=print$u(-1)


which prints 1 and -1.

Any method you use to crack a extension must be specific to that extension. There may be ways of arbitrarily detecting what compiler flags or LanguageExtensions are enabled, if so such methods are not allowed. You may enable additional language extensions or change the compiler optimization using -O at no cost to your byte count.

Language extensions

You cannot crack any language extension that does not have a No counterpart (e.g. Haskell98, Haskell2010, Unsafe, Trustworthy, Safe) because these do not fall under the terms outlined above. Every other language extension is fair game.

Scoring

You will be awarded one point for every language extensions you are the first person to crack and one additional point for every language extension for which you have the shortest (measured in bytes) crack. For the second point ties will be broken in favor of earlier submissions. Higher score is better

You will not be able to score a point for first submission on NegativeLiterals or QuasiQuotes because I have already cracked them and included them in the body of the post. You will however be able to score a point for the shortest crack of each of these. Here is my crack of QuasiQuotes

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


Try it online!

• Can programs take input? Jan 21, 2018 at 19:19
• I think this is a list of all valid options Jan 21, 2018 at 20:32
• Note that my above comment does not include NondecreasingIndentation for obvious reasons Jan 21, 2018 at 21:12
• I'm quite curious whether it's possible to crack RelaxedPolyRec, for a compiler ancient enough to actually support turning it off. (The option hung around, with documentation, for some years after it stopped doing anything.) Mar 7, 2019 at 8:51
• @dfeuer Looking at this ticket it seems like GHC 6.12.1 supported turning it off. Mar 8, 2019 at 6:35

MagicHash, 30 bytes

x=1
y#a=2
x#a=1
main=print$x#x  -XMagicHash outputs 1, -XNoMagicHash outputs 2 MagicHash allows variable names to terminate in a #. Therefore with the extension, this defines two functions y# and x# which each take a value and return a constant 2, or 1. x#x will return 1 (because it is x# applied to 1) Without the extension, this defines one function # which takes two arguments and returns 2. The x#a=1 is a pattern that never gets reached. Then x#x is 1#1, which returns 2. 29 bytes a=1 a#b=a main|a<-0=print$a#0

• I'm now singing X Magic Hash to the tune of Dance Magic Dance. I hope you're proud!
– TRiG
Jan 21, 2018 at 23:36
• I'm astonished that MagicHash doesn't allow non-trailing hashes. Weird! Mar 6, 2019 at 19:28

CPP, 33 20 bytes

main=print$0-- \ +1  Prints 0 with -XCPP and 1 with -XNoCPP. With -XCPP, a slash \ before a newline removes the newline, thus the code becomes main=print$0-- +1 and only 0 is printed as the +1 is now part of the comment.

Without the flag the comment is ignored and the second line is parsed as a part of the previous line because it is indented.

Previous approach with #define

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


Also prints 0 with -XCPP and 1 with -XNoCPP.

• Oh god, until now I kind of thought GHC would strip Haskell comments before passing over to the CPP. Jan 22, 2018 at 13:17
• @Cubic Is it not a pre-processor? Jan 24, 2018 at 11:18
• @Bergi Sure, but pre-processors doesn't necessarily mean "is the first thing that runs", especially since GHC has to make a pass over the file first to even find the pragma. I guess comments are kept in so doc comments and the like work after CPP is done. Jan 24, 2018 at 11:46

NumDecimals, 14 bytes

main=print 1e1


-XNumDecimals prints 10. -XNoNumDecimals prints 10.0.

BinaryLiterals, 57 bytes

b1=1
instance Show(a->b)where;show _=""
main=print$(+)0b1  -XBinaryLiterals prints a single newline. -XNoBinaryLiterals prints a 1. I am sure there is a better way to do this. If you find one, please post it. • Can't you just define b as a function (so no binary becomes b(0, 1), but binary becomes 0b1)? Jan 23, 2018 at 22:08 MonomorphismRestriction + 7 others, 107 bytes This uses TH which requires the flag -XTemplateHaskell at all times. File T.hs, 81 + 4 bytes module T where import Language.Haskell.TH p=(+) t=reify(mkName"p")>>=stringE.show  Main, 22 bytes import T main=print$t


Compiling with the flag MonomorphismRestriction forces the type of p to Integer -> Integer -> Integer and thus produces the following 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"


Compiling with the flag NoMonomorphismRestriction leaves the type of p at the most general, ie. Num a => a->a->a - producing something like (shortened the VarT names to 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"


Try them online!

Alternatives

Since the above code simply prints out the type of p, this can be done with all flags that somehow influence how Haskell infers types. I will only specify the flag and with what to replace the function p and if needed additional flags (besides -XTemplateHaskell):

Additionally needs -XNoMonomorphismRestriction:

p=[]


Either p :: [a] or p :: IsList l => l, try them online!

Additionally needs -XNoMonomorphismRestriction:

p=""


Either p :: String or p :: IsString s => s, try them online!

PolyKinds, 112 bytes

This is entirely due to @CsongorKiss:

data P a=P


Either P :: P a or P :: forall k (a :: k). P a, try them online!

p x=[i|i<-x]


Either p :: [a] -> [a] or p :: Monad m => m a -> m a, try them online!

NamedWildCards, 114 bytes

This one was found by @Laikoni, it additionally requires -XPartialTypeSignatures:

p=id::_a->_a


They both have the save type (p :: a -> a) but GHC generates different names for the variables, try them online!

ApplicativeDo, 120 bytes

p x=do i<-x;pure i


Either p :: Monad m => m a -> m a or p :: Functor f => f a -> f a, try them online!

This needs the additional flag -XFlexibleContexts:

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


Either types as p :: a -> b -> b or p :: IsLabel "id" (a->b) => a -> b, try them online!

• Does a similar thing work for other flags? Jan 21, 2018 at 22:29
• Yeah, you could do it with OverloadedStrings or OverloadedLists for sure and probably others as well.. Jan 21, 2018 at 22:31
• It also works with PolyKinds: Try it online! Jan 22, 2018 at 8:36
• Also seems to work with NamedWildCards: Try it online! (Requires -XPartialTypeSignatures) Jan 23, 2018 at 1:28

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 prints "" (empty), -XNoScopedTypeVariables prints "[()]".

Edit: updated solution thanks to useful suggestions in the comments

• Ah I see. Its generally nicer to include your code in the body, but ungolfed versions are nice as well. I'm also noticing that "T" can just be replaced with "". Jan 22, 2018 at 1:17
• Another thing you can do is replace your datatype T with (). To avoid having to define it. Try it online! Jan 22, 2018 at 1:19
• Nice catch, I just realised that the incoherent pragma can be included as a flag: Try it online! Jan 22, 2018 at 1:22
• Additionally show can be changed for print Jan 22, 2018 at 1:26
• Unicode syntax for forall will save you a few bytes. I doubt any solution that needs extra instances has much hope of winning, though. Mar 7, 2019 at 10:59

CPP, 27 25

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


Try it online!

Prints () for -XCPP and 1 for -XNoCPP

Previous version:

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


Try it online!

Prints [1] with -XCPP and [1,2] otherwise.

Credits: This is inspired by Laikoni's answer, but instead of a #define it simply uses C comments.

BangPatterns, 32 bytes

(!)=seq
main|let f!_=0=print$9!1  -XBangPatterns prints 1 whereas -XNoBangPatterns will print 0. This makes use that the flag BangPatterns allows to annotate patterns with a ! to force evaluation to WHNF, in that case 9!1 will use the top-level definition (!)=seq. If the flag is not enabled f!_ defines a new operator (!) and shadows the top-level definition. MonoLocalBinds, GADTs, or TypeFamilies, 36 32 bytes EDIT: • -4 bytes: A version of this was incorporated into the great polyglot chain by stasoid, who surprised me by putting all the declarations at top level. Apparently triggering this restriction does not require actual local bindings. a=0 f b=b^a main=print(f pi,f 0)  • With no extensions, this program prints (1.0,1). • With either of the flags -XMonoLocalBinds, -XGADTs, or -XTypeFamilies, it prints (1.0,1.0). • The MonoLocalBinds extension exists to prevent some unintuitive type inference triggered by GADTs and type families. As such, this extension is automatically turned on by the two others. • It is possible to turn it off again explicitly with -XNoMonoLocalBinds, this trick assumes you don't. • Like its more well-known cousin the monomorphism restriction, MonoLocalBinds works by preventing some values (in local bindings like let or where, thus the name apparently it can also happen at top level) from being polymorphic. Despite being created for saner type inference, the rules for when it triggers are if possible even more hairy than the MR. • Without any extension, the above program infers the type f :: Num a => a -> a, allowing f pi to default to a Double and f 0 to an Integer. • With the extensions, the type inferred becomes f :: Double -> Double, and f 0 has to return a Double as well. • The separate variable a=0 is needed to trigger the technical rules: a is hit by the monomorphism restriction, and a is a free variable of f, which means that f's binding group is not fully generalized, which means f is not closed and thus doesn't become polymorphic. 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.

Taking advantage of RebindableSyntax, use our own version of fromString to turn any string literal into "y".

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


Must be compiled with -XRebindableSyntax -XImplicitPrelude.

Without -XOverloadedStrings prints ""; with prints "y".

Also, it only just now struck me that the same technique works with (e.g.) OverloadedLists:

main=print[0]
fromListN=(:)


Must be compiled with -XRebindableSyntax -XImplicitPrelude.

Without -XOverloadedLists prints [0]; with prints [1,0].

• You can shorten the last line to fromString a=['y']. Jan 23, 2018 at 8:21
• The space in print "n" can also be dropped. Jan 23, 2018 at 9:12
• @ØrjanJohansen thanks! I was having it fail with ="y", but =['y'] works fine! Jan 23, 2018 at 21:09
• You can remove the second n from print"n" Jun 23, 2018 at 13:09
• You can also use -XImplicitPrelude after RebindableSyntax to avoid the import line. Mar 6, 2019 at 22:18

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}


Prints 1 when ApplicativeDo is enabled, 0 otherwise

Try it online!

• Thanks! Ah, I think I'm on an older version of GHC (the "no applicative" was a warning on my system) Jan 22, 2018 at 14:58
• Using -XDeriveAnyClass you can derive Applicative and Show to save using record syntax, see this. Jan 22, 2018 at 15:11

ApplicativeDo, 104 bytes

import Control.Applicative
z=ZipList
main=print$do a<-z[1];pure a  Try it online! With ApplicativeDo, this prints ZipList {getZipList = [1]}  Without it, it prints ZipList {getZipList = []}  ZipList is one of the few types in the base libraries with an instance for Applicative but not for Monad. There may be shorter alternatives lurking somewhere. BinaryLiterals, 31 24 bytes Edit: • -7 bytes: H.PWiz suggested adjusting it further by using a single b12 variable. An adjustment to H.PWiz's method, avoiding the function instance. b12=1 main=print$(+)0b12

• With -XNoBinaryLiterals, 0b12 lexes as 0 b12, printing 0+1 = 1.
• With -XBinaryLiterals, 0b12 lexes as 0b1 2, printing 1+2 = 3.

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. Jun 22, 2018 at 18:06
• 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. Mar 7, 2019 at 1:25

Strict, 87 84 82 bytes

-5 bytes thanks to dfeuer!

Could be less with BlockArguments saving the parens around \_->print 1:

import Control.Exception
0!_=0
main=catch @ErrorCall(print$0!error"")(\_->print 1)  Running this with -XStrict prints a 1 whereas running it with -XNoStrict will print a 0. This uses that Haskell by default is lazy and doesn't need to evaluate error"" since it already knows that the result will be 0 when it matched on the first argument of (!), this behaviour can be changed with that flag - forcing the runtime to evaluate both arguments. If printing nothing in one case is allowed we can get it down to 75 bytes replacing the main by (also some bytes off by dfeuer): main=catch @ErrorCall(print$0!error"")mempty


StrictData, 106 99 93 bytes

-15 bytes thanks to dfeuer!

This basically does the same but works with data fields instead:

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


Prints 1 with the -XStrictData flag and 0 with -XNoStrictData.

If printing nothing in one case is allowed we can get it down to 86 bytes replacing the main by (19 bytes off by dfeuer):

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


Note: All solutions require TypeApplications set.

• You can cut this down pretty easily to 98 bytes, which happens to match my (very different) solution exactly. TIO. Mar 7, 2019 at 9:35
• Actually, you can do even better: instead of printing in the exception handler, just use pure(). Mar 7, 2019 at 9:53
• @dfeuer: Nice, the D{} trick is pretty cool! Shaved another one off by using PartialTypeSignatures instead of ScopedTypeVariables :) Mar 8, 2019 at 1:39
• @dfeuer: I had a look and tried a few things, but I never used Generics, so I'm probably not the right person. Mar 8, 2019 at 17:58
• You can do even better with bleeding edge GHC and -XBlockArguments: main=catch @ErrorCall(p$seq(D$error"")1)\_->p 3 Mar 8, 2019 at 19:12

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.

StrictData, 58 bytes

import GHC.Exts
data D=D Int
main=print$unsafeCoerce#D 3+0  -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.

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? Jan 22, 2018 at 17:49
• @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. Jan 22, 2018 at 19:02
• 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. Jan 22, 2018 at 19:13

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. Mar 7, 2019 at 2:33

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. Jul 6, 2018 at 6:14
• main|let _._=0=print$0x0.0 might be easier for the polyglot though. Jul 6, 2018 at 6:45 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. • 45 bytes Mar 7, 2019 at 5:00 • @ØrjanJohansen, nice. Mar 7, 2019 at 5:01 • @ØrjanJohansen, should I make the edit, or would you prefer to add your own? Mar 7, 2019 at 5:03 • Edit, it was a gradual evolution from yours. Mar 7, 2019 at 5:08 • @ØrjanJohansen, thanks, that was beautiful. Mar 7, 2019 at 5:13 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... Jan 23, 2018 at 0:28
• @ceasedtoturncounterclockwis: Yes in GHCi as well, but when compiling on TIO (and my machine) & then running it results in 1 :) Jan 23, 2018 at 0:32
• 113 bytes Mar 8, 2019 at 6:41
• 109 bytes Mar 8, 2019 at 6:44
• I got it down to 104 in a completely different way, so I added my own answer. Mar 8, 2019 at 7:15

PostfixOperators, 63 bytes

import Text.Show.Functions
instance Num(a->b)
main=print(0id)


Try it online (without extension)

Try it online (with extension)

This is a cut-down version of a Hugs/GHC polyglot I wrote. See that post for explanation. Thanks to @ØrjanJohansen for realizing I could use id instead of a custom operator, saving four bytes.

• id can be used instead of !. Mar 7, 2019 at 5:35
• @ØrjanJohansen, yes indeed! That saves a cool four bytes. Mar 7, 2019 at 5:44

DeriveAnyClass, 104 bytes

import Control.Exception
newtype M a=M a deriving(Show,Exception)

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.
• I think f=(2^);main=print$f$f(64::Int) would save a byte. But it won't realistically terminate Jun 24, 2018 at 18:43
• @H.PWiz Fortunately 64=2^6, which saves yet another byte. Jun 25, 2018 at 1:42

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). Jul 25, 2019 at 11:31 • @Ø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. Jul 26, 2019 at 9:44 • 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. Jul 26, 2019 at 12:16