Zaraz, jaki to język?


37

Ostatnio miałem przyjemność napisać program Haskell, który mógłby wykryć, czy NegativeLiteralsrozszerzenie jest włączone. Wymyśliłem następujące:

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

Wypróbuj online!

Zostanie wydrukowany Truenormalnie i Falseinaczej.

Teraz miałem tyle radości, robiąc to, że rozszerzam wyzwanie na was wszystkich. Jakie inne rozszerzenia języka Haskell możesz złamać?

Zasady

Aby złamać określone rozszerzenie językowe, musisz napisać program Haskell, który kompiluje zarówno z rozszerzeniem językowym, jak i bez niego (ostrzeżenia są w porządku) i wyświetla dwie różne wartości inne niż błędy po uruchomieniu z rozszerzeniem językowym i wyłączeniu go (poprzez dodanie Noprefiksu do rozszerzenie języka). W ten sposób powyższy kod może zostać skrócony do:

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

który drukuje 1i -1.

Każda metoda używana do złamania rozszerzenia musi być specyficzna dla tego rozszerzenia. Mogą istnieć sposoby arbitralnego wykrywania, które flagi kompilatora lub rozszerzenia językowe są włączone, jeśli takie metody nie są dozwolone. Możesz włączyć dodatkowe rozszerzenia językowe lub zmienić optymalizację kompilatora, używając -Obez żadnych opłat do liczby bajtów.

Rozszerzenia językowe

Nie można złamać każde rozszerzenie języka, które nie mają Noodpowiednika (np Haskell98, Haskell2010, Unsafe, Trustworthy, Safe), ponieważ te nie są objęte warunkami opisanymi powyżej. Każde inne rozszerzenie języka jest uczciwą grą.

Punktacja

Otrzymasz jeden punkt za każde rozszerzenie językowe, które złamałeś jako pierwszy, i jeden dodatkowy punkt za każde rozszerzenie językowe, dla którego masz najkrótsze (mierzone w bajtach) pęknięcie. W przypadku drugiego punktu więzi zostaną zerwane na korzyść wcześniejszych wniosków. Wyższy wynik jest lepszy

Nie będziesz w stanie zdobyć punktu za pierwsze zgłoszenie NegativeLiteralslub QuasiQuotesdlatego, że już je złamałem i umieściłem w treści postu. Będziesz jednak mógł zdobyć punkt za najkrótsze pęknięcie każdego z nich. Oto mój trzaskQuasiQuotes

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

Wypróbuj online!


3
Myślę, że to jest lista wszystkich ważnych opcji
H.PWiz

1
Zauważ, że mój powyższy komentarz nie zawiera NondecreasingIndentationz oczywistych powodów
H.PWiz

4
Myślę, że ten tytuł jest mylący, ponieważ jedynym językiem, którego możesz używać, jest Haskell. A Wait, what language extension is this?może coś zupełnie innego.
MD XF,

1
Jestem dość ciekawy, czy można go złamać RelaxedPolyRec, ponieważ kompilator na tyle starożytny, że rzeczywiście obsługuje jego wyłączenie. (Ta opcja pozostała z dokumentacją przez kilka lat po tym, jak przestała coś robić).
dfeuer

1
@dfeuer Patrząc na ten bilet , wydaje się, że GHC 6.12.1 obsługuje wyłączenie.
Ørjan Johansen

Odpowiedzi:


24

MagicHash, 30 bajtów

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

-XMagicHash wyjścia 1, -XNoMagicHash wyjścia 2

MagicHash pozwala na zakończenie nazw zmiennych w #. Dlatego z rozszerzeniem, to definiuje dwie funkcje y#, a x#których każda ma wartość i powrócić stałej 2lub 1. x#xzwróci 1 (ponieważ jest x#stosowany do 1)

Bez rozszerzenia definiuje to jedną funkcję, #która pobiera dwa argumenty i zwraca 2. x#a=1To wzór, który nigdy nie zostanie osiągnięty. Następnie x#xjest 1#1, która zwraca 2.


2
Teraz śpiewam X Magic Hash do melodii Dance Magic Dance . Mam nadzieję, że jesteś dumny!
TRiG

Jestem zdziwiony, że MagicHashnie pozwala na ciągłe hashowanie. Dziwne!
dfeuer

18

CPP, 33 20 bajtów

main=print$0-- \
 +1

