Зачекайте, що це за мова?


37

Нещодавно я мав задоволення написати програму Haskell, яка могла б виявити, чи було NegativeLiteralsрозширення задіяним. Я придумав таке:

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

Спробуйте в Інтернеті!

Це надрукується Trueнормально та в Falseіншому випадку.

Тепер мені було так весело робити це, я поширюю виклик на всіх вас. Які ще розширення мови Haskell ви можете зламати?

Правила

Щоб зламати певне розширення мови, ви повинні написати програму Haskell, яка компілює як з мовним розширенням, так і без нього (попередження прекрасні) та виводить два різних значення помилок під час запуску з розширенням мови та його вимкнено (додавши Noпрефікс до розширення мови). Таким чином код вище можна було скоротити до просто:

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

який друкує 1і -1.

Будь-який метод, який ви використовуєте для розтріскування розширення, повинен бути специфічним для цього розширення. Можливо, існують способи довільного визначення того, які прапорці компілятора або LanguageExtensions увімкнено, якщо так такі методи заборонені. Ви можете ввімкнути додаткові розширення мови або змінити оптимізацію компілятора, використовуючи -Oбезкоштовно вартість вашого байта.

Розширення мови

Ви не можете зламати будь-яке розширення мови, не мають Noаналогів (наприклад Haskell98, Haskell2010, Unsafe, Trustworthy, Safe) , тому що вони не потрапляють в відповідно до умов , викладених вище. Кожне інше розширення мови - це чесна гра.

Оцінка балів

Вам буде присвоєно один бал за кожне розширення мови, який ви є першою людиною, що зламається, і один додатковий бал за кожне розширення мови, для якого у вас найкоротший (вимірюється в байтах) тріск. Для другого пункту зв'язки будуть розірвані на користь попередніх подань. Вищий бал - кращий

Ви не зможете набрати бал за перше подання NegativeLiteralsабо QuasiQuotesтому, що я вже зламав їх і включив їх до основної публікації. Однак ви зможете набрати очко за найкоротший злом кожного з них. Ось моя тріщинаQuasiQuotes

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

Спробуйте в Інтернеті!


3
Я думаю, що це перелік усіх дійсних варіантів
H.PWiz

1
Зауважте, що мій вище коментар не містить NondecreasingIndentationзрозумілих причин
H.PWiz

4
Я думаю, що ця назва вводить в оману, оскільки єдиною мовою, якою ви можете скористатися, є Haskell. Як щодо Wait, what language extension is this?Або щось зовсім інше.
MD XF

1
Мені дуже цікаво, чи можна зламати RelaxedPolyRec, оскільки компілятор досить старий, щоб насправді підтримувати його вимкнення. (Опція висіла з документацією протягом декількох років після того, як вона перестала робити щось.)
dfeuer

1
@dfeuer Дивлячись на цей квиток, схоже, що GHC 6.12.1 підтримує його вимкнення.
Ørjan Johansen

Відповіді:


24

MagicHash, 30 байт

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

-XMagicHash виводи 1, -XNoMagicHash виходи 2

MagicHash дозволяє закінчувати імена змінних у a #. Тому з розширенням, це визначає дві функції , y#і x#якій кожен приймати значення і повертає константу 2, або 1. x#xповерне 1 (тому що це x#застосовано до 1)

Без розширення це визначає одну функцію, #яка бере два аргументи і повертає 2. Це x#a=1закономірність, якої ніколи не можна досягти. Тоді x#xє 1#1, що повертає 2.


2
Зараз я співаю X Magic Hash під мелодію Dance Magic Dance . Я сподіваюся, ви пишаєтесь!
TRiG

Я здивований, що MagicHashне допускає хеш-трейлінгу. Дивно!
dfeuer

18

CPP, 33 20 байт

main=print$0-- \
 +1

Друкує 0з -XCPPі 1разом із -XNoCPP.

З -XCPP, коса коса риса \перед новим рядком видаляє новий рядок, таким чином код стає main=print$0-- +1і 0друкується лише як +1тепер частина коментаря.

Без прапора коментар ігнорується, а другий рядок аналізується як частина попереднього рядка, оскільки він є відступом.


Попередній підхід с #define

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

Також друкує 0з -XCPPі 1з-XNoCPP .


