Kürzlich hatte ich das Vergnügen, ein Haskell-Programm zu schreiben, das erkennen konnte, ob die NegativeLiterals
Erweiterung belegt war. Ich habe mir folgendes ausgedacht:
data B=B{u::Integer}
instance Num B where{fromInteger=B;negate _=B 1}
main=print$1==u(-1)
Dies wird True
normal und False
ansonsten gedruckt .
Jetzt hatte ich so viel Spaß dabei, dass ich die Herausforderung auf euch alle ausdehne. Welche anderen Haskell-Spracherweiterungen können Sie knacken?
Regeln
Um eine bestimmte Spracherweiterung zu knacken, müssen Sie ein Haskell-Programm schreiben, das mit und ohne Spracherweiterung kompiliert (Warnungen sind in Ordnung) und zwei verschiedene fehlerfreie Werte ausgibt , wenn es mit der Spracherweiterung ausgeführt und deaktiviert wird (durch Hinzufügen des No
Präfixes zu) die Spracherweiterung). Auf diese Weise könnte der obige Code auf Folgendes gekürzt werden:
data B=B{u::Integer}
instance Num B where{fromInteger=B;negate _=B 1}
main=print$u(-1)
welche druckt 1
und -1
.
Jede Methode, die Sie zum Knacken einer Erweiterung verwenden, muss für diese Erweiterung spezifisch sein. Es kann Möglichkeiten geben, willkürlich festzustellen, welche Compiler-Flags oder LanguageExtensions aktiviert sind, wenn solche Methoden nicht zulässig sind. Sie können zusätzliche Spracherweiterungen aktivieren oder die Compileroptimierung kostenlos -O
an Ihrer Byteanzahl ändern .
Spracherweiterungen
Sie können keine Spracherweiterung knacken, der keinen hat No
Gegenstück (zB Haskell98
, Haskell2010
, Unsafe
, Trustworthy
, Safe
) , da diese nicht unter den oben genannten Bedingungen fallen. Jede andere Spracherweiterung ist Freiwild.
Wertung
Sie erhalten einen Punkt für jede Spracherweiterung, die Sie als erste Person knacken, und einen zusätzlichen Punkt für jede Spracherweiterung, für die Sie den kürzesten (gemessen in Byte) Riss haben. Für den zweiten Punkt werden die Bande zugunsten früherer Einreichungen unterbrochen. Eine höhere Punktzahl ist besser
Sie können keinen Punkt für die erste Einreichung erzielen, NegativeLiterals
oder QuasiQuotes
weil ich sie bereits geknackt und in den Inhalt des Beitrags aufgenommen habe. Sie werden jedoch in der Lage sein, einen Punkt für den kürzesten Riss von jedem von diesen zu erzielen. Hier ist mein Riss vonQuasiQuotes
import Text.Heredoc
main=print[here|here<-""] -- |]
quelle
NondecreasingIndentation
aus offensichtlichen Gründen nicht enthaltenWait, what language extension is this?
Oder etwas ganz anderes.RelaxedPolyRec
, für einen Compiler, der alt genug ist, um das Ausschalten tatsächlich zu unterstützen. (Die Option blieb mit der Dokumentation einige Jahre lang bestehen, nachdem sie aufgehört hatte, irgendetwas zu tun.)Antworten:
MagicHash, 30 Bytes
-XMagicHash gibt 1 aus, -XNoMagicHash gibt 2 aus
Mit MagicHash können Variablennamen in a enden
#
. Daher mit der Erweiterung definiert diese beiden Funktioneny#
undx#
die jeweils einen Wert annehmen , und eine konstante Rück2
oder1
.x#x
gibt 1 zurück (weil esx#
angewendet wird1
)Ohne die Erweiterung wird eine Funktion definiert,
#
die zwei Argumente akzeptiert und zurückgibt2
. Dasx#a=1
ist ein Muster, das niemals erreicht wird. Dannx#x
ist1#1
, was 2 zurückgibt.quelle
MagicHash
dass nicht nachgestellte Hashes nicht zulässig sind. Seltsam!CPP,
3320 BytesDruckt
0
mit-XCPP
und1
mit-XNoCPP
.Mit
-XCPP
einem Schrägstrich\
vor einer neuen Zeile wird die neue Zeile entfernt, so dass der Codemain=print$0-- +1
nur0
gedruckt wird, wenn er+1
jetzt Teil des Kommentars ist.Ohne das Flag wird der Kommentar ignoriert und die zweite Zeile wird als Teil der vorherigen Zeile analysiert, da sie eingerückt ist.
Vorheriger Ansatz mit
#define
Druckt auch
0
mit-XCPP
und1
mit-XNoCPP
.quelle
NumDecimals, 14 Bytes
-XNumDecimals druckt
10
. -XNoNumDecimals druckt10.0
.quelle
BinaryLiterals, 57 Bytes
-XBinaryLiterals gibt eine einzelne neue Zeile aus. -XNoBinaryLiterals druckt a
1
.Ich bin sicher, es gibt einen besseren Weg, dies zu tun. Wenn Sie einen finden, posten Sie ihn bitte.
quelle
b
als Funktion definieren (also wird keine Binärdateib(0, 1)
, sondern Binärdatei0b1
)?MonomorphismRestriction + 7 andere, 107 Bytes
Dies verwendet TH, wofür das Flag immer benötigt wird
-XTemplateHaskell
.Datei T.hs, 81 + 4 Bytes
Haupt, 22 Bytes
Das Kompilieren mit dem Flag MonomorphismRestriction erzwingt den Typ von
p
toInteger -> Integer -> Integer
und erzeugt somit die folgende Ausgabe:Beim Kompilieren mit dem Flag NoMonomorphismRestriction bleibt der Typ von
p
am allgemeinsten, d. H.Num a => a->a->a
- Herstellung von etwas wie (dieVarT
Namen verkürzta
):Probiere sie online aus!
Alternativen
Da der obige Code einfach den Typ von
p
ausgibt, kann dies mit allen Flags erfolgen, die irgendwie Einfluss darauf haben, wie Haskell Typen ableitet. Ich werde nur das Flag angeben und womit die Funktion zu ersetzen istp
und ggf. zusätzliche Flags (nebenbei-XTemplateHaskell
):OverloadedLists, 106 Bytes
Benötigt zusätzlich
-XNoMonomorphismRestriction
:Entweder
p :: [a]
oderp :: IsList l => l
, versuchen Sie sie online!OverloadedStrings, 106 Bytes
Benötigt zusätzlich
-XNoMonomorphismRestriction
:Entweder
p :: String
oderp :: IsString s => s
, versuchen Sie sie online!PolyKinds, 112 Bytes
Dies ist ausschließlich @CsongorKiss zu verdanken:
Entweder
P :: P a
oderP :: forall k (a :: k). P a
, versuchen Sie sie online!MonadComprehensions, 114 Byte
Entweder
p :: [a] -> [a]
oderp :: Monad m => m a -> m a
, versuchen Sie sie online!NamedWildCards, 114 Bytes
Diese wurde von @Laikoni gefunden und benötigt zusätzlich
-XPartialTypeSignatures
:Beide haben den Speichertyp (
p :: a -> a
), aber GHC generiert unterschiedliche Namen für die Variablen. Probieren Sie sie online aus!ApplicativeDo, 120 Byte
Entweder
p :: Monad m => m a -> m a
oderp :: Functor f => f a -> f a
, versuchen Sie sie online!OverloadedLabels, 120 Byte
Dies benötigt das zusätzliche Flag
-XFlexibleContexts
:Entweder Typen wie
p :: a -> b -> b
oderp :: IsLabel "id" (a->b) => a -> b
, versuchen Sie sie online!quelle
OverloadedStrings
oderOverloadedLists
sicher und wahrscheinlich auch mit anderen machen.PolyKinds
: Online ausprobieren!NamedWildCards
: Online ausprobieren! (Erforderlich-XPartialTypeSignatures
)CPP,
2725Probieren Sie es online!
Drucke
()
für-XCPP
und1
für-XNoCPP
Vorherige Version:
Probieren Sie es online!
Druckt
[1]
mit-XCPP
und[1,2]
anders.Credits: Dies ist von der Antwort von Laikoni inspiriert, verwendet aber statt eines
#define
einfach C-Kommentare.quelle
ScopedTypeVariables,
162 -113 Byte-XScopedTypeVariables druckt
""
(leer), -XNoScopedTypeVariables druckt"[()]"
.Edit: aktualisierte Lösung dank nützlicher Vorschläge in den Kommentaren
quelle
"T"
nur durch ersetzt werden kann""
.T
durch ersetzen()
. Um es nicht definieren zu müssen. Probieren Sie es online!show
Kann für Druckforall
sparen Sie einige Bytes. Ich bezweifle, dass jede Lösung, die zusätzliche Instanzen benötigt, viel Hoffnung auf einen Sieg hat.MonoLocalBinds, GADTs oder TypeFamilies,
3632 BytesBEARBEITEN:
(1.0,1)
.Mit den Flags -XMonoLocalBinds , -XGADTs oder -XTypeFamilies wird gedruckt
(1.0,1.0)
.Die
MonoLocalBinds
Erweiterung soll verhindern, dass durch GADTs und Typfamilien eine nicht intuitive Typinferenz ausgelöst wird. Daher wird diese Erweiterung von den beiden anderen automatisch aktiviert.-XNoMonoLocalBinds
, dieser Trick geht davon aus, dass Sie dies nicht tun.Wie seine bekanntere Cousine, die Monomorphismus-Beschränkung,
MonoLocalBinds
verhindert sie, dass einige Werte (in lokalen Bindungen wieanscheinend auch auf oberster Ebene vorkommen) polymorph sind. Die Regeln für den Zeitpunkt der Auslösung sind, obwohl sie für eine genauere Typinferenz erstellt wurden, nach Möglichkeit noch haariger als die MR.let
oderwhere
, daher kann der NameDas obige Programm fügt den Typ ohne Erweiterung ein und
f :: Num a => a -> a
erlaubtf pi
standardmäßig aDouble
undf 0
anInteger
.f :: Double -> Double
undf 0
mussDouble
auch a zurückgeben.a=0
wird benötigt, um die technischen Regeln auszulösen:a
Wird von der Monomorphismus-Beschränkung getroffen unda
ist eine freie Variable vonf
, was bedeutet, dassf
die Bindungsgruppe nicht vollständig verallgemeinert ist , dhf
nicht geschlossen ist und daher nicht polymorph wird.quelle
OverloadedStrings,
654832 BytesVerwenden Sie unter Ausnutzung von RebindableSyntax unsere eigene Version von fromString, um jedes String-Literal in zu verwandeln
"y"
.Muss mit kompiliert werden
-XRebindableSyntax -XImplicitPrelude
.Ohne
-XOverloadedStrings
Drucke""
; mit drucke"y"
.Außerdem ist mir erst jetzt aufgefallen, dass die gleiche Technik mit (zB) OverloadedLists funktioniert:
OverloadedLists, 27 Bytes
Muss mit kompiliert werden
-XRebindableSyntax -XImplicitPrelude
.Ohne
-XOverloadedLists
Drucke[0]
; mit drucke[1,0]
.quelle
fromString a=['y']
.print "n"
kann auch fallen gelassen werden.="y"
, aber=['y']
funktioniert gut!n
von entfernenprint"n"
-XImplicitPrelude
nach verwendenRebindableSyntax
, um die Importzeile zu umgehen.BangPatterns, 32 Bytes
-XBangPatterns druckt
1
während -XNoBangPatterns druckt0
.Dies macht Gebrauch davon, dass das Flag BangPatterns erlaubt, Muster mit Anmerkungen zu versehen
!
, um die Auswertung an WHNF zu erzwingen. In diesem Fall9!1
wird die Definition der obersten Ebene verwendet(!)=seq
. Wenn das Flag nicht aktiviertf!_
ist, wird ein neuer Operator definiert(!)
und die Definition der obersten Ebene abgeschattet.quelle
ApplicativeDo, 104 Byte
Probieren Sie es online!
Mit
ApplicativeDo
wird dies gedrucktOhne es druckt es
ZipList
ist einer der wenigen Typen in den Basisbibliotheken mit einer Instanz für,Applicative
aber nicht fürMonad
. Es kann kürzere Alternativen geben, die irgendwo lauern.quelle
Streng,
87 8482 Bytes-5 bytes dank dfeuer !
Könnte weniger mit dem
BlockArguments
Speichern der Eltern herum sein\_->print 1
:Wird dies mit -XStrict ausgeführt, wird ein ausgegeben ,
1
während bei Ausführung mit -XNoStrict ein ausgegeben wird0
. In diesem Fall ist Haskell standardmäßig faul und muss nicht ausgewertet werden,error""
da bereits bekannt ist, dass das Ergebnis0
bei Übereinstimmung mit dem ersten Argument von angezeigt wird.(!)
Dieses Verhalten kann mit diesem Flag geändert werden, sodass die Laufzeit beide Argumente auswerten muss.Wenn in einem Fall nichts gedruckt werden darf, können wir es auf 75 Bytes reduzieren , indem wir das Hauptbyte ersetzen (auch einige Bytes von dfeuer ):
StrictData,
106 9993 Bytes-15 bytes dank dfeuer !
Dies funktioniert im Prinzip genauso, funktioniert jedoch stattdessen mit Datenfeldern:
Druck
1
mit der -XStrictData Flagge und0
mit -XNoStrictData .Wenn in einem Fall nichts gedruckt werden darf, können wir es auf 86 Bytes reduzieren, wobei das Hauptbyte durch (19 Bytes durch dfeuer ) ersetzt wird:
Hinweis: Alle Lösungen müssen
TypeApplications
festgelegt werden.quelle
pure()
.D{}
Trick ist ziemlich cool! Rasiert eine andere von mitPartialTypeSignatures
anstelle vonScopedTypeVariables
:)-XBlockArguments
:main=catch @ErrorCall(p$seq(D$error"")1)\_->p 3
ApplicativeDo, 146 Bytes
Gibt 1 aus, wenn ApplicativeDo aktiviert ist, andernfalls 0
Probieren Sie es online!
quelle
Applicative
undShow
mit Rekord - Syntax zu speichern, finden Sie diese .BinaryLiterals,
3124 BytesBearbeiten:
b12
Variablen weiter anzupassen .Eine Anpassung der Methode von H.PWiz unter Vermeidung der Funktionsinstanz.
0b12
lexes as0
b12
mit 0 + 1 = ausgegeben1
.0b12
lexes as0b1
2
mit 1 + 2 = ausgegeben3
.quelle
ExtendedDefaultRules,
5453 BytesDruckt
()
mit-XExtendedDefaultRules
und0
mit-XNoExtendedDefaultRules
.Dieses Flag ist standardmäßig in GHCi aktiviert, aber nicht in GHC, was kürzlich einige Verwirrung bei mir ausgelöst hat , obwohl BMO schnell helfen konnte.
Der obige Code ist eine Golfversion eines Beispiels im GHC-Benutzerhandbuch, in dem der in GHCi voreingestellte Typ erläutert wird.
-1 Byte danke an Ørjan Johansen !
quelle
toEnum 0::Num a=>Enum a=>a
.PartialTypeSignatures
:main=print(toEnum 0::_=>Num a=>a)
. Außerdem ist Ihr TIO-Link nicht mehr aktuell.RebindableSyntax , 25 Byte
Ich habe gerade den kürzlich veröffentlichten Leitfaden zu den Erweiterungen von GHC gelesen, als mir ein einfacher Leitfaden aufgefallen ist, den ich hier noch nicht gesehen habe.
-1
.1
.Benötigt
-XImplicitPrelude
auch oder alternativimport Prelude
im Code selbst.-XRebindableSyntax
ändert das Verhalten einiger syntaktischer Zucker von Haskell, um eine Neudefinition zu ermöglichen.-1
ist syntaktischer Zucker fürnegate 1
.negate
istPrelude.negate
, aber mit der Erweiterung ist es „je nachdem , wasnegate
an der Verwendungsstelle in ihrem Umfang ist“, die definiert ist alsid
.Prelude
Moduls verwendet werden soll, wird der normale implizite Import des Moduls automatisch deaktiviert, jedoch werden hier anderePrelude
Funktionen (wieprint
) benötigt, sodass es mit erneut aktiviert wird-XImplicitPrelude
.quelle
Streng, 52 Bytes
-XStrict
-XNoStrict
Mit
-XStrict
wird()
eine zusätzliche Zeit gedruckt .Vielen Dank an @Sriotchilism O'Zaic für zwei Bytes.
quelle
StrictData, 58 Bytes
(Links sind etwas veraltet; wird behoben.)
-XNoStrictData
-XStrictData
Benötigt
MagicHash
(GHC.Exts
statt importieren zu lassenUnsafe.Coerce
) und-O
(unbedingt erforderlich, um das Auspacken kleiner, strenger Felder zu ermöglichen).Mit
-XStrictData
wird 3 ausgegeben. Andernfalls wird der ganzzahlige Wert des (wahrscheinlich gekennzeichneten) Zeigers auf die vorab zugewiesene Kopie von gedruckt3::Integer
, die möglicherweise nicht 3 sein kann.Erläuterung
Es wird ein bisschen einfacher, mit einer kleinen Erweiterung zu verstehen, basierend auf dem Standardtyp. Mit Unterschriften können wir den Zusatz verwerfen.
Äquivalent dazu
Warum druckt es jemals 3? Das scheint überraschend! Nun, kleine
Integer
Werte werden sehr ähnlich wieInt
s dargestellt, die (mit strengen Daten) genau wieD
s dargestellt werden. Am Ende ignorieren wir das Tag, das angibt, ob die Ganzzahl klein oder groß positiv / negativ ist.Warum kann 3 nicht ohne die Erweiterung gedruckt werden? Abgesehen von Speicherlayoutgründen muss ein Datenzeiger mit niedrigen Bits (2 niedrigste für 32-Bit, 3 niedrigste für 64-Bit) von 3 einen Wert darstellen, der aus dem dritten Konstruktor erstellt wurde. In diesem Fall würde dies eine negative ganze Zahl erfordern .
quelle
UnboxedTuples, 52 Bytes
Benötigt
-XTemplateHaskell
. DruckeConE GHC.Prim.(##)
mit -XUnboxedTuples undUnboundVarE ##
mit -XNoUnboxedTuples .quelle
-XTemplateHaskell
?OverloadedLists, 76 Bytes
Mit -XOverloadedLists wird gedruckt
[()]
. Mit -XNoOverloadedLists wird gedruckt[]
Dies erfordert die zusätzliche Fahnen:
-XFlexibleInstances
,-XIncoherentInstances
quelle
HexFloatLiterals ,
4925 Bytes-24 Bytes dank Ørjan Johansen.
Druckt
0.0
mit-XHexFloatLiterals
und0
mit-XNoHexFloatLiterals
.Es gibt keine TIO-Links, da HexFloatLiterals in Ghc 8.4.1 hinzugefügt wurde, TIO jedoch Ghc 8.2.2.
quelle
main|(.)<-seq=print$0x0.0
vermeidet das Ausblenden des Imports.main|let _._=0=print$0x0.0
könnte jedoch für die Mehrsprachigkeit einfacher sein.ScopedTypeVariables, 37 Byte
Dies erfordert auch
UnicodeSyntax
,PartialTypeSignatures
,GADTs
, undExplicitForAll
.Probieren Sie es online (ohne Erweiterung)
Probieren Sie es online (mit Erweiterung)
Erläuterung
Die partiellen Typ-Signaturen dienen nur zum Speichern von Bytes. Wir können sie folgendermaßen ausfüllen:
Mit scoped Typ Variablen, die
a
von in der Art1
beschränkt ist , die zu seina
in der Art dermain
, der sich gezwungen ist , zu seinFloat
. Ohne Typvariablen mit Gültigkeitsbereich wird1
standardmäßig der Typ verwendetInteger
. DaFloat
undInteger
Werte unterschiedlich dargestellt werden, können wir sie unterscheiden.Vielen Dank an @ ØrjanJohansen für satte 19 Bytes! Er erkannte, dass es viel besser war, den Unterschied zwischen
Show
Instanzen verschiedener numerischer Typen auszunutzen, als Unterschiede in ihrer Arithmetik. Er erkannte auch, dass es in Ordnung war, den Typmain
"syntaktisch mehrdeutig" zu belassen, da die Einschränkung ihn tatsächlich eindeutig macht. Durch das Entfernen der lokalen Funktion konnte ich auch die Typensignatur für entfernenmain
(auf RHS verschieben), um fünf weitere Bytes zu sparen.quelle
DeriveAnyClass,
121113 BytesDanke an dfeuer für etliche Bytes!
-XDeriveAnyClass druckt,
1
wohingegen -XNoDeriveAnyClass drucktM 0
.Dies nutzt die Tatsache aus, dass DeriveAnyClass die Standardstrategie ist, wenn DeriveAnyClass und GeneralizedNewtypeDeriving aktiviert sind, wie Sie anhand der Warnungen sehen können. Dieses Flag generiert problemlos leere Implementierungen für alle Methoden, aber GeneralizedNewtypeDeriving ist tatsächlich intelligent genug, um die Implementierung des zugrunde liegenden Typs zu verwenden, und da dies
Int
einNum
Fehler ist , wird es in diesem Fall nicht fehlschlagen.Wenn für den Fall, dass das Flag aktiviert ist, nichts gedruckt wird, beträgt das Ersetzen
main
der folgenden Werte 109 Byte :quelle
runhaskell
, dies tatsächlich drucktM 1
mit-XDeriveAnyClass
, aus Faulheit ...1
:)PostfixOperators, 63 Bytes
Probieren Sie es online (ohne Erweiterung)
Probieren Sie es online (mit Erweiterung)
Dies ist eine gekürzte Version eines von mir geschriebenen Hugs / GHC-Polyglots . In diesem Beitrag finden Sie eine Erklärung. Dank @ ØrjanJohansen für die Realisierung, dass ich
id
anstelle eines benutzerdefinierten Operators vier Bytes einsparen konnte.quelle
id
kann anstelle von verwendet werden!
.DeriveAnyClass, 104 Byte
Probieren Sie es online (ohne Erweiterung)
Probieren Sie es online (mit Erweiterung)
Benötigt auch
GeneralizedNewtypeDeriving
.quelle
StrictData, 97 Bytes
Probieren Sie es online aus (keine strengen Daten)
Online testen (strenge Daten)
Benötigt auch
DeriveGeneric
.quelle
UnicodeSyntax, 33 Byte
Probieren Sie es online!
quelle
TemplateHaskell,
14091 BytesNur mit kleinen Modifikationen von Mauke kopiert . Ich weiß nicht, was los ist.
-49 Bytes dank Ørjan Johansen.
Probieren Sie es online!
quelle
$(...)
(kein Leerzeichen) ist die Syntax für die Vorlagenbewertung, wenn TH aktiviert ist, undTupE[]
("leeres Tupel") gibt()
. Die Verwendung vonShow
könnte für die Mehrsprachigkeit gut funktionieren, obwohl ich für diese besondere Herausforderung ein wenig schlecht darin bin, einen Wert als leere Zeichenfolge zu definieren ...MonomorphismRestriction,
3129 BytesBearbeiten:
-XMonomorphismRestriction druckt
0
. -XNoMonomorphismRestriction druckt18446744073709551616
.f
denselben Typ haben, sodass das Programm2^2^6 = 2^64
als 64-Bit-VersionInt
(auf 64-Bit-Plattformen) gedruckt wird , die überläuft0
.2^64
als Bignum gedrucktInteger
.quelle
f=(2^);main=print$f$f(64::Int)
würde ein Byte sparen. Aber es wird nicht realistisch enden64=2^6
spart das noch ein Byte.ScopedTypeVariables,
11997 BytesNur mit kleinen Modifikationen von Mauke kopiert .
Derzeit gibt es zwei weitere Antworten für ScopedTypeVariables: 113 Bytes von Csongor Kiss und 37 Bytes von dfeuer . Diese Übermittlung unterscheidet sich darin, dass keine anderen Haskell-Erweiterungen erforderlich sind.
-22 Bytes dank Ørjan Johansen.
Probieren Sie es online!
quelle
IO()/print
Trick im Polyglott nicht funktioniert).Num
. Ich denkeclass(Show a,Floating a)=>K a where{k::a->String;k=pure$ show(f pi)where f=id::a->a};
sollte funktionieren, das bequem nutzenFloat
und mit unterschiedlicher PräzisionDouble
anzeigenpi
.