Drukuje 0z -XCPPi 1o -XNoCPP.

Za -XCPPpomocą ukośnika \przed nowym wierszem usuwa się nowy wiersz, w ten sposób kod staje się main=print$0-- +1i 0jest drukowany tylko wtedy, gdy +1jest teraz częścią komentarza.

Bez flagi komentarz jest ignorowany, a druga linia jest analizowana jako część poprzedniej linii, ponieważ jest wcięta.


Poprzednie podejście z #define

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

Drukuje również 0z -XCPPi 1z -XNoCPP.


2
O Boże, do tej pory myślałem, że GHC rozebra komentarze Haskella, zanim przejdzie do CPP.
Cubic

@Cubic Czy nie jest to pre -processor?
Bergi

1
@Bergi Jasne, ale wstępnie -processors niekoniecznie oznacza „jest pierwszą rzeczą, która biegnie”, zwłaszcza, że GHC musi dokonać podaniem w pliku do nawet znaleźć pragmy. Sądzę, że komentarze są przechowywane w komentarzach doc i podobne prace po zakończeniu CPP.
Cubic


14

BinaryLiterals, 57 bajtów

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

-XBinaryLiterals wypisuje pojedynczy znak nowej linii. -XNoBinaryLiterals drukuje a 1.

Jestem pewien, że jest na to lepszy sposób. Jeśli znajdziesz, prześlij go.


Czy nie możesz po prostu zdefiniować bjako funkcji (więc żaden plik binarny nie staje się b(0, 1), ale staje się plik binarny 0b1)?
NoOneIsHere

12

Monomorfizm Ograniczenie + 7 innych, 107 bajtów

Używa TH, która wymaga flagi -XTemplateHaskellprzez cały czas.

Plik T.hs, 81 + 4 bajty

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

Główny, 22 bajty

import T
main=print $t

Kompilacja z flagą MonomorphismRestriction wymusza typ pna, Integer -> Integer -> Integera zatem generuje następujące dane wyjściowe:

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

