Подождите, что это за язык?

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 поддерживает его отключение.
Орджан Йохансен

Ответы:

24

MagicHash, 30 байт

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

-XMagicHash выводит 1, -XNoMagicHash выводит 2

MagicHash позволяет именам переменных заканчиваться на #. Поэтому с расширением, это определяет две функции , y#и x#которой каждый принимать значение и возвращает константу 2, или 1. x#xвернет 1 (потому что он x#применяется к 1)

Без расширения это определяет одну функцию, #которая принимает два аргумента и возвращает 2. Это x#a=1шаблон, который никогда не будет достигнут. Тогда x#xесть 1#1, который возвращает 2.

H.PWiz
источник
2
Сейчас я пою X Magic Hash под мелодию Dance Magic Dance . Я надеюсь, что вы гордитесь!
ТРИГ
Я удивлен, что MagicHashне допускает непереключающиеся хэши. Weird!
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.

Laikoni
источник
2
О боже, до сих пор я думал, что GHC будет отбрасывать комментарии на Haskell, прежде чем перейти к CPP.
Куб
@Cubic Разве это не до -Процессора?
Берги
1
@Bergi Конечно, но предварительно -processors не обязательно означает , что «это первая вещь , которая работает», тем более , что GHC должен сделать проход над файлом первой даже найти прагму. Я предполагаю, что комментарии хранятся в комментариях к документам и тому подобной работе после CPP.
Куб
14

BinaryLiterals, 57 байт

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

-XBinaryLiterals печатает одну новую строку . -XNoBinaryLiterals печатает 1.

Я уверен, что есть лучший способ сделать это. Если вы найдете один, пожалуйста, опубликуйте его.

H.PWiz
источник
Разве вы не можете просто определить 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

Main, 22 байта

import T
main=print $t

Компиляция с флагом MonomorphismRestriction заставляет тип pto 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, попробовать их в Интернете!

OverloadedStrings, 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, попробовать их в Интернете!

MonadComprehensions, 114 байтов

p x=[i|i<-x]

Либо p :: [a] -> [a]или p :: Monad m => m a -> m a, попробовать их в Интернете!

NamedWildCards, 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: Попробуйте онлайн!
Цонгор Кисс
1
Также, кажется, работает с NamedWildCards: Попробуйте онлайн! (Требуется -XPartialTypeSignatures)
Лайкони
10

CPP, 27 25

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

Попробуйте онлайн!

Принты ()для -XCPPи 1для-XNoCPP

Предыдущая версия:

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

Попробуйте онлайн!

Печать [1]с -XCPPи в [1,2]противном случае.

Кредиты: Это вдохновлено ответом Лайкони, но вместо него #defineон просто использует комментарии С.

celtschk
источник
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
Хороший улов, я только что понял, что бессвязная прагма может быть включена как флаг: попробуйте это онлайн!
Цонгор Кисс
2
Дополнительно show можно изменить для печати
H.PWiz
Синтаксис Unicode для forallсэкономит вам несколько байтов. Я сомневаюсь, что у любого решения, которое нуждается в дополнительных инстанциях, есть большая надежда на победу.
dfeuer
9

MonoLocalBinds, GADT или TypeFamilies, 36 32 байта

РЕДАКТИРОВАТЬ:

  • -4 байта: версия этого была включена в большую цепочку полиглотов стасоидом, который удивил меня, поместив все объявления на верхний уровень. Видимо, запуск этого ограничения не требует фактических локальных привязок.
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 полиморфность , таким образом, название, по- видимому, также может происходить на верхнем уровне). Несмотря на то, что они созданы для логического вывода, правила, когда это срабатывает , по возможности, даже более пугающие, чем MR.

  • Без какого-либо расширения, вышеуказанная программа выводит тип f :: Num a => a -> a, позволяяf pi по умолчанию a Doubleи f 0a 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".

Кроме того, только сейчас меня поразило, что та же самая техника работает с (например) OverloadedLists:

