Wait, what language is this?

38

13

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!

Post Rock Garf Hunter

Posted 2018-01-21T18:48:15.630

Reputation: 55 382

Can programs take input? – H.PWiz – 2018-01-21T19:19:03.520

Can we require more than one extension, but only toggle one – H.PWiz – 2018-01-21T19:25:45.573

@H.PWiz programs should not take input. You may require additional language extensions if you wish. – Post Rock Garf Hunter – 2018-01-21T19:43:43.023

3

I think this is a list of all valid options

– H.PWiz – 2018-01-21T20:32:06.123

1Note that my above comment does not include NondecreasingIndentation for obvious reasons – H.PWiz – 2018-01-21T21:12:31.567

If certain circumstances raise an exception and the program can recover from it (printing a message to stderr), is this acceptable behaviour? Asking because of this.

– ბიმო – 2018-01-22T07:58:43.140

@BMO You are free to print to STDERR during compilation for warnings but at run time STDERR should be empty. – Post Rock Garf Hunter – 2018-01-22T14:42:37.590

How should other flags be scored? See the comments here for context.

– Laikoni – 2018-01-22T19:04:15.857

I'd suggest that language extensions other than the one you're testing for should count for bytes. Mostly because I'm disappointed about all the TemplateHaskell use I see here. – Ørjan Johansen – 2018-01-23T02:15:08.633

@ØrjanJohansen In retrospect it might not have been a good idea to let all language extensions get by for free, but I don't intend to change the rules now. – Post Rock Garf Hunter – 2018-01-23T04:59:21.510

4I think this title is misleading, as the only language you can use is Haskell. How about Wait, what language extension is this? Or something completely different. – MD XF – 2018-01-25T03:44:57.693

@MDXF All the languages are different they are just all in the Haskell family. – Post Rock Garf Hunter – 2018-01-25T03:45:50.123

I think you should drop the requirement for a No counterpart. I'm not sure, but I think there might be at least one game to play with safe Haskell. – dfeuer – 2019-03-06T18:01:08.830

@dfeuer The problem with extensions that don't have No counter part is it is hard to tell what we should be comparing it to. No counterparts make it nice and clear. – Post Rock Garf Hunter – 2019-03-06T18:04:29.423

@SriotchilismO'Zaic, in those cases, compare to the effect of not giving the option. The same goes for No options without a positive counterpart, if there are any. – dfeuer – 2019-03-06T19:25:20.127

1I'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.) – dfeuer – 2019-03-07T08:51:40.277

@dfeuer I don't have an old compiler to check, but would x=0^y;y=seq(x/)0;y::Int work? (Needs NoMonomorphismRestriction.) – Ørjan Johansen – 2019-03-08T04:47:47.237

@ØrjanJohansen, my intuition for NoRelaxedPolyRec is rather poor. The description of the restriction in the Haskell 98 Report is just awful. – dfeuer – 2019-03-08T05:02:40.627

@ØrjanJohansen, I'm really not sure. GHC is the only compiler I've been able to find that (at one point) claimed to be able to turn the extension on and off. As far as I can tell, there's no way to turn it on in Gofer, and the only way I've found to (maybe!) turn it off in Hugs also disables all other extensions. I don't see any mention of it in the nhc98 docs. It's probably still possible to get some really old GHC versions.... – dfeuer – 2019-03-08T05:41:21.773

