46
\$\begingroup\$

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!

\$\endgroup\$
27
  • \$\begingroup\$ Can programs take input? \$\endgroup\$
    – H.PWiz
    Commented Jan 21, 2018 at 19:19
  • 3
    \$\begingroup\$ I think this is a list of all valid options \$\endgroup\$
    – H.PWiz
    Commented Jan 21, 2018 at 20:32
  • 1
    \$\begingroup\$ Note that my above comment does not include NondecreasingIndentation for obvious reasons \$\endgroup\$
    – H.PWiz
    Commented Jan 21, 2018 at 21:12
  • 1
    \$\begingroup\$ 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.) \$\endgroup\$
    – dfeuer
    Commented Mar 7, 2019 at 8:51
  • 1
    \$\begingroup\$ @dfeuer Looking at this ticket it seems like GHC 6.12.1 supported turning it off. \$\endgroup\$ Commented Mar 8, 2019 at 6:35

34 Answers 34

27
\$\begingroup\$

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
\$\endgroup\$
2
  • 2
    \$\begingroup\$ I'm now singing X Magic Hash to the tune of Dance Magic Dance. I hope you're proud! \$\endgroup\$
    – TRiG
    Commented Jan 21, 2018 at 23:36
  • \$\begingroup\$ I'm astonished that MagicHash doesn't allow non-trailing hashes. Weird! \$\endgroup\$
    – dfeuer
    Commented Mar 6, 2019 at 19:28
20
\$\begingroup\$

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.

\$\endgroup\$
3
  • 5
    \$\begingroup\$ Oh god, until now I kind of thought GHC would strip Haskell comments before passing over to the CPP. \$\endgroup\$
    – Cubic
    Commented Jan 22, 2018 at 13:17
  • \$\begingroup\$ @Cubic Is it not a pre-processor? \$\endgroup\$
    – Bergi
    Commented Jan 24, 2018 at 11:18
  • 1
    \$\begingroup\$ @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. \$\endgroup\$
    – Cubic
    Commented Jan 24, 2018 at 11:46
15
\$\begingroup\$

NumDecimals, 14 bytes

main=print 1e1

-XNumDecimals prints 10. -XNoNumDecimals prints 10.0.

\$\endgroup\$
14
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ Can't you just define b as a function (so no binary becomes b(0, 1), but binary becomes 0b1)? \$\endgroup\$ Commented Jan 23, 2018 at 22:08
13
\$\begingroup\$

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!

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

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

\$\endgroup\$
5
  • 1
    \$\begingroup\$ 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 "". \$\endgroup\$
    – Wheat Wizard
    Commented Jan 22, 2018 at 1:17
  • 2
    \$\begingroup\$ Another thing you can do is replace your datatype T with (). To avoid having to define it. Try it online! \$\endgroup\$
    – Wheat Wizard
    Commented Jan 22, 2018 at 1:19
  • 1
    \$\begingroup\$ Nice catch, I just realised that the incoherent pragma can be included as a flag: Try it online! \$\endgroup\$ Commented Jan 22, 2018 at 1:22
  • 2
    \$\begingroup\$ Additionally show can be changed for print \$\endgroup\$
    – H.PWiz
    Commented Jan 22, 2018 at 1:26
  • \$\begingroup\$ Unicode syntax for forall will save you a few bytes. I doubt any solution that needs extra instances has much hope of winning, though. \$\endgroup\$
    – dfeuer
    Commented Mar 7, 2019 at 10:59
11
\$\begingroup\$

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.

\$\endgroup\$
0
9
\$\begingroup\$

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.

\$\endgroup\$
9
\$\begingroup\$

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.
\$\endgroup\$
9
\$\begingroup\$

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.
\$\endgroup\$
9
\$\begingroup\$

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

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

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!

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

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.

\$\endgroup\$
0
8
\$\begingroup\$

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
\$\endgroup\$
0
7
\$\begingroup\$

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!

\$\endgroup\$
2
  • \$\begingroup\$ 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. \$\endgroup\$ Commented Jun 22, 2018 at 18:06
  • \$\begingroup\$ 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. \$\endgroup\$
    – dfeuer
    Commented Mar 7, 2019 at 1:25
7
\$\begingroup\$

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.

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

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.

\$\endgroup\$
0
6
\$\begingroup\$

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.