Перегруженные списки, 27 байт

main=print[0]
fromListN=(:)

Должен быть скомпилирован с-XRebindableSyntax -XImplicitPrelude .

Без -XOverloadedListsотпечатков [0]; с принтами [1,0].

felixphew
источник
1
Вы можете сократить последнюю строку до fromString a=['y'].
Эрджан Йохансен
Пространство в print "n"также может быть отброшено.
Лайкони
@ ØrjanJohansen спасибо! Я терпел неудачу ="y", но =['y']работает отлично!
Феликсфью
1
Вы можете удалить второй nизprint"n"
Мастер Пшеницы
1
Вы также можете использовать -XImplicitPreludeпосле, RebindableSyntaxчтобы избежать строки импорта.
dfeuer
8

BangPatterns, 32 байта

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

-XBangPatterns печатает, 1тогда как -XNoBangPatterns печатает0 .

Это использует то, что флаг BangPatterns позволяет аннотировать шаблоны с помощью !принудительной оценки в WHNF, в этом случае 9!1будет использоваться определение верхнего уровня (!)=seq. Если флаг не активирован, f!_определяет новый оператор (!)и скрывает определение верхнего уровня.

ბიმო
источник
7

ApplicativeDo, 104 байта

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

Попробуйте онлайн!

С ApplicativeDoэтим печатает

ZipList {getZipList = [1]}

Без него печатает

ZipList {getZipList = []}

ZipListявляется одним из немногих типов в базовых библиотеках с экземпляром для, Applicativeно не для Monad. Возможно, где-то есть более короткие альтернативы.

Zgarb
источник
7

Строгий, 87 84 82 байта

-5 байт благодаря dfeuer !

Может быть меньше с BlockArgumentsсохранением паренов вокруг \_->print 1:

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

Выполнение этого с -XStrict печатает a, 1тогда как выполнение этого с -XNoStrict будет печатать a 0. При этом используется то, что Haskell по умолчанию является ленивым и не нуждается в оценке, error""так как он уже знает, что результат будет, 0когда он соответствует первому аргументу(!) этого результата это поведение можно изменить с помощью этого флага, что заставит среду выполнения оценить оба аргумента.

Если в одном случае разрешено ничего не печатать, мы можем уменьшить его до 75 байт, заменив основной на (также некоторые байты отключены dfeuer ):

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

StrictData, 106 99 93 байта

-15 байт благодаря dfeuer !

Это в основном то же самое, но вместо этого работает с полями данных:

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

Печать 1с флагом -XStrictData и 0с -XNoStrictData .

Если в одном случае разрешено печатать ничего, мы можем уменьшить его до 86 байт, заменив основной на (19 байтов выключено dfeuer ):

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

Примечание: все решения требуют TypeApplicationsустановки.

ბიმო
источник
Вы можете довольно легко сократить это до 98 байт, что в точности соответствует моему (совсем другому) решению. TIO .
dfeuer
На самом деле, вы можете сделать еще лучше: вместо печати в обработчике исключений просто используйте pure().
dfeuer
1
@dfeuer: Хорошо, D{}трюк довольно крутой! Побрил еще один, используя PartialTypeSignaturesвместо ScopedTypeVariables:)
მოიმო
1
@dfeuer: я посмотрел и попробовал несколько вещей, но я никогда не использовал Дженерики, поэтому я, вероятно, не тот человек.
მოიმო
1
Вы можете добиться еще большего успеха с GHC и -XBlockArguments:main=catch @ErrorCall(p$seq(D$error"")1)\_->p 3
dfeuer
6

ApplicativeDo, 146 байт

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}

Печатает 1, когда ApplicativeDo включен, 0 в противном случае

Попробуйте онлайн!

oisdk
источник
1
Благодарность! Ах, я думаю, что я использую старую версию GHC (в моей системе было предупреждение «без аппликатива»)
oisdk
3
Используя -XDeriveAnyClass вы можете получить Applicativeи Showсохранить используя синтаксис записи, смотрите это .
მოიმო
6