@dfeuer x()=0^y;y=seq(x()/)0;y::Int ought to work without NoMonomorphismRestriction. However, changing between Hugs and Haskell 98 mode (which I'm guessing you mean) doesn't change the result. :( – Ørjan Johansen – 2019-03-08T06:13:08.717

Yes, that's what I meant. That was the only option I saw that looked like it might disable the extension. I could've missed something though. – dfeuer – 2019-03-08T06:16:34.560

1

@dfeuer Looking at this ticket it seems like GHC 6.12.1 supported turning it off.

– Ørjan Johansen – 2019-03-08T06:35:50.040

Are we allowed to print more than one value? – dfeuer – 2019-03-08T21:31:32.700

@dfeuer What does it mean to print more than one value? – Post Rock Garf Hunter – 2019-03-08T21:32:36.413

For example, to print two numbers, one on each line. Also, we need an answer about whether the output is allowed to be empty, or just a newline, sometimes. Do the things printed have to represent Haskell values, or can they be arbitrary strings? – dfeuer – 2019-03-08T21:34:22.650

@dfeuer Yeah, I don't care whether things are haskell values or how many lines they are on etc. As long as the outputs are different and non-error. (output to STDERR or non-zero exit code) – Post Rock Garf Hunter – 2019-03-08T21:35:56.043

What are the rules about compiler flags (e.g., -O)? – dfeuer – 2019-03-08T22:00:32.940

@dfeuer I'd like to say that you can use whatever flags you want at no cost, but I am pretty sure there are ways that you can just write all your code as flags and thus "score" zero bytes. I went ahead and said you can use the various -Os at no additional cost, if there is any other flags you or any one else would like me to add I'd probably do so. – Post Rock Garf Hunter – 2019-03-08T22:04:16.017

Answers

24

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.

H.PWiz

Posted 2018-01-21T18:48:15.630

Reputation: 10 962

2I'm now singing X Magic Hash to the tune of Dance Magic Dance. I hope you're proud! – TRiG – 2018-01-21T23:36:36.503

I'm astonished that MagicHash doesn't allow non-trailing hashes. Weird! – dfeuer – 2019-03-06T19:28:20.573

19

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.

Laikoni

Posted 2018-01-21T18:48:15.630

Reputation: 23 676

3Oh god, until now I kind of thought GHC would strip Haskell comments before passing over to the CPP. – Cubic – 2018-01-22T13:17:25.780

@Cubic Is it not a pre-processor? – Bergi – 2018-01-24T11:18:10.987

1@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. – Cubic – 2018-01-24T11:46:29.650

14

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.

H.PWiz

Posted 2018-01-21T18:48:15.630

Reputation: 10 962

Can't you just define b as a function (so no binary becomes b(0, 1), but binary becomes 0b1)? – NoOneIsHere – 2018-01-23T22:08:43.297

14

NumDecimals, 14 bytes

main=print 1e1

-XNumDecimals prints 10. -XNoNumDecimals prints 10.0.

H.PWiz

Posted 2018-01-21T18:48:15.630

Reputation: 10 962

12

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):

OverloadedLists, 106 bytes

Additionally needs -XNoMonomorphismRestriction:

p=[]

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

OverloadedStrings, 106 bytes

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!

MonadComprehensions, 114 bytes

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!

OverloadedLabels, 120 bytes

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!

ბიმო

Posted 2018-01-21T18:48:15.630

Reputation: 15 345

Does a similar thing work for other flags? – H.PWiz – 2018-01-21T22:29:05.717

Yeah, you could do it with OverloadedStrings or OverloadedLists for sure and probably others as well.. – ბიმო – 2018-01-21T22:31:23.380

2

It also works with PolyKinds: Try it online!

– Csongor Kiss – 2018-01-22T08:36:30.690

1

Also seems to work with NamedWildCards: Try it online! (Requires -XPartialTypeSignatures)

– Laikoni – 2018-01-23T01:28:52.127

10

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.

celtschk

Posted 2018-01-21T18:48:15.630

Reputation: 4 650

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

Edit: updated solution thanks to useful suggestions in the comments

Csongor Kiss

Posted 2018-01-21T18:48:15.630

Reputation: 191

1Ah 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 "". – Post Rock Garf Hunter – 2018-01-22T01:17:25.577

2

Another thing you can do is replace your datatype T with (). To avoid having to define it. Try it online!

– Post Rock Garf Hunter – 2018-01-22T01:19:45.803

1

Nice catch, I just realised that the incoherent pragma can be included as a flag: Try it online!

– Csongor Kiss – 2018-01-22T01:22:49.877

2

Additionally show can be changed for print

– H.PWiz – 2018-01-22T01:26:30.250

Unicode syntax for forall will save you a few bytes. I doubt any solution that needs extra instances has much hope of winning, though. – dfeuer – 2019-03-07T10:59:18.903

9

OverloadedStrings, 65 48 32 bytes

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:

OverloadedLists, 27 bytes

main=print[0]
fromListN=(:)

Must be compiled with -XRebindableSyntax -XImplicitPrelude.

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

felixphew

Posted 2018-01-21T18:48:15.630

Reputation: 321

1You can shorten the last line to fromString a=['y']. – Ørjan Johansen – 2018-01-23T08:21:18.423

The space in print "n" can also be dropped. – Laikoni – 2018-01-23T09:12:58.510

@ØrjanJohansen thanks! I was having it fail with ="y", but =['y'] works fine! – felixphew – 2018-01-23T21:09:21.673

1You can remove the second n from print"n" – Post Rock Garf Hunter – 2018-06-23T13:09:07.957

1You can also use -XImplicitPrelude after RebindableSyntax to avoid the import line. – dfeuer – 2019-03-06T22:18:08.100

9

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.

Ørjan Johansen

Posted 2018-01-21T18:48:15.630

Reputation: 6 914

8

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.

ბიმო

Posted 2018-01-21T18:48:15.630

Reputation: 15 345

7

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.

ბიმო

Posted 2018-01-21T18:48:15.630

Reputation: 15 345

You can cut this down pretty easily to 98 bytes, which happens to match my (very different) solution exactly. TIO.

– dfeuer – 2019-03-07T09:35:41.767

Actually, you can do even better: instead of printing in the exception handler, just use pure(). – dfeuer – 2019-03-07T09:53:42.847

1@dfeuer: Nice, the D{} trick is pretty cool! Shaved another one off by using PartialTypeSignatures instead of ScopedTypeVariables :) – ბიმო – 2019-03-08T01:39:22.313