Kompilacja z flagą NoMonomorphismRestriction pozostawia typ pna najbardziej ogólny, tj. Num a => a->a->a- tworzenie czegoś w rodzaju (skrócono VarTnazwy 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"

Wypróbuj je online!


Alternatywy

Ponieważ powyższy kod po prostu wypisuje typ p, można to zrobić za pomocą wszystkich flag, które w jakiś sposób wpływają na sposób, w jaki Haskell określa typy. Podam tylko flagę i tym, co zastąpić funkcję, paw razie potrzeby dodatkowe flagi (oprócz -XTemplateHaskell):

OverloadedLists, 106 bajtów

Dodatkowo potrzebuje -XNoMonomorphismRestriction:

p=[]

Albo p :: [a]albo p :: IsList l => l, spróbuj je online!

OverloadedStrings, 106 bajtów

Dodatkowo potrzebuje -XNoMonomorphismRestriction:

p=""

Albo p :: Stringalbo p :: IsString s => s, spróbuj je online!

PolyKinds, 112 bajtów

Wynika to całkowicie z @CsongorKiss:

data P a=P 

Albo P :: P aalbo P :: forall k (a :: k). P a, spróbuj je online!

MonadCompstandingions, 114 bajtów

p x=[i|i<-x]

Albo p :: [a] -> [a]albo p :: Monad m => m a -> m a, spróbuj je online!

NamedWildCards, 114 bajtów

Ten został znaleziony przez @Laikoni, wymaga dodatkowo -XPartialTypeSignatures:

p=id::_a->_a

Oba mają typ zapisu ( p :: a -> a), ale GHC generuje różne nazwy zmiennych, wypróbuj je online!

ApplicativeDo, 120 bajtów

p x=do i<-x;pure i

Albo p :: Monad m => m a -> m aalbo p :: Functor f => f a -> f a, spróbuj je online!

OverloadedLabels, 120 bajtów

Wymaga to dodatkowej flagi -XFlexibleContexts:

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

Albo typy jak p :: a -> b -> blub p :: IsLabel "id" (a->b) => a -> b, spróbuj je online!


Czy podobna rzecz działa w przypadku innych flag?
H.PWiz

Tak, możesz to zrobić z OverloadedStringslub OverloadedListsna pewno i prawdopodobnie także inni ...
ბიმო

2
Działa również z PolyKinds: Wypróbuj online!
Csongor Kiss

1
Wydaje się również współpracować z NamedWildCards: Wypróbuj online! (Wymaga -XPartialTypeSignatures)
Laikoni

10

CPP, 27 25

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

Wypróbuj online!

Wydruki ()dla -XCPPi 1dla-XNoCPP

Poprzednia wersja:

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

Wypróbuj online!

Drukuje [1]z -XCPPlub w [1,2]inny sposób.

Kredyty: Jest to inspirowane odpowiedzią Laikoni, ale zamiast #definetego po prostu używa komentarzy C.


9

ScopedTypeVariables, 162 113 bajtów

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

-XScopedTypeVariables drukuje ""(pusty), -XNoScopedTypeVariables drukuje "[()]".

Edycja: zaktualizowane rozwiązanie dzięki przydatnym sugestiom w komentarzach


1
O, rozumiem. Zazwyczaj ładniej jest umieścić swój kod w ciele, ale wersje bez golfa są również miłe. Zauważam też, że "T"można to po prostu zastąpić "".
Wheat Wizard

2
Inną rzeczą, jaką możesz zrobić, to wymienić typ danych Tz (). Aby uniknąć konieczności jego definiowania. Wypróbuj online!
Wheat Wizard

1
Fajny haczyk, właśnie zdałem sobie sprawę, że niespójną pragmę można zaliczyć do flagi: Wypróbuj online!
Csongor Kiss

2
Dodatkowo show można zmienić na druk
H.PWiz

Składnia Unicode dla forallpozwoli Ci zaoszczędzić kilka bajtów. Wątpię jednak, aby jakiekolwiek rozwiązanie wymagające dodatkowych instancji miało dużą nadzieję na zwycięstwo.
dfeuer

9

MonoLocalBinds, GADTs lub TypeFamilies, 36 32 bajtów

EDYTOWAĆ:

  • -4 bajty: Wersja tego została włączona przez Stasoid do wielkiego łańcucha poliglotów , który zaskoczył mnie, umieszczając wszystkie deklaracje na najwyższym poziomie. Najwyraźniej uruchomienie tego ograniczenia nie wymaga rzeczywistych lokalnych powiązań.
a=0
f b=b^a
main=print(f pi,f 0)
  • Bez rozszerzeń ten program drukuje (1.0,1).
  • Z każdą z flag -XMonoLocalBinds , -XGADTs lub -XTypeFamilies , drukuje (1.0,1.0).

  • MonoLocalBindsPrzedłużenie istnieje, aby zapobiec trochę nieintuicyjne typu wnioskowanie wyzwalany przez GADTs i rodzin typu. W związku z tym to rozszerzenie jest automatycznie włączane przez dwie pozostałe.

  • Można to jednoznacznie wyłączyć za pomocą -XNoMonoLocalBinds, ta sztuczka zakłada, że ​​nie.
  • Podobnie jak jego bardziej znany kuzyn, ograniczenie monomorfizmu, MonoLocalBindsdziała poprzez zapobieganie polimorficzności niektórych wartości ( w lokalnych wiązaniach takich jak letlub where, a więc nazwa najwyraźniej może się zdarzyć na najwyższym poziomie). Pomimo tego, że został stworzony do wnioskowania o typie rozsądniejszego, reguły dotyczące jego wyzwalania są, jeśli to możliwe, jeszcze bardziej owłosione niż MR.

  • Bez rozszerzenia powyższy program podaje typ f :: Num a => a -> a, pozwalając f pidomyślnie na a Doublei f 0na Integer.

  • W przypadku rozszerzeń wywnioskowany typ staje się f :: Double -> Doublei f 0musi również zwrócić a Double.
  • Oddzielna zmienna a=0jest potrzebne do uruchomienia przepisy techniczne: ajest trafiony przez ograniczenie monomorfizm i ajest zmienna wolna od f, co oznacza, że fjest grupa wiążący nie jest w pełni uogólnione , co oznacza, fnie jest zamknięty , a zatem nie stać polimorficzny.

9

OverloadedStrings, 65 48 32 bajtów

Korzystając z RebindableSyntax, skorzystaj z naszej własnej wersji fromString, aby zamienić dowolny ciąg literału na "y".

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

Musi zostać skompilowany z -XRebindableSyntax -XImplicitPrelude.

Bez -XOverloadedStringsnadruków ""; z nadrukami "y".

Dopiero teraz uderzyło mnie, że ta sama technika działa z (np.) OverloadedLists:

OverloadedLists, 27 bajtów

main=print[0]
fromListN=(:)

Musi zostać skompilowany z -XRebindableSyntax -XImplicitPrelude.

Bez -XOverloadedListsnadruków [0]; z nadrukami [1,0].


1
Możesz skrócić ostatnią linię do fromString a=['y'].
Ørjan Johansen

Miejsce w print "n"można również upuścić.
Laikoni

@ ØrjanJohansen dzięki! Nie udało mi się ="y", ale =['y']działa dobrze!
felixphew

1
Możesz usunąć drugi nzprint"n"
Wheat Wizard

1
Możesz także użyć -XImplicitPreludepo, RebindableSyntaxaby uniknąć linii importu.
dfeuer

8

BangPatterns, 32 bajty

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

-XBangPatterns drukuje, 1podczas gdy -XNoBangPatterns drukuje 0.

Wykorzystuje to fakt, że flaga BangPatterns pozwala na dodawanie adnotacji do wzorców w !celu wymuszenia oceny WHNF, w takim przypadku 9!1użyje definicji najwyższego poziomu (!)=seq. Jeśli flaga nie jest włączona, f!_definiuje nowego operatora (!)i przesłania definicję najwyższego poziomu.


7

ApplicativeDo, 104 bajty

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

Wypróbuj online!

Z ApplicativeDo, to drukuje

ZipList {getZipList = [1]}

Bez tego drukuje

ZipList {getZipList = []}

ZipListjest jednym z niewielu typów w bibliotekach podstawowych z instancją dla, Applicativeale nie dla Monad. Gdzieś czają się krótsze alternatywy.


7

Ścisłe, 87 84 82 bajtów

-5 bajtów dzięki dfeuer !

Może być mniej z BlockArgumentsoszczędzaniem parens wokół \_->print 1:

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

Uruchomienie tego z -XStrict spowoduje wydrukowanie a, 1natomiast uruchomienie go z -XSoStrict spowoduje wydrukowanie a 0. Wykorzystuje to, że Haskell domyślnie jest leniwy i nie musi oceniać, error""ponieważ już wie, że wynikiem będzie 0dopasowanie pierwszego argumentu (!), to zachowanie można zmienić za pomocą tej flagi - zmuszając środowisko wykonawcze do oceny obu argumentów.

Jeśli nic nie jest drukowane w jednym przypadku, możemy sprowadzić go do 75 bajtów, zastępując główny przez (także niektóre bajty wyłączone przez dfeuer ):

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

StrictData, 106 99 93 bajtów

-15 bajtów dzięki dfeuer !

To w zasadzie robi to samo, ale zamiast tego działa z polami danych:

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

Drukuje 1z flagą -XStrictData i 0z -XNoStrictData .

Jeśli nic nie jest drukowane w jednym przypadku, możemy zmniejszyć go do 86 bajtów, zastępując główny przez (19 bajtów przez dfeuer ):

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

Uwaga: wszystkie rozwiązania wymagają TypeApplicationszestawu.


Możesz to dość łatwo zmniejszyć do 98 bajtów, co dokładnie pasuje do mojego (zupełnie innego) rozwiązania. TIO .
dfeuer

W rzeczywistości możesz zrobić jeszcze lepiej: zamiast drukowania w module obsługi wyjątków, po prostu użyj pure().
dfeuer

1
@dfeuer: Fajnie, D{}sztuczka jest całkiem fajna! Ogoliłem jeszcze jeden, używając PartialTypeSignatureszamiast ScopedTypeVariables:)
ბიმო