BinaryLiterals, 31 24 байта

Редактировать:

  • -7 байт: H.PWiz предложил откорректировать его, используя один b12 переменную.

Корректировка метода H.PWiz , избегая экземпляра функции.

b12=1
main=print$(+)0b12
Орджан Йохансен
источник
6

ExtendedDefaultRules, 54 53 байта

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

Печать ()с -XExtendedDefaultRulesи 0с -XNoExtendedDefaultRules.

Этот флаг включен по умолчанию в GHCi, но не в GHC, что недавно вызвало у меня некоторую путаницу , хотя BMO быстро помогло.

Приведенный выше код является версией для гольфа, приведенной в примере в Руководстве пользователя GHC, где поясняется тип по умолчанию в GHCi .

-1 байт благодаря Эрджану Йохансену !

Laikoni
источник
Глядя на этот код, заимствованный в полиглот (где круглые скобки доставляют некоторые проблемы), я вспомнил, что GHC поддерживает более короткий байтовый синтаксис toEnum 0::Num a=>Enum a=>a.
Орджан Йохансен
Вы можете получить его до 48 байт с PartialTypeSignatures: main=print(toEnum 0::_=>Num a=>a). Кроме того, ваша ссылка TIO устарела.
dfeuer
6

RebindableSyntax , 25 байтов

Я читал недавно опубликованное « Руководство по расширениям GHC», когда заметил простое, которое я еще не помню, видя здесь.

main|negate<-id=print$ -1

Также требуется -XImplicitPreludeили, альтернативно, import Preludeв самом коде.

  • -XRebindableSyntax изменяет поведение некоторого синтаксического сахара в Haskell, чтобы сделать возможным его переопределение.
  • -1 является синтаксическим сахаром для negate 1 .
  • Как правило , это negateявляется Prelude.negate, но с расширением его « в зависимости от тогоnegate находится в области видимости в точке использования», который определяется как id.
  • Поскольку расширение предназначено для использования для замены Preludeмодуля, оно автоматически отключает обычный неявный импорт этого, но здесь необходимы другие Preludeфункции (например print), поэтому его снова включают с -XImplicitPrelude.
Орджан Йохансен
источник
6

Строгий, 52 байта

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

-XStrict

-XNoStrict

С -XStrict, печатает ()дополнительное время.

Спасибо @Sriotchilism О'Зайку за два байта.

dfeuer
источник
6

StrictData, 58 байт

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

(Ссылки немного устарели; исправят.)

-XNoStrictData

-XStrictData

Требуется MagicHash(чтобы мы могли импортировать GHC.ExtsвместоUnsafe.Coerce ) и -O(абсолютно необходимо, чтобы разрешить распаковку небольших строгих полей).

С -XStrictData , печатает 3. В противном случае печатает целочисленное значение (возможно, с тегами) указателя на предварительно выделенную копию 3::Integer, которая не может быть 3.

объяснение

Это будет немного легче понять с небольшим расширением, основанным на типе по умолчанию. С помощью подписей мы можем отказаться от сложения.

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

Эквивалентное

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

Почему он печатает 3? Это кажется удивительным! Ну, маленькие Integerзначения представлены очень похоже на Ints, которые (со строгими данными) представлены так же, как Ds. В итоге мы игнорируем тег, указывающий, является ли целое число маленьким или большим положительным / отрицательным.

Почему он не может напечатать 3 без расширения? Оставляя в стороне любые причины размещения памяти, указатель данных с младшими битами (2 младших для 32-битных, 3 младших для 64-битных), равный 3, должен представлять значение, построенное из третьего конструктора. В этом случае для этого потребуется отрицательное целое число.

dfeuer
источник
5

UnboxedTuples, 52 байта

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