You used the Monoid instance for ErrorCall ->IO ()?! Devious! The record syntax trick is useful in real code when the number of fields in a sum type constructor can potentially change, but you only care which constructor it is. – dfeuer – 2019-03-08T05:48:28.390

I'm not optimistic that my own StrictData solution can be cut down any, but do you think you could give it a try? – dfeuer – 2019-03-08T05:53:34.120

You can drop one more byte by switching from catch to handle: 95 bytes

– dfeuer – 2019-03-08T06:03:06.070

BTW, your TIO for StrictData actually invokes Strict (unnecessarily). – dfeuer – 2019-03-08T06:05:21.973

I'm not sure printing nothing qualifies as printing a value. – Ørjan Johansen – 2019-03-08T07:59:30.383

@ØrjanJohansen, that's a good point, but it's not really clear to me what exactly "print a value" is supposed to mean in general. As I recall, putStrLn.show$ ("'::Text) doesn't print anything either. – dfeuer – 2019-03-08T15:05:02.317

1@dfeuer: I had a look and tried a few things, but I never used Generics, so I'm probably not the right person. – ბიმო – 2019-03-08T17:58:00.657

93 bytes – dfeuer – 2019-03-08T19:04:11.243

1You can do even better with bleeding edge GHC and -XBlockArguments: main=catch @ErrorCall(p$seq(D$error"")1)\_->p 3 – dfeuer – 2019-03-08T19:12:44.223

It looks like empty output is fine. – dfeuer – 2019-03-08T21:36:41.147

58 bytes for StrictData, taking advantage of some truly disgusting trickery. See my latest answer. – dfeuer – 2019-03-09T00:00:10.900

7

ApplicativeDo, 104 bytes

import Control.Applicative
z=ZipList
instance Monad ZipList where _>>=_=z[]
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.

Zgarb

Posted 2018-01-21T18:48:15.630

Reputation: 39 083

7

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.

Ørjan Johansen

Posted 2018-01-21T18:48:15.630

Reputation: 6 914

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}

Prints 1 when ApplicativeDo is enabled, 0 otherwise

Try it online!

oisdk

Posted 2018-01-21T18:48:15.630

Reputation: 161

1Thanks! Ah, I think I'm on an older version of GHC (the "no applicative" was a warning on my system) – oisdk – 2018-01-22T14:58:23.830

3

Using -XDeriveAnyClass you can derive Applicative and Show to save using record syntax, see this.

– ბიმო – 2018-01-22T15:11:00.073

6

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

Ørjan Johansen

Posted 2018-01-21T18:48:15.630

Reputation: 6 914

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!

Laikoni

Posted 2018-01-21T18:48:15.630

Reputation: 23 676

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 – 2018-06-22T18:06:05.367

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 – 2019-03-07T01:25:55.053

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

Posted 2018-01-21T18:48:15.630

Reputation: 1 016

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.

dfeuer

Posted 2018-01-21T18:48:15.630

Reputation: 1 016

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

ბიმო

Posted 2018-01-21T18:48:15.630

Reputation: 15 345

At least in runhaskell, this actually prints M 1 with -XDeriveAnyClass, due to laziness... – ceased to turn counterclockwis – 2018-01-23T00:28:14.807