1
@dfeuer: Spojrzałem i wypróbowałem kilka rzeczy, ale nigdy nie używałem Generics, więc prawdopodobnie nie jestem odpowiednią osobą.
ბიმო

1
Można to zrobić jeszcze lepiej z krawędzi krwawienia GHC i -XBlockArguments:main=catch @ErrorCall(p$seq(D$error"")1)\_->p 3
dfeuer

6

ApplicativeDo, 146 bajtów

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}

Drukuje 1, gdy włączona jest opcja ApplicativeDo, w przeciwnym razie 0

Wypróbuj online!


1
Dzięki! Ach, myślę, że jestem na starszej wersji GHC („brak aplikacji” był ostrzeżeniem dla mojego systemu)
oisdk

3
Korzystając z opcji -XDeriveAnyClass, możesz uzyskać Applicativei Showzapisać przy użyciu składni rekordu, zobacz to .
ბიმო

6

BinaryLiterals, 31 24 bajtów

Edytować:

  • -7 bajtów: H.PWiz zaproponował dalsze dostosowanie za pomocą jednej b12zmiennej.

Dostosowanie metody H.PWiz , unikanie wystąpienia funkcji.

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

6

ExtendedDefaultRules, 54 53 bajtów

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

Drukuje ()z -XExtendedDefaultRulesi 0o -XNoExtendedDefaultRules.

