Wyzwanie
Znajdź wyrażenie o maksymalnej długości 100 bajtów z najdłuższym podpisem.
Zasady
- Dowolny język o typie statycznym z wnioskowaniem typu jest dozwolony
- Typ musi być niejednoznaczny, ale w przeciwnym razie może zawierać typy bez zdefiniowanych instancji. Na przykład
Num [a]
iEq [a]
mogą nawet bez określonej instancji - Brak importu innego niż minimum wymagane do skompilowania programu z STDIN / STDOUT
- Nieskończone typy są niedozwolone
- Jeśli odpowiedź ma więcej niż jedno wyrażenie, tylko jeden może przyczynić się do wyniku. Na przykład, chociaż sygnatura typu kompozycji ma
(.) :: (b -> c) -> (a -> b) -> a -> c
wynik 20, odpowiedź z 25 kopiami(.)\n
miałaby wynik 20, a nie 500 - Wyrażenie musi mieć maksymalnie 100 bajtów
- Wynik to liczba znaków w podpisie typu, z wyłączeniem nazwy funkcji i wszelkich białych znaków. Na przykład
f :: (a -> b) -> a -> b
miałby wynik 12 - Najwyższy wynik wygrywa!
Przykłady
Chociaż dozwolone są inne języki, następujące przykłady są w języku Haskell:
Score: 112
map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map.map
f :: (a -> b)
-> [[[[[[[[[[[[[[[[[[[[[[[[[a]]]]]]]]]]]]]]]]]]]]]]]]]
-> [[[[[[[[[[[[[[[[[[[[[[[[[b]]]]]]]]]]]]]]]]]]]]]]]]]
Score: 240
(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.).(.)
f :: (b->c)->(a->a1->a2->a3->a4->a5->a6->a7->a8->a9->a10->a11->a12->a13->a14->a15->a16->a17->a18->a19->a20->a21->a22->a23->a24->b)->a1->a2->a3->a4->a5->a6->a7->a8->a9->a10->a11->a12->a13->a14->a15->a16->a17->a18->a19->a20->a21->a22->a23->a24->c
Score: 313
foldl$foldl$foldl$foldl$foldl$foldl$foldl$foldl$foldl$foldl$foldl$foldl$foldl$foldl$foldl$foldl(.)
f :: (Foldable t, Foldable t1, Foldable t2, Foldable t3, Foldable t4,
Foldable t5, Foldable t6, Foldable t7, Foldable t8, Foldable t9,
Foldable t10, Foldable t11, Foldable t12, Foldable t13,
Foldable t14, Foldable t15) =>
(b -> c)
-> t (t1 (t2 (t3 (t4 (t5 (t6 (t7 (t8 (t9 (t10 (t11 (t12 (t13 (t14 (t15 (b
-> b))))))))))))))))
-> b
-> c
Score: 538
lex.show.foldl1.mapM.traverse.sum.mapM.sum.traverse.(.).mapM.scanl.zipWith3((.traverse).(.traverse))
(Num
(a -> ([[c]] -> t3 [[a1 -> f b]]) -> [[c]] -> t3 [[a1 -> f b]]),
Num
(([[c]] -> t3 [[a1 -> f b]])
-> t1 (t2 ([[c]] -> t3 [[a1 -> f b]]))
-> [[c]]
-> t3 [[a1 -> f b]]),
Show
(t (t1 (t2 ([[c]] -> t3 [[a1 -> f b]])))
-> t1 (t2 ([[c]] -> t3 [[a1 -> f b]]))),
Applicative f, Foldable t,
Foldable ((->) (t1 (t2 ([[c]] -> t3 [[a1 -> f b]])) -> a)),
Foldable
((->) (([[c]] -> t3 [[a1 -> f b]]) -> a -> t3 [a1 -> f b])),
Traversable t1, Traversable t2, Traversable t3, Traversable t4,
Traversable t5,
Traversable ((->) (t1 (t2 ([[c]] -> t3 [[a1 -> f b]])))),
Traversable ((->) ([[c]] -> t3 [[a1 -> f b]]))) =>
[(t5 (t4 a1) -> f (t5 (t4 b))) -> c -> a1 -> f b]
-> [(String, String)]
code-challenge
busy-beaver
functional-programming
Michael Klein
źródło
źródło
Odpowiedzi:
Haskell, ~ 2 ^ (2 ^ 18)
Każde zastosowanie z
f
grubsza podwaja podpis typu, przekształcając podpis typuT
na(T,T)
. Na przykład czterokrotna kompozycjaf.f.f.f$0
ma typKażda linia czterokrotnie zwiększa liczbę aplikacji
f
, podając4^9 = 2^18
na końcu. Tak więc podpis typu ma rozmiar rzędu2^(2^18)
.źródło
f x=(x,x,x)
kosztem jednegon.
w ostatnim wierszu daje optymalny wynik dla tej ogólnej struktury.n.
będzie większy.2^18
vs3 * (2^16)
chyba że popełniłem błąd przy obliczaniu pierwotnego potęgowania:2^(4^9)
vs.3^((4^8)*3)
(,)
(lub(,,)
) można wykorzystać do zapisania niektórych bajtów i poprawy wyniku poprzez użycie większej liczbyn
s.Java, wynik 17301488
Wymaga metody
<T>java.util.Map<T,T>f(T t){return null;}
, która została zaliczona do limitu 100 bajtów.f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(1)))))))))))))))))))
Podpis tego typu kompilacji powinien być zgodny z tym.
źródło
Haskell z rozszerzeniami,⋙ A ( A ( A ( A ( 220 , 0 ) , 0 ) , 0 ) , 0 ) , 0 )
Wypróbuj online!
Wymaga
-XDataKinds
,-XPolyKinds
,-XTypeOperators
,-XUndecidableInstances
, i-XTypeFamilies
.Ogromne podziękowania dla Ørjana Johansena, który zdał sobie sprawę, że poprawienie konstruktora liczb naturalnych i zbudowanie argumentów nieco inaczej pozwoliło zaoszczędzić dwa bajty, pozostawiając wystarczająco dużo miejsca na kolejną iterację
#
.Oczywiście sprawdzanie typu zrezygnuje z próby sprawdzenia tego programu. Aby uzyskać ogólne wyobrażenie o tym, jak wyglądałby podpis (gdyby był wystarczająco mały, aby zmieścił się w obserwowalnym wszechświecie), wypróbuj znacznie mniejszy
Wyjaśnienie
RodzinaZA
#
typów jest ściśle powiązana z funkcją Ackermann – Péter , powszechnie zapisywaną literą , ale rośnie znacznie szybciej. Funkcja Ackermanna – Pétera jest zdefiniowana#
#
z drugiej strony możemy zadzwonić do i napisaćTylko drugi przypadek jest inny. Dowód zakończenia jest identyczny ze standardowym dla i powinno być jasne, że dla wszystkich i .A B(m,n)≥A(m,n) m n
Tutaj obliczamy jednoargumentową reprezentację
Według bezpośredniego obliczenia , a więcB(B(B(B(0,0),0),0),0)=220
Zauważ, że to tylko , więc na początek trochę podnieśliśmy. Nie mam jasnego pojęcia, o ile szybciej rośnie niż , ale biorąc pod uwagę przebieg obliczeń, wydaje się prawdopodobne, że będzie rosło znacznie szybciej.A(A(A(A(0,0),0),0),0) 5 B A
Liczba cyfr w parzystym jest zbyt duża, aby wyrazić praktycznie w systemie dziesiętnym, więc jest ... dość śmiesznie duża.A(6,0)
Definicja liczb naturalnych
(?)
jest nieco niestandardowa. Aby zaoszczędzić miejsce, używamy(?)
zarówno typu liczb naturalnych (na poziomie typu), jak i typu proxy (na poziomie terminu).Uważam, że albo,
TypeFamilies
albo (bardziej dosłownie i zaciemniając)FunctionalDependencies
są konieczne, aby uzyskać obliczenia na poziomie typu wymagane do osiągnięcia naprawdę dużych typów.UndecidableInstances
jest potrzebny do obejścia bardzo prymitywnego sprawdzania terminacji w Haskell. Inne rozszerzenia są potrzebne tylko do skompresowania kodu do małej dostępnej przestrzeni.źródło
#Z
Z
z przodu jest lepsze niż rozpoczęcieS(S Z)#S Z
, czy to samo?#Z
na końcu są bardzo mile widziane.?
zapisywanie drugiego, pozostawiając miejsce na dodatkowe#Z
.A(m,1)
nigdy nie był większyA(A(m,0),0)
i chciałem o tym wspomnieć, ale po prostu zoptymalizowałeś się do punktu, w którym opcje były równe. (m+1
Nigdy też nie jest większy niżA(m,0)
.)Haskell, 9 · 2 663552 - 3 (≈ 1,02 · 10 199750 )
Mała („mała”) poprawa w stosunku do xnor 522 262144 + 5 . To jest 99 bajtów.
Jak to działa
Mamy
i tak dalej, przy długości mniej więcej dwukrotnie większej dla każdego
(:)
. Podane wyrażenieo.o.o
działa(:).(:).(:).….(:)
z 2 · 4 6 · 3 4 = 663552 kopii(:)
.Haskell zi
FlexibleContexts
orazNoMonomorphismRestriction
(200 · 4 331776 + 75 · 331776 + 16) / 9 ≈ 2,53 · 10 199750Niewielka poprawa w porównaniu z 12 · 2 663552 + 9 · 663552 - 4 × 1,36 · 10 199750 Bubblera , która również opiera się na tych rozszerzeniach. Sformułowanie rodzaju wyzwania sugeruje, że można na nich polegać („Na przykład
Num [a]
iEq [a]
są dozwolone, nawet bez określonej instancji”); Nie jestem pewny. To jest 100 bajtów.Jak to działa
Mamy
i tak dalej, z grubością czterokrotnie dla każdego
(/).(:)
. Podane wyrażenie-o.o.o
działa-(/).(:).(/).(:).….(/).(:)
z 4 6 · 3 4 = 331776 kopii(/).(:)
.źródło
Haskell, 12,2 663552 + 9,663552 - 4
Kolejna drobna poprawa w stosunku do odpowiedzi Andersa Kaseorga .
Jak to działa
Właśnie zmieniłem skład funkcji
(.)
na podział ułamkowy(/)
.Fractional x
Udział w wybucha podpisu funkcji wraz z głównej części, dając nieco wyższą stałą mnożnika.źródło
C 979
f
ma podpis:źródło
C ++ 11, niekonkurencyjny
I ledwo nie może uzyskać to pod 100 bajtów, ale to jest tak blisko Pomyślałem, że mogę pisać to w każdym razie, w nadziei, że ktoś zauważy optymalizację.
To jest prolog, który kosztuje 93 bajty:
I wyrażenie, 9 bajtów:
Ilustrować:
Z grubsza podwaja się za każdym razem, gdy liczba rośnie.
źródło
class
zamiasttypename
. Zastanawiam się, czy jest gdzieś tam kompilator, który nadal obsługuje tę frazę dla kompatybilności wstecznej?C # 363
Wyrażenie:
Podpis typu:
Wypróbuj online!
źródło
Idź 1.0 bez
reflect
, 98Typy Go 1.x są zdefiniowane statycznie. Oto moja pierwsza próba:
Plac zabaw On the Go :
Idź 1.9 używając aliasów typów, 2389
Plac zabaw On the Go :
Wynik:
Idź 1 za pomocą
reflect
, 65532W pakiecie istnieje ograniczenie
reflect
długości nazw typów:len(name) <= 1<<16-1
Do tej pory udało mi się uzyskać nazwę typu 65532 bajtów za pomocą tego bloku:
Pełny kod na placu zabaw Go :
Uwagi:
x:=
nigdy się nie liczy.źródło
reflect
należy liczyć importIdris,> hyper (hyper (hyper (hyper (999999999, 99, 99), 99,99), 99,99), 99,99)
Wyjaśnienie:
Definiujemy funkcję f, obliczenie typu f (0) jest tylko typem jednostki, podczas gdy f (S (n)) oblicza się do typu równości zastosowanego do argumentu funkcji „przeforsowanego” przez siebie i do f zastosowanego do n . Ostatni wiersz jest w zasadzie funkcją oczekującą wartości typu typu (27 = (4 = (2 = (1 = ()))))) (dla n = 4).
Prosty przykład
źródło
:Type
?hyper
; czy możesz wytłumaczyć?hyper
wzmocniony znacznie bardziej niż reszta, myślę, że chcesz, aby wszystkie / większość z nich99
była9
. (3) Zakładając, że$
dzieła Idrisa, takie jak Haskella, zewnętrzny zestaw nawiasów pof$
jest zbędny. (4) Czy możesz skrócić,hyper
czy wymagałoby to samego podpisu typu?Haskell, 782
Wyrażenie:
Podpis typu:
źródło
sum
jest(Num a, Foldable t) => t a -> a
Ceylon, 38843546786070481 (~ 4 · 10 16 )
To 49 zagnieżdżonych pojedynczych krotek, z pustą krotką najbardziej od środka. Krótka nazwa tego typu jest w rzeczywistości taka sama jak wartość w tym przypadku, ale w pełni rozwinięta nazwa jest znacznie dłuższa.
Kompilator Ceylon działa wiecznie, próbując to skompilować (kompilator nadal działał po 180 minutach) - będę musiał spróbować obliczyć teoretyczną długość typu.
Problem polega na tym, że w
[X]
systemie typów Cejlona typ krotki z jednym elementem jest w rzeczywistości reprezentowany jakoTuple<X, X, []>
(pierwszy parametr jest nadtypem dla wszystkich typów elementów, drugi to typ pierwszego elementu, a trzeci typ wszystkich oprócz pierwszych elementów , który jest tutaj pustą krotką (empty
obiekt, pojedyncza instancja spełniająca interfejsEmpty
)).Więc
[]
jestempty
,[[]]
jestTuple<[], [], []>
=Tuple<empty, empty, empty>
,[[[]]]
jestTuple<[[]], [[]], []>
=Tuple<Tuple<[], [], []>, Tuple<[], [], []>, []>
. A pełna nazwa zawiera nazwy pakietów, więc właściwie mamyceylon.language::Tuple<ceylon.language::Tuple<ceylon.language::empty, ceylon.language::empty, ceylon.language::empty>, ceylon.language::Tuple<ceylon.language::empty, ceylon.language::empty, ceylon.language::empty>, ceylon.language::empty>
tylko trzy poziomy. I chcemy przejść do 50.Ponieważ
ceylon.language::empty
ma 22 znaki i każdyceylon.language::Tuple<?,?,ceylon.language::empty>
dodaje 47 do dwukrotności wyniku z poprzedniego kroku, otrzymujemyf(1) = 22
if(n) = 2 · f(n-1) + 47
. Upraszcza tof(n) = 69 · 2^(n - 1) - 47
, a wpisanie 50 daje nam 38843546786070481. Oczywiście jest to znacznie więcej niż mieściłoby się w pamięci mojego komputera (8 · 10 9 bajtów).Oczywiście kompilator może być inteligentny i nie próbować przechowywać w pamięci całej nazwy typu, dopóki nie zostanie zażądana jego nazwa.
Oto pełny program próbujący wydrukować typ:
źródło
C # (interaktywny kompilator Visual C #) , 99 bajtów, wynik 841
Wypróbuj online!
Wyjścia
źródło