@ceasedtoturncounterclockwis: Yes in GHCi as well, but when compiling on TIO (and my machine) & then running it results in 1 :) – ბიმო – 2018-01-23T00:32:08.407

113 bytes – dfeuer – 2019-03-08T06:41:03.313

109 bytes – dfeuer – 2019-03-08T06:44:32.730

1I got it down to 104 in a completely different way, so I added my own answer. – dfeuer – 2019-03-08T07:15:16.550

5

UnboxedTuples, 52 bytes

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

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

Laikoni

Posted 2018-01-21T18:48:15.630

Reputation: 23 676

Shouldn't there be another +16 in the score for the required option -XTemplateHaskell? – celtschk – 2018-01-22T17:49:46.577

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 – 2018-01-22T19:02:45.703

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 – 2018-01-22T19:13:35.407

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

Posted 2018-01-21T18:48:15.630

Reputation: 10 962

You can get away with overlapping instances. – dfeuer – 2019-03-07T02:33:46.910

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

Posted 2018-01-21T18:48:15.630

Reputation: 7 175

main|(.)<-seq=print$0x0.0 avoids the import hiding. – Ørjan Johansen – 2018-07-06T06:14:46.557

main|let _._=0=print$0x0.0 might be easier for the polyglot though. – Ørjan Johansen – 2018-07-06T06:45:08.523

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

Posted 2018-01-21T18:48:15.630

Reputation: 1 016

45 bytes – Ørjan Johansen – 2019-03-07T05:00:41.237

@ØrjanJohansen, nice. – dfeuer – 2019-03-07T05:01:43.563

@ØrjanJohansen, should I make the edit, or would you prefer to add your own? – dfeuer – 2019-03-07T05:03:05.493

Edit, it was a gradual evolution from yours. – Ørjan Johansen – 2019-03-07T05:08:09.320

@ØrjanJohansen, thanks, that was beautiful. – dfeuer – 2019-03-07T05:13:34.403

@ØrjanJohansen, five more down. I suspect this may be minimal. – dfeuer – 2019-03-07T05:56:11.680

Huh, I didn't know the :: forall a. ... for scoping could be on a local expression. – Ørjan Johansen – 2019-03-07T06:06:56.837

@ØrjanJohansen, I learned that trick from Ed Kmett. – dfeuer – 2019-03-07T06:12:03.343

4

PostfixOperators, 63 bytes

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

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.

dfeuer

Posted 2018-01-21T18:48:15.630

Reputation: 1 016

id can be used instead of !. – Ørjan Johansen – 2019-03-07T05:35:33.853

@ØrjanJohansen, yes indeed! That saves a cool four bytes. – dfeuer – 2019-03-07T05:44:55.487

4

StrictData, 97 bytes

import GHC.Generics
data A=A()deriving Generic
main=print$selDecidedStrictness$unM1.unM1$from$A()

Try it online (no strict data)

Try it online (strict data)

Also requires DeriveGeneric.

dfeuer

Posted 2018-01-21T18:48:15.630

Reputation: 1 016

4

DeriveAnyClass, 104 bytes

import Control.Exception
newtype M a=M a deriving(Show,Exception)
main=print.displayException$M Deadlock

Try it online (without extension)

Try it online (with extension)

Also requires GeneralizedNewtypeDeriving.

dfeuer

Posted 2018-01-21T18:48:15.630

Reputation: 1 016

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

Posted 2018-01-21T18:48:15.630

Reputation: 7 175

$(...) (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 – 2019-07-25T11:02:32.373

3

UnicodeSyntax, 33 bytes

(∀)=0
main|forall<-1=print(∀)

Try it online!

H.PWiz

Posted 2018-01-21T18:48:15.630

Reputation: 10 962

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

Posted 2018-01-21T18:48:15.630

Reputation: 6 914

1I think f=(2^);main=print$f$f(64::Int) would save a byte. But it won't realistically terminate – H.PWiz – 2018-06-24T18:43:08.830

@H.PWiz Fortunately 64=2^6, which saves yet another byte. – Ørjan Johansen – 2018-06-25T01:42:14.410

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

Posted 2018-01-21T18:48:15.630

Reputation: 7 175

97 bytes (although the IO()/print trick won't work in the polyglot). – Ørjan Johansen – 2019-07-25T11:31:42.607

@Ø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 – 2019-07-26T09:44:05.340

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 – 2019-07-26T12:16:54.097