Ta flaga jest domyślnie włączona w GHCi, ale nie w GHC, co ostatnio spowodowało pewne zamieszanie , chociaż BMO szybko było w stanie pomóc.

Powyższy kod jest golfową wersją przykładu w Podręczniku użytkownika GHC, w którym wyjaśniono domyślny typ w GHCi .

-1 bajt dzięki Ørjan Johansen !


Przyglądając się temu kodowi zapożyczonemu w poliglocie (gdzie nawiasy powodują pewne problemy), przypomniałem sobie, że GHC obsługuje krótszą składnię o jeden bajt toEnum 0::Num a=>Enum a=>a.
Ørjan Johansen

Można je dostać w dół do 48 bajtów z PartialTypeSignatures: main=print(toEnum 0::_=>Num a=>a). Ponadto Twój link TIO jest nieaktualny.
dfeuer

6

RebindableSyntax , 25 bajtów

Czytałem niedawno opublikowany Przewodnik po rozszerzeniach GHC, kiedy zauważyłem łatwy, którego jeszcze nie pamiętałem.

main|negate<-id=print$ -1

Wymaga również -XImplicitPreludelub alternatywnie import Preludew samym kodzie.

  • -XRebindableSyntax zmienia zachowanie niektórych cukrów syntaktycznych Haskella, aby umożliwić jego przedefiniowanie.
  • -1jest cukrem syntaktycznym dla negate 1.
  • Zwykle tak negatejest Prelude.negate, ale z rozszerzeniem jest to „którekolwiek negatejest w zasięgu w momencie użycia”, które jest zdefiniowane jako id.
  • Ponieważ rozszerzenie ma służyć do zastępowania Preludemodułu, automatycznie wyłącza zwykły domyślny import tego modułu, ale tutaj potrzebne są inne Preludefunkcje (jak print), więc można je ponownie włączyć -XImplicitPrelude.

6

Ścisłe, 52 bajty

import GHC.IO
f _=print()
main=f$unsafePerformIO$f()

-XStrict

-XNoStrict

Dzięki -XStrictdrukuje ()dodatkowy czas.

Dzięki @Sriotchilism O'Zaic za dwa bajty.


6

StrictData, 58 bajtów

import GHC.Exts
data D=D Int
main=print$unsafeCoerce#D 3+0

(Linki są nieco nieaktualne; zostaną naprawione).

-XNoStrictData

-XStrictData

Wymaga MagicHash(abyśmy mogli importować GHC.Extszamiast Unsafe.Coerce) i -O(absolutnie wymagane, aby umożliwić rozpakowanie małych ścisłych pól).

Za pomocą -XStrictData, drukuje 3. W przeciwnym razie drukuje wartość całkowitą wskaźnika (prawdopodobnie oznaczonego) do wstępnie przydzielonej kopii 3::Integer, która nie może być równa 3.

Wyjaśnienie

Będzie to nieco łatwiejsze do zrozumienia z niewielkim rozszerzeniem, opartym na domyślnym typie. Dzięki podpisom możemy usunąć dodatek.

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

Równoważnie

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

Dlaczego kiedykolwiek drukuje 3? To wydaje się zaskakujące! Cóż, małe Integerwartości są reprezentowane bardzo podobnie jak Ints, które (przy ścisłych danych) są reprezentowane podobnie jak Ds. W końcu ignorujemy znacznik wskazujący, czy liczba całkowita jest mała, czy duża dodatnia / ujemna.

Dlaczego nie można wydrukować 3 bez rozszerzenia? Pomijając wszelkie przyczyny związane z układem pamięci, wskaźnik danych z małymi bitami (2 najniższe dla 32-bitów, 3 najniższe dla 64-bitów) 3 musi reprezentować wartość zbudowaną z trzeciego konstruktora. W takim przypadku wymagałoby to ujemnej liczby całkowitej.