2
Боже, до цих пір я думав, що GHC зніме коментарі Haskell, перш ніж перейти до CPP.
Кубік

@Cubic Це не попередній процес ?
Бергі

1
@Bergi Звичайно, але попередні процесори не означають, що "це перше, що працює", тим більше, що GHC спочатку повинен пройти файл, щоб навіть знайти прагму. Я думаю, що коментарі містяться в коментарях док та подібних робіт після того, як CPP буде виконано.
Кубік


14

Бінарні літератури, 57 байт

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

-XBinaryLiterals друкує один новий рядок. -XNoBinaryLiterals друкує a 1.

Я впевнений, що для цього є кращий спосіб. Якщо ви знайдете його, будь ласка, опублікуйте його.


Ви не можете просто визначити bфункцію (так що не стає бінарним b(0, 1), а двійковим стає 0b1)?
NoOneIsHere

12

Мономорфізмобмеження + 7 інших, 107 байт

Для цього використовується TH, який вимагає прапор -XTemplateHaskellпостійно.

Файл T.hs, 81 + 4 байти

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

Основна, 22 байти

import T
main=print $t

Компіляція з прапором MonomorphismRestriction змушує тип pдо Integer -> Integer -> Integerі, таким чином, дає такий вихід:

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

Компіляція з прапором NoMonomorphismRestriction залишає тип pу найбільш загальному, тобто. Num a => a->a->a- створення щось подібне (скорочено VarTназви до 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"

Спробуйте їх онлайн!


Альтернативи

Оскільки вищевказаний код просто виводить тип типу p, це можна зробити з усіма прапорами, які якимось чином впливають на те, як Haskell виводить типи. Я вкажу лише прапор і з чим замінити функцію pта, якщо потрібно, додаткові прапори (до того ж-XTemplateHaskell ):

Перевантажені списки, 106 байт

Додатково потрібно -XNoMonomorphismRestriction:

p=[]

Або p :: [a]чи p :: IsList l => l, спробувати їх в Інтернеті!

Перевантажені строки, 106 байт

Додатково потрібно -XNoMonomorphismRestriction:

p=""

Або p :: Stringчи p :: IsString s => s, спробувати їх в Інтернеті!

PolyKinds, 112 байт

Це повністю завдяки @CsongorKiss:

data P a=P 

Або P :: P aчи P :: forall k (a :: k). P a, спробувати їх в Інтернеті!

MonadОсмислення, 114 байт

p x=[i|i<-x]

Або p :: [a] -> [a]чи p :: Monad m => m a -> m a, спробувати їх в Інтернеті!

НазваніWildCards, 114 байт

Цю знайшов @Laikoni, вона також потребує -XPartialTypeSignatures:

p=id::_a->_a

Вони мають тип збереження ( p :: a -> a), але GHC генерує різні назви змінних, спробуйте їх в Інтернеті!

ApplicativeDo, 120 байт

p x=do i<-x;pure i

Або p :: Monad m => m a -> m aчи p :: Functor f => f a -> f a, спробувати їх в Інтернеті!

Перевантажені мітки, 120 байт

Для цього потрібен додатковий прапор -XFlexibleContexts:

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

Будь-які типи як p :: a -> b -> bабо p :: IsLabel "id" (a->b) => a -> b, спробуйте їх онлайн!


Чи працює подібна річ для інших прапорів?
H.PWiz

Так, ви можете зробити це з OverloadedStringsабо OverloadedListsточно і , можливо , інші, а ..
ბიმო

2
Він також працює з PolyKinds: Спробуйте в Інтернеті!
Csongor Kiss

1
Також, здається, працює з NamedWildCards: Спробуйте в Інтернеті! (Потрібно -XPartialTypeSignatures)
Лайконі

10

CPP, 27 25

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

Спробуйте в Інтернеті!

Друки ()для -XCPPі 1для-XNoCPP

Попередня версія:

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

Спробуйте в Інтернеті!

Друкується за [1]допомогою -XCPPта [1,2]іншим способом.

Подяки: Це надихає відповідь Лайконі, але замість цього #defineвін просто використовує коментарі C.


9

ScopedTypeVariables, 162 113 байт

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

-XScopedTypeVariables відбитки ""(порожні), -XNoScopedTypeVariables відбитки"[()]" .

Редагувати: оновлене рішення завдяки корисним пропозиціям у коментарях


1
А, бачу. Як правило, приємніше включати свій код у корпус, але також непогані версії. Я також помічаю, що його "T"можна просто замінити "".
Пшеничний майстер

2
Ще одна річ , яку ви можете зробити , це замінити тип даних Tз (). Щоб уникнути необхідності визначати це. Спробуйте в Інтернеті!
Пшеничний чарівник

1
Хороший улов, я щойно зрозумів, що непослідовна прагма може бути включена як прапор: Спробуйте це в Інтернеті!
Csongor Kiss

2
Додатково show можна змінити для друку
H.PWiz

Синтаксис Unicode for forallзаощадить вам кілька байт. Я сумніваюся, що будь-яке рішення, яке потребує додаткових примірників, має велику надію на перемогу.
dfeuer

9

MonoLocalBinds, GADTs або TypeFamilies, 36 32 байти

Редагувати:

  • -4 байти: Версія цього була включена у великий ланцюг поліглотів від stasoid, який мене здивував, поставивши всі декларації на верхній рівень. Очевидно, що запровадження цього обмеження не потребує фактичних локальних прив’язок.
a=0
f b=b^a
main=print(f pi,f 0)
  • З якими - або розширень , ця програма друкує (1.0,1).
  • З будь-якого з прапорів -XMonoLocalBinds , -XGADTs або -XTypeFamilies друкується (1.0,1.0).

  • MonoLocalBindsРозширення існує , щоб запобігти деякий неінтуітівнимі умовивід типу , спровокований GADTs і сім'ями типу. Таким чином, це розширення автоматично включається двома іншими.

  • Це є можливість відключити його знову в явному вигляді з-XNoMonoLocalBinds , цей прийом передбачає , що ви не робите.
  • Як і його більш відомий кузен обмеження мономорфізму, MonoLocalBindsпрацює, запобігаючи деякі значення ( в локальних прив'язок , як letі where, таким чином , назва , мабуть , це також може статися на верхньому рівні) від того , поліморфний. Незважаючи на те, що створено для більш безпечного виводу, правила, коли він спрацьовує , по можливості навіть більш волохаті, ніж ЗМ.

  • Без будь-якого розширення вищезазначена програма підводить тип f :: Num a => a -> a, що дозволяє f piза замовчуванням до a Doubleта f 0an Integer.

  • З розширеннями робиться висновок типу f :: Double -> Double, f 0який також повинен повернути Doubleа.
  • Окремі змінна a=0необхідна , щоб викликати технічні правила: aудар по обмеженню мономорфізму, і aє вільним змінним з f, що означає , що f«и зв'язування група не повністю генералізований , що означає fНЕ закрито , і , таким чином , не стає поліморфними.

9

Перевантажені строки, 65 48 32 байт

Скориставшись RebindableSyntax, використовуйте нашу власну версію fromString, щоб перетворити будь-який літеральний рядок "y".

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

Потрібно скласти -XRebindableSyntax -XImplicitPrelude.

Без -XOverloadedStringsвідбитків ""; з відбитками"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].


1
You can shorten the last line to fromString a=['y'].
Ørjan Johansen

The space in print "n" can also be dropped.
Laikoni

@ØrjanJohansen thanks! I was having it fail with ="y", but =['y'] works fine!
felixphew

1
You can remove the second n from print"n"
Wheat Wizard

1
You can also use -XImplicitPrelude after RebindableSyntax to avoid the import line.
dfeuer

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.


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.


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.


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

Actually, you can do even better: instead of printing in the exception handler, just use pure().
dfeuer

1
@dfeuer: Nice, the D{} trick is pretty cool! Shaved another one off by using PartialTypeSignatures instead of ScopedTypeVariables :)
ბიმო

1
@dfeuer: I had a look and tried a few things, but I never used Generics, so I'm probably not the right person.
ბიმო

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

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!


1
Thanks! Ah, I think I'm on an older version of GHC (the "no applicative" was a warning on my system)
oisdk

3
Using -XDeriveAnyClass you can derive Applicative and Show to save using record syntax, see this.
ბიმო


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.