Récemment, j'ai eu le plaisir d'écrire un programme Haskell capable de détecter si l' NegativeLiterals
extension était activée. Je suis venu avec ce qui suit:
data B=B{u::Integer}
instance Num B where{fromInteger=B;negate _=B 1}
main=print$1==u(-1)
Cela imprimera True
normalement et False
sinon.
Maintenant, je me suis tellement amusé à faire que je vous lance un défi à tous. Quelles autres extensions de langage Haskell pouvez-vous craquer?
Règles
Pour déchiffrer une extension de langue particulière, vous devez écrire un programme Haskell qui compile à la fois avec et sans extension de langue (les avertissements conviennent) et génère deux valeurs différentes sans erreur lorsqu’elle est exécutée avec l’extension de langue et désactivée (en ajoutant le No
préfixe à l'extension de langue). De cette façon, le code ci-dessus pourrait être réduit à seulement:
data B=B{u::Integer}
instance Num B where{fromInteger=B;negate _=B 1}
main=print$u(-1)
qui imprime 1
et -1
.
Toute méthode utilisée pour craquer une extension doit être spécifique à cette extension. Il peut exister des moyens de détecter arbitrairement quels indicateurs du compilateur ou LanguageExtensions sont activés, si de telles méthodes ne sont pas autorisées. Vous pouvez activer des extensions de langue supplémentaires ou modifier l'optimisation du compilateur en utilisant -O
gratuitement le nombre d'octets.
Extensions de langue
Vous ne pouvez pas casser toute extension de langage qui ne dispose pas d' une No
contrepartie (par exemple Haskell98
, Haskell2010
, Unsafe
, Trustworthy
, Safe
) car ceux - ci ne tombent pas dans les conditions décrites ci - dessus. Toute autre extension linguistique est un jeu équitable.
Notation
Vous recevrez un point pour chaque extension de langue que vous êtes la première personne à craquer et un point supplémentaire pour chaque extension de langue pour laquelle vous avez la fissure la plus courte (mesurée en octets). Pour le deuxième point, les liens seront brisés en faveur des soumissions précédentes. Plus le score est élevé, mieux c'est
Vous ne serez pas en mesure de marquer un point pour la première soumission NegativeLiterals
ou QuasiQuotes
parce que je les ai déjà craquées et les ai incluses dans le corps du message. Vous pourrez cependant marquer un point pour la fissure la plus courte de chacune d’elles. Voici ma fente deQuasiQuotes
import Text.Heredoc
main=print[here|here<-""] -- |]
la source
NondecreasingIndentation
pour des raisons évidentesWait, what language extension is this?
ou quelque chose de complètement différent.RelaxedPolyRec
, pour un compilateur assez ancien pour réellement soutenir le mettre hors tension. (L'option a traîné, avec documentation, pendant quelques années après avoir cessé de faire quoi que ce soit.)Réponses:
MagicHash, 30 octets
-XMagicHash sorties 1, -XNoMagicHash sorties 2
MagicHash permet aux noms de variables de se terminer par a
#
. Donc avec l'extension, cela définit deux fonctionsy#
etx#
qui prennent chacune une valeur et retournent une constante2
, ou1
.x#x
retournera 1 (car il estx#
appliqué à1
)Sans l'extension, cela définit une fonction
#
qui prend deux arguments et retourne2
. Lex#a=1
est un modèle qui n'est jamais atteint. Alorsx#x
est1#1
, qui retourne 2.la source
MagicHash
les hachages ne soient pas perdus. Bizarre!CPP,
33 à20 octetsImprime
0
avec-XCPP
et1
avec-XNoCPP
.Avec
-XCPP
, une barre oblique\
avant une nouvelle ligne supprime la nouvelle ligne, ainsi le code devientmain=print$0-- +1
et0
est uniquement imprimé, car il+1
fait maintenant partie du commentaire.Sans l'indicateur, le commentaire est ignoré et la deuxième ligne est analysée comme faisant partie de la ligne précédente car elle est en retrait.
Approche précédente avec
#define
Imprime aussi
0
avec-XCPP
et1
avec-XNoCPP
.la source
NumDecimals, 14 octets
-XNumDecimals imprime
10
. -XNoNumDecimals imprime10.0
.la source
BinaryLiterals, 57 bytes
-XBinaryLiterals imprime une nouvelle ligne. -XNoBinaryLiterals imprime a
1
.Je suis sûr qu'il existe un meilleur moyen de le faire. Si vous en trouvez un, merci de le poster.
la source
b
tant que fonction (aucun binaire ne devientb(0, 1)
, mais binaire devient0b1
)?MonomorphismRestriction + 7 others, 107 bytes
Cela utilise TH qui nécessite le drapeau
-XTemplateHaskell
à tout moment.Fichier T.hs, 81 + 4 octets
Main, 22 octets
La compilation avec l'indicateur MonomorphismRestriction force le type de
p
toInteger -> Integer -> Integer
et produit ainsi le résultat suivant:Compiler avec le drapeau NoMonomorphismRestriction laisse le type
p
au plus général, c'est-à-dire.Num a => a->a->a
- produire quelque chose comme (abrégé lesVarT
nomsa
):Essayez-les en ligne!
Des alternatives
Puisque le code ci-dessus affiche simplement le type de
p
, cela peut être fait avec tous les indicateurs qui influencent d'une manière ou d'une autre la façon dont Haskell déduit les types. Je ne spécifierai que le drapeau et avec quoi remplacer la fonctionp
et si nécessaire des drapeaux supplémentaires (à part-XTemplateHaskell
):OverloadedLists, 106 octets
De plus, il faut
-XNoMonomorphismRestriction
:Ou
p :: [a]
bienp :: IsList l => l
, essayez-les en ligne!OverloadedStrings, 106 octets
De plus, il faut
-XNoMonomorphismRestriction
:Ou
p :: String
bienp :: IsString s => s
, essayez-les en ligne!PolyKinds, 112 octets
Ceci est entièrement dû à @CongorKiss:
Ou
P :: P a
bienP :: forall k (a :: k). P a
, essayez-les en ligne!MonadComprehensions, 114 octets
Ou
p :: [a] -> [a]
bienp :: Monad m => m a -> m a
, essayez-les en ligne!NamedWildCards, 114 octets
Celui-ci a été trouvé par @Laikoni, il nécessite en plus
-XPartialTypeSignatures
:Ils ont tous les deux le type de sauvegarde (
p :: a -> a
) mais GHC génère des noms différents pour les variables, essayez-les en ligne!ApplicativeDo, 120 octets
Ou
p :: Monad m => m a -> m a
bienp :: Functor f => f a -> f a
, essayez-les en ligne!OverloadedLabels, 120 octets
Cela nécessite le drapeau supplémentaire
-XFlexibleContexts
:Soit comme
p :: a -> b -> b
oup :: IsLabel "id" (a->b) => a -> b
, essayez-les en ligne!la source
OverloadedStrings
ouOverloadedLists
sûr et probablement d' autres aussi ..PolyKinds
: Essayez-le en ligne!NamedWildCards
: essayez-le en ligne! (Requis-XPartialTypeSignatures
)CPP,
2725Essayez-le en ligne!
Gravures
()
pour-XCPP
et1
pour-XNoCPP
La version précédente:
Essayez-le en ligne!
Imprime
[1]
avec-XCPP
et[1,2]
autrement.Crédits: Ceci est inspiré de la réponse de Laikoni, mais au lieu de
#define
cela, il utilise simplement des commentaires C.la source
ScopedTypeVariables,
162113 octets-XScopedTypeVariables imprime
""
(vide), -XNoScopedTypeVariables imprime"[()]"
.Edit: solution mise à jour grâce aux suggestions utiles dans les commentaires
la source
"T"
peut simplement être remplacé par""
.T
de données par()
. Pour éviter d'avoir à le définir. Essayez-le en ligne!show
peut être modifié pour impressionforall
fera économiser quelques octets. Je doute que toute solution nécessitant des instances supplémentaires ait beaucoup d’espoir de gagner.MonoLocalBinds, GADT ou TypeFamilies,
3632 octetsMODIFIER:
(1.0,1)
.Avec l'un des indicateurs -XMonoLocalBinds , -XGADTs ou -XTypeFamilies , il s'imprime
(1.0,1.0)
.L'
MonoLocalBinds
extension existe pour empêcher toute inférence de type non intuitive déclenchée par les GADT et les familles de types. En tant que telle, cette extension est automatiquement activée par les deux autres.-XNoMonoLocalBinds
, cette astuce suppose que vous ne le faites pas.Comme son cousin plus connu, la restriction de monomorphisme,
MonoLocalBinds
empêche certaines valeurs (dans les liaisons locales telles quesemble aussi arriver au plus haut niveau) d’être polymorphes. Bien qu’elles aient été créées pour des inférences de type plus sain, les règles régissant les déclencheurs sont, si possible, encore plus difficiles que le MR.let
ouwhere
, ainsi le nomSans aucune extension, le programme ci-dessus déduit le type
f :: Num a => a -> a
, permettantf pi
de définir par défaut unDouble
etf 0
unInteger
.f :: Double -> Double
etf 0
doit lui aussi être renvoyéDouble
.a=0
est nécessaire pour déclencher les règles techniques:a
est frappée par la restriction de monomorphisme eta
est une variable libre def
, ce qui signifie quef
le groupe de liaisons de ce dernier n'est pas complètement généralisé , ce qui signifie qu'ilf
n'est pas fermé et ne devient donc pas polymorphe.la source
OverloadedStrings,
654832 octetsTirant parti de RebindableSyntax, utilisez notre propre version de fromString pour transformer tout littéral de chaîne en
"y"
.Doit être compilé avec
-XRebindableSyntax -XImplicitPrelude
.Sans
-XOverloadedStrings
impressions""
; avec des impressions"y"
.En outre, je viens tout juste de penser que la même technique fonctionne avec (par exemple) OverloadedLists:
OverloadedLists, 27 octets
Doit être compilé avec
-XRebindableSyntax -XImplicitPrelude
.Sans
-XOverloadedLists
impressions[0]
; avec des impressions[1,0]
.la source
fromString a=['y']
.print "n"
peut également être supprimé.="y"
, mais ça=['y']
fonctionne bien!n
deprint"n"
-XImplicitPrelude
aprèsRebindableSyntax
pour éviter la ligne d'importation.BangPatterns, 32 octets
-XBangPatterns imprime
1
alors que -XNoBangPatterns imprimera0
.Cela permet d’utiliser le drapeau que BangPatterns permet d’annoter des modèles avec
!
pour forcer l’évaluation au format WHNF, auquel cas9!1
on utilisera la définition de niveau supérieur(!)=seq
. Si l'indicateur n'est pas activé,f!_
définit un nouvel opérateur(!)
et masque la définition de niveau supérieur.la source
ApplicativeDo, 104 octets
Essayez-le en ligne!
Avec
ApplicativeDo
, cela imprimeSans cela, ça imprime
ZipList
est l'un des rares types dans les bibliothèques de base avec une instance pourApplicative
mais pas pourMonad
. Il peut y avoir des alternatives plus courtes qui se cachent quelque part.la source
Strict,
87 8482 octets-5 octets grâce à dfeuer !
Pourrait être moins de
BlockArguments
sauver les parents autour\_->print 1
:Exécuter ceci avec -XStrict imprime une impression
1
alors que le faire avec -XNoStrict imprimera une0
. Cela utilise par défaut que Haskell est fainéant et qu'il n'est pas nécessaire de l'évaluererror""
puisqu'il sait déjà que le résultat sera le même0
lorsque le premier argument correspond(!)
, ce comportement peut être modifié avec cet indicateur - forçant le moteur d'exécution à évaluer les deux arguments.Si rien n'est autorisé dans un cas, nous pouvons le réduire à 75 octets en remplaçant le texte principal par (certains octets sont également désactivés par dfeuer ):
StrictData,
106 9993 octets-15 octets grâce à dfeuer !
Ceci fait fondamentalement la même chose mais fonctionne avec des champs de données:
Imprime
1
avec l' indicateur -XStrictData et0
avec -XNoStrictData .Si rien n'est autorisé dans un cas, nous pouvons le réduire à 86 octets en remplaçant le principal par (19 octets désactivés par dfeuer ):
Remarque: Toutes les solutions nécessitent un
TypeApplications
ensemble.la source
pure()
.D{}
truc est plutôt cool! Rasés les uns des autres par utiliser auPartialTypeSignatures
lieu deScopedTypeVariables
:)-XBlockArguments
:main=catch @ErrorCall(p$seq(D$error"")1)\_->p 3
ApplicativeDo, 146 octets
Imprime 1 lorsque ApplicativeDo est activé, 0 sinon
Essayez-le en ligne!
la source
Applicative
etShow
sauvegarder en utilisant la syntaxe d’enregistrement, voyez ceci .BinaryLiterals,
31 à24 octetsModifier:
b12
variable.Un ajustement à la méthode de H.PWiz , évitant l'instance de la fonction.
0b12
lexes as0
b12
, impression 0 + 1 =1
.0b12
lexes as0b1
2
, impression 1 + 2 =3
.la source
ExtendedDefaultRules,
5453 octetsImprime
()
avec-XExtendedDefaultRules
et0
avec-XNoExtendedDefaultRules
.Cet indicateur est activé par défaut dans GHCi, mais pas dans GHC, ce qui m'a récemment causé une certaine confusion , même si BMO a rapidement été en mesure de vous aider.
Le code ci-dessus est une version par défaut d'un exemple du Guide de l'utilisateur GHC où le type par défaut dans GHCi est expliqué.
-1 octet grâce à Ørjan Johansen !
la source
toEnum 0::Num a=>Enum a=>a
.PartialTypeSignatures
:main=print(toEnum 0::_=>Num a=>a)
. De plus, votre lien TIO est obsolète.RebindableSyntax , 25 octets
Je lisais le Guide des extensions de GHC, récemment publié , lorsque j'ai remarqué un guide facile que je ne me souvenais pas avoir vu ici.
-1
.1
.Nécessite également
-XImplicitPrelude
, ou bienimport Prelude
dans le code lui-même.-XRebindableSyntax
modifie le comportement de certains sucres syntaxiques de Haskell pour permettre de le redéfinir.-1
est le sucre syntaxique pournegate 1
.negate
c’estPrelude.negate
, mais avec l’extension, c’est "quelle quenegate
soit la portée au moment de l’utilisation", qui est définie parid
.Prelude
module, elle désactive automatiquement l'importation implicite habituelle de cette dernière, mais d'autresPrelude
fonctions (commeprint
) sont nécessaires ici, elle est donc réactivée-XImplicitPrelude
.la source
Strict, 52 octets
-XStrict
-XNoStrict
Avec
-XStrict
, imprime()
un temps supplémentaire.Merci à @Sriotchilism O'Zaic pour deux octets.
la source
StrictData, 58 octets
(Les liens sont un peu dépassés; ça va s'arranger.)
-XNoStrictData
-XStrictData
Requiert
MagicHash
(pour nous permettre d'importerGHC.Exts
au lieu deUnsafe.Coerce
) et-O
(absolument nécessaire, pour permettre le décompactage de petits champs stricts).With
-XStrictData
, imprime 3. Sinon, imprime la valeur entière du pointeur (probablement marqué) sur la copie pré-allouée de3::Integer
, qui ne peut éventuellement pas être 3.Explication
Ce sera un peu plus facile à comprendre avec un peu d’extension, basé sur le type default. Avec les signatures, nous pouvons supprimer l’ajout.
De manière équivalente,
Pourquoi imprime-t-on 3? Cela semble surprenant! Eh bien, les petites
Integer
valeurs sont représentées beaucoup commeInt
s, qui (avec des données strictes) sont représentées exactement commeD
s. Nous finissons par ignorer la balise indiquant si le nombre entier est petit ou grand positif / négatif.Pourquoi ne peut-il pas imprimer 3 sans l'extension? Mis à part les raisons d’agencement de la mémoire, un pointeur de données avec des bits faibles (2 inférieurs pour 32 bits, 3 inférieurs pour 64 bits) de 3 doit représenter une valeur générée à partir du troisième constructeur. Dans ce cas, cela nécessiterait un entier négatif .
la source
UnboxedTuples, 52 octets
Nécessite
-XTemplateHaskell
. ImprimeConE GHC.Prim.(##)
avec -XUnboxedTuples etUnboundVarE ##
avec -XNoUnboxedTuples .la source
-XTemplateHaskell
?OverloadedLists, 76 bytes
Avec -XOverloadedLists, il s'imprime
[()]
. Avec -XNoOverloadedLists, il imprime[]
Cela nécessite des drapeaux supplémentaires:
-XFlexibleInstances
,-XIncoherentInstances
la source
HexFloatLiterals ,
4925 octets-24 octets grâce à Ørjan Johansen.
Imprime
0.0
avec-XHexFloatLiterals
et0
avec-XNoHexFloatLiterals
.Il n'y a pas de liens TIO car HexFloatLiterals a été ajouté dans ghc 8.4.1, mais TIO contient ghc 8.2.2.
la source
main|(.)<-seq=print$0x0.0
évite la dissimulation d'importation.main|let _._=0=print$0x0.0
pourrait être plus facile pour le polyglotte cependant.ScopedTypeVariables, 37 octets
Cela nécessite également
UnicodeSyntax
,PartialTypeSignatures
,GADTs
etExplicitForAll
.Essayez-le en ligne (sans extension)
Essayez-le en ligne (avec extension)
Explication
Les signatures de type partiel servent uniquement à sauvegarder des octets. Nous pouvons les remplir comme suit:
Avec les variables de type scoped, le
a
dans le type de1
est contraint à êtrea
dans le type demain
, ce qui est lui-même contraint à êtreFloat
. Sans variables de type ciblées, le type par1
défautInteger
. PuisqueFloat
et lesInteger
valeurs sont affichées différemment, nous pouvons les distinguer.Merci à @ ØrjanJohansen pour ses 19 octets! Il s'est rendu compte qu'il était bien préférable de tirer parti de la différence entre des
Show
instances de types numériques différents que des différences d'arithmétique. Il s'est également rendu compte qu'il était normal de laisser le type d 'main
"ambiguïté syntaxique" car la contrainte la désambiguise. Le fait de me débarrasser de la fonction locale m'a également libéré pour supprimer la signature de typemain
( pour la déplacer vers le RHS) et économiser cinq octets supplémentaires.la source
DeriveAnyClass,
121113 octetsMerci à dfeuer pour quelques octets!
-XDeriveAnyClass imprime
1
alors que -XNoDeriveAnyClass imprimeM 0
.Ceci exploite le fait que DeriveAnyClass est la stratégie par défaut lorsque DeriveAnyClass et GeneralizedNewtypeDeriving sont activées, comme vous pouvez le constater dans les avertissements. Ce drapeau se fera un plaisir de générer des implémentations vides pour toutes les méthodes , mais GeneralizedNewtypeDeriving est en fait assez intelligent pour utiliser la mise en œuvre du type sous - jacent et depuis
Int
est un ,Num
il ne manquera pas dans ce cas.Si vous n'imprimez rien si l'indicateur est activé, le remplacement
main
par le suivant serait de 109 octets :la source
runhaskell
, cela imprime effectivementM 1
avec-XDeriveAnyClass
, à cause de la paresse ...1
:)PostfixOperators, 63 octets
Essayez-le en ligne (sans extension)
Essayez-le en ligne (avec extension)
Ceci est une version réduite d' un polyglotte Hugs / GHC que j'ai écrit . Voir ce post pour une explication. Merci à @ ØrjanJohansen d’avoir réalisé que j’aurais pu utiliser
id
un opérateur personnalisé, économisant quatre octets.la source
id
peut être utilisé à la place de!
.DeriveAnyClass, 104 octets
Essayez-le en ligne (sans extension)
Essayez-le en ligne (avec extension)
Nécessite également
GeneralizedNewtypeDeriving
.la source
StrictData, 97 octets
Essayez-le en ligne (pas de données strictes)
Essayez-le en ligne (données strictes)
Nécessite également
DeriveGeneric
.la source
UnicodeSyntax, 33 octets
Essayez-le en ligne!
la source
TemplateHaskell,
14091 octetsVient de copier mauke avec de petites modifications. Je ne sais pas ce qui se passe.
-49 octets grâce à Ørjan Johansen.
Essayez-le en ligne!
la source
$(...)
(pas d'espace) est la syntaxe d'évaluation du modèle lorsque TH est activé, etTupE[]
("tuple vide") donne()
. UtiliserShow
pourrait bien fonctionner pour les polyglottes, bien que pour ce défi particulier, je me sens un peu mal de définir une valeur à imprimer comme une chaîne vide ...MonomorphismRestriction,
3129 bytesModifier:
-XMonomorphismRestriction imprime
0
. -XNoMonomorphismRestriction imprime18446744073709551616
.f
sont forcées d'être du même type, de sorte que le programme s'imprime en2^2^6 = 2^64
tant que 64 bitsInt
(sur des plates-formes 64 bits), ce qui déborde0
.2^64
en bignumInteger
.la source
f=(2^);main=print$f$f(64::Int)
économiser un octet. Mais cela ne se terminera pas de manière réaliste64=2^6
, ce qui sauve encore un autre octet.ScopedTypeVariables,
11997 octetsVient de copier mauke avec de petites modifications.
Il existe actuellement deux autres réponses pour ScopedTypeVariables: 113 octets par Csongor Kiss et 37 octets par dfeuer . Cette soumission est différente en ce sens qu'elle ne nécessite pas d'autres extensions Haskell.
-22 octets grâce à Ørjan Johansen.
Essayez-le en ligne!
la source
IO()/print
astuce ne marche pas dans le polyglotte).Num
. Je pense queclass(Show a,Floating a)=>K a where{k::a->String;k=pure$ show(f pi)where f=id::a->a};
devrait fonctionner, en utilisant commodément celaFloat
etDouble
afficherpi
avec une précision différente.