5

UnboxedTuples, 52 bajty

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

Wymaga -XTemplateHaskell. Drukuje ConE GHC.Prim.(##)z -XUnboxedTuples i UnboundVarE ##z -XNoUnboxedTuples .


Czy nie powinno być innego wyniku +16 dla wymaganej opcji -XTemplateHaskell?
celtschk

2
@celtschk Nie policzyłem tego, ponieważ obecny meta konsensus w sprawie flag wiersza poleceń mówi, że nie są one liczone, ale stanowią nowy język. Chociaż po zastanowieniu się nad tym widzę, że w kontekście tego wyzwania, które pozwala tylko na odpowiedzi Haskella, ale także użycie innych flag, nie jest całkiem jasne, co to zrobić. Zapytam o to OP.
Laikoni

Nie wiedziałem, że konsensus w tej sprawie się zmienił. Dziękuję za wskaźnik. Zapytanie OP to na pewno dobry pomysł.
celtschk


5

HexFloatLiterals , 49 25 bajtów

-24 bajty dzięki Ørjan Johansen.

main|(.)<-seq=print$0x0.0

Drukuje 0.0z -XHexFloatLiteralsi 0o -XNoHexFloatLiterals.

Nie ma linków TIO, ponieważ w ghc 8.4.1 dodano HexFloatLiterals, ale TIO ma ghc 8.2.2.


main|(.)<-seq=print$0x0.0pozwala uniknąć ukrywania importu.
Ørjan Johansen

main|let _._=0=print$0x0.0może być łatwiejsze dla poliglota.
Ørjan Johansen

5

ScopedTypeVariables, 37 bajtów

main=print(1::_=>a):: a.a~Float=>_

Wymaga to również UnicodeSyntax, PartialTypeSignatures, GADTs, i ExplicitForAll.

Wypróbuj online (bez rozszerzenia)

Wypróbuj online (z rozszerzeniem)

Wyjaśnienie

Podpisy typu częściowego służą jedynie do zapisywania bajtów. Możemy je wypełnić w następujący sposób:

main=print(1::(Num a, Show a)=>a):: a.a~Float=>IO ()

Z o zakresie zmiennych typu, aw rodzaju 1jest ograniczone być aw rodzaju main, który z kolei jest przymocowany do być Float. Bez zmiennych typu o zasięgu 1domyślnie wpisuje się Integer. Ponieważ Floati Integerwartości są pokazane inaczej, możemy je rozróżnić.

Dzięki @ ØrjanJohansen za aż 19 bajtów! Uświadomił sobie, że znacznie lepiej jest wykorzystać różnicę między Showinstancjami różnych typów liczbowych niż różnice w ich arytmetyce. Uświadomił sobie również, że można pozostawić typ main„dwuznacznie składniowo”, ponieważ ograniczenie faktycznie go ujednoznacznia. Pozbycie się funkcji lokalnej uwolniło mnie również do usunięcia podpisu typu dla main(przeniesienie go do RHS), aby zaoszczędzić pięć kolejnych bajtów.



@ ØrjanJohansen, miło .
dfeuer

@ ØrjanJohansen, czy powinienem dokonać edycji, czy wolisz dodać własną?
dfeuer

Edytuj, to była stopniowa ewolucja od twojej.
Ørjan Johansen

@ ØrjanJohansen, dzięki, to było piękne.
dfeuer

5

DeriveAnyClass, 121 113 bajtów

Dzięki dfeuer za całkiem sporo bajtów!

import Control.Exception
newtype M=M Int deriving(Show,Num)
main=handle h$print(0::M);h(_::SomeException)=print 1

Drukuje -XDeriveAnyClass,1 podczas gdy -XNoDeriveAnyClass drukuje M 0.

Wykorzystuje to fakt, że DeriveAnyClass jest strategią domyślną, gdy zarówno DeriveAnyClass, jak i GeneralizedNewtypeDeriving są włączone, jak widać z ostrzeżeń. Ta flaga chętnie generować puste implementacje wszystkich metod, ale GeneralizedNewtypeDeriving jest rzeczywiście mądry wystarczy użyć wdrożenie instrumentu bazowego Type i ponieważ Intjest Numona nie zawiedzie w tej sprawie.


Jeśli nic nie zostanie wydrukowane, jeśli flaga jest włączona, zastąpienie mainjej następującą wartością będzie 109 bajtów :

main=print(0::M)`catch`(mempty::SomeException->_)

Przynajmniej w środku runhaskell, to faktycznie drukuje, M 1z -XDeriveAnyClasspowodu lenistwa ...
przestało się obracać przeciwnie do zegara

@ceasedtoturncounterclockwis: Tak również w GHCi, ale podczas kompilacji na TIO (i mojej maszynie), a następnie uruchomienie go powoduje 1:)
ბიმო