Требуется -XTemplateHaskell. Печатается ConE GHC.Prim.(##)с -XUnboxedTuples и UnboundVarE ##с -XNoUnboxedTuples .

Laikoni
источник
Разве не должно быть еще +16 в счете для требуемой опции -XTemplateHaskell?
celtschk
2
@celtschk Я не считал это, потому что текущий мета-консенсус относительно флагов командной строки говорит, что они не учитываются, а вместо этого составляют новый язык. Хотя, подумав об этом, я вижу, что в контексте этой задачи, которая позволяет только ответы на Haskell, но также и использование других флагов, не совсем понятно, что делать. Я спрошу у ОП об этом.
Лайкони
Я не знал, что консенсус по этому вопросу изменился. Спасибо за указатель. Запрашивать ОП - это хорошая идея.
celtschk
5

Перегруженные списки, 76 байт

import GHC.Exts
instance IsList[()]where fromList=(():)
main=print([]::[()])

С -XOverloadedLists это печатает [()]. С -XNoOverloadedLists печатает[]

Это требует дополнительных флагов: -XFlexibleInstances,-XIncoherentInstances

H.PWiz
источник
Вы можете сойти с перекрывающихся экземпляров.
dfeuer
5

HexFloatLiterals , 49 25 байт

-24 байта благодаря Орджану Йохансену.

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

Печать 0.0с -XHexFloatLiteralsи 0с -XNoHexFloatLiterals.

Нет ссылок на TIO, потому что HexFloatLiterals был добавлен в ghc 8.4.1, но TIO имеет ghc 8.2.2.

stasoid
источник
main|(.)<-seq=print$0x0.0избегает сокрытия импорта
Орджан Йохансен
main|let _._=0=print$0x0.0может быть проще для полиглота, хотя.
Орджан Йохансен
5

ScopedTypeVariables, 37 байт

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

Это также требует UnicodeSyntax, PartialTypeSignatures,GADTs и ExplicitForAll.

Попробуйте онлайн (без расширения)

Попробуйте онлайн (с расширением)

объяснение

Частичные подписи типа предназначены только для сохранения байтов. Мы можем заполнить их так:

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

С переменными типа scoped тип ain 1должен быть aтипом in main, который сам должен быть Float. Без переменных типа с областью видимости по 1умолчанию Integer. Так как Floatи Integerзначения отображаются по-разному, мы можем их различать.

Спасибо @ ÖrjanJohansen за колоссальные 19 байтов! Он понял, что гораздо лучше использовать разницу между Showэкземплярами разных числовых типов, чем различия в их арифметике. Он также понял, что было бы нормально оставить тип main«синтаксически неоднозначным», потому что ограничение фактически устраняет его. Избавление от локальной функции также освободило меня от удаления сигнатуры типа для main(смещения ее в RHS), чтобы сохранить еще пять байтов.

dfeuer
источник
45 байтов
Орджан Йохансен
@ ØrjanJohansen, хорошо .
dfeuer
@ ØrjanJohansen, я должен сделать редактирование, или ты предпочитаешь добавить свое собственное?
dfeuer
Отредактируйте, это было постепенное развитие от вашего.
Орджан Йохансен
@ ØrjanJohansen, спасибо, это было прекрасно.
dfeuer
5

DeriveAnyClass, 121 113 байт

Спасибо dfeuer за довольно много байтов!

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

-XDeriveAnyClass печатает, 1тогда как -XNoDeriveAnyClass печатаетM 0 .

Это использует тот факт, что DeriveAnyClass является стратегией по умолчанию, когда включены и DeriveAnyClass, и GeneralizedNewtypeDeriving, как вы можете видеть из предупреждений. Этот флаг будет счастливо генерировать пустые реализации для всех методов , но GeneralizedNewtypeDeriving на самом деле достаточно умен , чтобы использовать реализацию базового типа и с тех пор Intявляется Numего не подведет и в этом случае.


Если ничего не печатать в случае, если флаг включен, замена mainна следующее будет 109 байтов :

main=print(0::M)`catch`(mempty::SomeException->_)
ბიმო
источник
По крайней мере , runhaskellэто фактически печатает M 1с -XDeriveAnyClass, из - за лени ...
перестала очередь counterclockwis
@ceasedtoturncounterclockwis: Да, и в GHCi, но при компиляции на TIO (и на моей машине) и последующем запуске это приводит к 1:)
მოიმო
113 байт
dfeuer
109 байт
dfeuer
1
Я понизил его до 104 совершенно другим способом, поэтому я добавил свой ответ.
dfeuer
4