\$\endgroup\$
5
\$\begingroup\$

UnboxedTuples, 52 bytes

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

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

\$\endgroup\$
3
  • \$\begingroup\$ Shouldn't there be another +16 in the score for the required option -XTemplateHaskell? \$\endgroup\$
    – celtschk
    Commented Jan 22, 2018 at 17:49
  • 2
    \$\begingroup\$ @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. \$\endgroup\$
    – Laikoni
    Commented Jan 22, 2018 at 19:02
  • \$\begingroup\$ 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. \$\endgroup\$
    – celtschk
    Commented Jan 22, 2018 at 19:13
5
\$\begingroup\$

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

\$\endgroup\$
1
  • \$\begingroup\$ You can get away with overlapping instances. \$\endgroup\$
    – dfeuer
    Commented Mar 7, 2019 at 2:33
5
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ main|(.)<-seq=print$0x0.0 avoids the import hiding. \$\endgroup\$ Commented Jul 6, 2018 at 6:14
  • \$\begingroup\$ main|let _._=0=print$0x0.0 might be easier for the polyglot though. \$\endgroup\$ Commented Jul 6, 2018 at 6:45
5
\$\begingroup\$

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.

\$\endgroup\$
8
  • \$\begingroup\$ 45 bytes \$\endgroup\$ Commented Mar 7, 2019 at 5:00
  • \$\begingroup\$ @ØrjanJohansen, nice. \$\endgroup\$
    – dfeuer
    Commented Mar 7, 2019 at 5:01
  • \$\begingroup\$ @ØrjanJohansen, should I make the edit, or would you prefer to add your own? \$\endgroup\$
    – dfeuer
    Commented Mar 7, 2019 at 5:03
  • \$\begingroup\$ Edit, it was a gradual evolution from yours. \$\endgroup\$ Commented Mar 7, 2019 at 5:08
  • \$\begingroup\$ @ØrjanJohansen, thanks, that was beautiful. \$\endgroup\$
    – dfeuer
    Commented Mar 7, 2019 at 5:13
5
\$\begingroup\$

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->_)
\$\endgroup\$
5
  • \$\begingroup\$ At least in runhaskell, this actually prints M 1 with -XDeriveAnyClass, due to laziness... \$\endgroup\$ Commented Jan 23, 2018 at 0:28
  • \$\begingroup\$ @ceasedtoturncounterclockwis: Yes in GHCi as well, but when compiling on TIO (and my machine) & then running it results in 1 :) \$\endgroup\$ Commented Jan 23, 2018 at 0:32
  • \$\begingroup\$ 113 bytes \$\endgroup\$
    – dfeuer
    Commented Mar 8, 2019 at 6:41
  • \$\begingroup\$ 109 bytes \$\endgroup\$
    – dfeuer
    Commented Mar 8, 2019 at 6:44
  • 1
    \$\begingroup\$ I got it down to 104 in a completely different way, so I added my own answer. \$\endgroup\$
    – dfeuer
    Commented Mar 8, 2019 at 7:15
4
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ id can be used instead of !. \$\endgroup\$ Commented Mar 7, 2019 at 5:35
  • \$\begingroup\$ @ØrjanJohansen, yes indeed! That saves a cool four bytes. \$\endgroup\$
    – dfeuer
    Commented Mar 7, 2019 at 5:44
4
\$\begingroup\$

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.

\$\endgroup\$
4
\$\begingroup\$

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.

\$\endgroup\$
4
\$\begingroup\$

UnicodeSyntax, 33 bytes

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

Try it online!

\$\endgroup\$
4
\$\begingroup\$

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!

\$\endgroup\$
1
  • \$\begingroup\$ $(...) (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... \$\endgroup\$ Commented Jul 25, 2019 at 11:02
3
\$\begingroup\$

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

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!

\$\endgroup\$
3
  • \$\begingroup\$ 97 bytes (although the IO()/print trick won't work in the polyglot). \$\endgroup\$ Commented Jul 25, 2019 at 11:31
  • \$\begingroup\$ @Ø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. \$\endgroup\$
    – stasoid
    Commented Jul 26, 2019 at 9:44
  • \$\begingroup\$ 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. \$\endgroup\$ Commented Jul 26, 2019 at 12:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.