1
Sprowadziłem go do 104 w zupełnie inny sposób, więc dodałem własną odpowiedź.
dfeuer

4

PostfixOperators, 63 bajty

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

Wypróbuj online (bez rozszerzenia)

Wypróbuj online (z rozszerzeniem)

To jest wycięta wersja poliglota Hugs / GHC, który napisałem . Zobacz ten post dla wyjaśnienia. Dzięki @ ØrjanJohansen za uświadomienie sobie, że mogę użyć idzamiast operatora niestandardowego, oszczędzając cztery bajty.


idmożna użyć zamiast !.
Ørjan Johansen

@ ØrjanJohansen, tak, rzeczywiście! To oszczędza fajne cztery bajty.
dfeuer




3

TemplateHaskell, 140 91 bajtów

Właśnie skopiowane z mauke z niewielkimi modyfikacjami. Nie wiem co się dzieje.

-49 bajtów dzięki Ørjan Johansen.

import Language.Haskell.TH
instance Show(Q a)where show _=""
main=print$(pure$TupE[]::ExpQ)

Wypróbuj online!


$(...)(bez spacji) to składnia oceny szablonu, gdy TH jest włączone, a TupE[](„pusta krotka”) daje (). UżywanieShow może działać dobrze dla poliglota, chociaż w przypadku tego konkretnego wyzwania czuję się trochę źle, definiując wartość do wydrukowania jako pusty ciąg ...
Ørjan Johansen

2

Monomorfizm Ograniczenie, 31 29 bajtów

Edytować:

  • -2 bajty z poprawą H.PWiz
f=(2^)
main=print$f$f(6::Int)

-X Odbitki monomorfizmu0 . -XNoMonomorphismRestriction prints 18446744073709551616.

  • Z tym ograniczeniem dwa zastosowania fmuszą być tego samego typu, więc program drukuje 2^2^6 = 2^64jako 64-bitowy Int(na platformach 64-bitowych), co powoduje przepełnienie 0.
  • Bez ograniczeń program drukuje się 2^64jako bignum Integer.

1
Myślę, f=(2^);main=print$f$f(64::Int)że uratuje bajt. Ale to nie zakończy się realistycznie
H.PWiz

@ H.PWiz Na szczęście 64=2^6, co oszczędza kolejny bajt.
Ørjan Johansen

1

ScopedTypeVariables, 119 97 bajtów

Właśnie skopiowane z mauke z niewielkimi modyfikacjami.

Obecnie istnieją dwie inne odpowiedzi dla ScopedTypeVariables: 113 bajtów Csongor Kiss i 37 bajtów dfeuer . To zgłoszenie różni się tym, że nie wymaga innych rozszerzeń Haskell.

-22 bajty dzięki Ø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)

Wypróbuj online!


97 bajtów (chociaż IO()/printsztuczka nie działa w poliglocie).
Ørjan Johansen

@ ØrjanJohansen Dodałem ScopedTypeVariables, ale złamałem ExtendedDefaultRules . Jak można to naprawić? Już wcześniej miałem taki błąd, ale nie mogę tutaj zastosować twojego wyjaśnienia. Kod ScopedTypeVariables Dodałem jest to .
stasoid

Rozumiem, kody używają podobnych domyślnych sztuczek i kolidują ze sobą. Jednym z rozwiązań jest pozwolenie nowemu na użycie bardziej ograniczonej klasy niż Num. Myślę, że class(Show a,Floating a)=>K a where{k::a->String;k=pure$ show(f pi)where f=id::a->a};powinien działać, wygodnie go używać Floati Doublewyświetlać piz różną precyzją.
Ørjan Johansen

@ ØrjanJohansen Wow, to pasuje od razu. Dziękuję.
stasoid
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.