PostfixOperators, 63 байта

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

Попробуйте онлайн (без расширения)

Попробуйте онлайн (с расширением)

Это урезанная версия полиглота Hugs / GHC, которую я написал . Смотрите этот пост для объяснения. Спасибо @ ÖrjanJohansen за понимание, что я мог использовать idвместо пользовательского оператора, сохраняя четыре байта.

dfeuer
источник
idможно использовать вместо !.
Орджан Йохансен
@ ØrjanJohansen, да, действительно! Это экономит четыре крутых байта.
dfeuer
3

TemplateHaskell, 140 91 байт

Просто скопировал с mauke с небольшими изменениями. Я не знаю, что происходит.

-49 байтов благодаря Орджану Йохансену.

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

Попробуйте онлайн!

stasoid
источник
$(...)(без пробела) синтаксис оценки шаблона, когда TH включен, и TupE[]("пустой кортеж") дает (). ИспользованиеShow может хорошо сработать для полиглота, хотя для этой конкретной задачи мне не очень удобно определять значение для печати в виде пустой строки ...
Орджан Йохансен
2

MonomorphismRestriction, 31 29 байт

Редактировать:

  • -2 байта с улучшением от H.PWiz
f=(2^)
main=print$f$f(6::Int)

-XMonomorphismRestriction печатает 0. -XNoMonomorphismRestriction печатает18446744073709551616 .

  • С ограничением, оба использования fпринудительно должны быть одного типа, поэтому программа печатает 2^2^6 = 2^64как 64-битныйInt (на 64-битных платформах), которая переполняется до0 .
  • Без ограничений программа печатает 2^64как бигнум Integer.
Орджан Йохансен
источник
1
Я думаю f=(2^);main=print$f$f(64::Int)спас бы байт. Но это не будет реально прекратить
H.PWiz
@ H.PWiz К счастью 64=2^6, это еще один байт.
Орджан Йохансен
1

ScopedTypeVariables, 119 97 байт

Просто скопировал с mauke с небольшими изменениями.

В настоящее время есть два других ответа для ScopedTypeVariables: 113 байтов Csongor Kiss и 37 байтов dfeuer . Это представление отличается тем, что не требует других расширений Haskell.

-22 байта благодаря Орджану Йохансену.

class(Show a,Num a)=>S a where s::a->IO();s _=print$(id::a->a)0
instance S Float
main=s(0::Float)

Попробуйте онлайн!

stasoid
источник
97 байт (хотя IO()/printв полиглоте трюк не сработает).
Орджан Йохансен
@ ØrjanJohansen Я добавил ScopedTypeVariables, но нарушил ExtendedDefaultRules . Как это можно исправить? У меня уже была такая ошибка раньше, но я не могу применить ваше объяснение здесь. Код ScopedTypeVariables я добавляемое это .
Стасоид
Я вижу, коды используют аналогичные приемы по умолчанию, и они мешают друг другу. Одно из решений - позволить новому использовать более ограниченный класс, чем Num. Я думаю, что class(Show a,Floating a)=>K a where{k::a->String;k=pure$ show(f pi)where f=id::a->a};должно работать, удобно использовать это Floatи Doubleотображать piс различной точностью.
Орджан Йохансен
@ ØrjanJohansen Ого, он подходит. Спасибо.
Стасоид