Dodaj funkcję do języka programowania [zamknięty]


55

Twoim zadaniem jest zaadaptowanie funkcji do języka programowania, albo przez wdrożenie bardzo sprytnej biblioteki, albo przez przetworzenie tekstu wejściowego i / lub dostosowanie procesu kompilacji.

Pomysły:

  • Dodaj przeplatanie prezentacji w stylu PHP do C (np <?c printf("Hello,"); ?> world!.).
  • Dodaj zerowy operator koalescencyjny do jednego z tych języków, który nie jest C #.
  • Dodaj makra do PHP.
  • Dodaj gotodo JavaScript.
  • Dodaj dopasowanie wzorca do języka X.
  • Dodaj obsługę przestrzeni nazw do języka, który jej nie ma.
  • Spraw, aby C wyglądał jak PHP.
  • Spraw, by Haskell wyglądał jak Pascal.
  • ... (zachęcamy do publikowania pomysłów w sekcji komentarzy)

Zasady:

  • Przynieś coś do stołu. Nie mów tylko „Szablon Haskell”, aby dodać funkcje metaprogramowania do Haskell. To nie jest StackOverflow.
  • Cała implementacja powinna zmieścić się na jednym ekranie (nie licząc przykładu).
  • Nie hostuj kodu w witrynie zewnętrznej specjalnie do tego zadania.
  • Najbardziej imponująca lub zaskakująca funkcja wygrywa.

Nie martw się o prawidłowe wdrożenie tej funkcji w 100%. Daleko stąd! Głównym wyzwaniem jest ustalenie, co chcesz zrobić, i brutalne wycięcie szczegółów, dopóki planowane przedsięwzięcie nie stanie się wykonalne.

Przykład:

Dodaj operator lambda do języka programowania C.

Wstępne podejście:

Okej, wiem, że chciałbym użyć libgc, aby moje lambdas rozwiązały problemy ze wzrostem i spadkiem. Myślę, że pierwszą rzeczą, którą muszę zrobić, to napisać / znaleźć parser dla języka programowania C, a następnie musiałbym dowiedzieć się wszystkiego o systemie typów C. Musiałbym dowiedzieć się, jak to zrozumieć, jeśli chodzi o typy. Czy musiałbym wdrożyć wnioskowanie o typie, czy powinienem po prostu wymagać, aby parametr formalny był wpisany tak, jak podano? Co z tymi wszystkimi szalonymi funkcjami w CI, o których jeszcze nie wiem?

Jest całkiem jasne, że poprawne wdrożenie lambda w C byłoby dużym przedsięwzięciem. Zapomnij o poprawności! Uprość, uprość.

Lepszy:

Pieprzyć się w górę, kto ich potrzebuje? Mogę być w stanie coś zrobić trudne z GNU C na zagnieżdżone funkcje i wyrażenia rachunku . Chciałem pochwalić się niesamowitą syntaktyczną transformacją na C za pomocą zwięzłego, zhackowanego kodu, ale nie potrzebuję nawet parsera do tego. To może poczekać na kolejny dzień.

Wynik (wymaga GCC):

#include <stdio.h>
#include <stdlib.h>

#define lambda(d,e)({d;typeof(e)f(d){return(e);};f;})

#define map(F,A)({typeof(F)f=(F);typeof(*(A))*a=(A);({int i,l=((int*)(a))[-1]; \
typeof(f(*a))*r=(void*)((char*)malloc(sizeof(int)+l*sizeof(*r))+sizeof(int));  \
((int*)r)[-1]=l;for(i=0;i<l;i++)r[i]=f(a[i]);r;});})

#define convert_to(T) lambda(T x, x)
#define print(T, fmt) lambda(T x, printf(fmt "\n", x))

int main(void)
{
    int *array = 1 + (int[]){10, 1,2,3,4,5,6,7,8,9,10};
    map(print(int, "%d"), array);

    double *array2 = map(lambda(int x, (double)x * 0.5), array);
    map(print(double, "%.1f"), array2);

    long *array3 = map(convert_to(long), array2);
    map(print(long, "%ld"), array3);

    long product = 1;
    map(lambda(int x, product *= x), array);
    printf("product: %ld\n", product);

    return 0;
}

To było łatwe, prawda? Wrzuciłem nawet mapmakro, aby było użyteczne i ładne.


10
Myślę, że Ken Thompson pobił nas wszystkich : 0 bajtów kodu.
dmckee,

4
Nie chcę tworzyć pełnej odpowiedzi, ale dodałem klasy do GNU C , na wypadek, gdyby ktoś był zainteresowany.
Richard J. Ross III

3
Nie wiem, czy to się kwalifikuje, ale ja pisałem przykład kontynuacje w C . Jednak trochę więcej niż ekran.
luser droog

1
Moje podziękowania dla każdego, kto wskrzesił to pytanie; Mam doskonały pomysł na zgłoszenie.
Jonathan Van Matre

2
Dodaj lambda do C ... hej, nie patrz tak na mnie.
Leushenko

Odpowiedzi:


27

Składnia OOP w Haskell

import Prelude hiding ((.))
a . b = b a

Obiekty mogą mieć właściwości:

[1,5,3,2].length -- 4
[1,5,3,2].maximum -- 5
'a'.succ -- 'b'

... i metody:

"Hello world!".take(5) -- "Hello"
"Hello world!".splitAt(2) -- ("He","llo world!")
"Hello world!".map(toUpper) -- "HELLO WORLD!"

2
Gdzieś widziałem tego operatora napisanego &i zdefiniowanego w ten sposób (&) = flip ($).
świst

6
@swish Nie korzystałem, &ponieważ jest to jedyny operator „adres” (implementacja wskaźników w Haskell pozostawia się jako ćwiczenie dla czytelnika).
lortabac

1
@ Swish możesz uratować postać (i cykl mózgowy), używającflip id
Sean D

24

goto w JavaScript?

Moją pierwszą myślą było podejście funkcjonalne - dodanie parametru do funkcji, aby wskazać, od którego miejsca ma się rozpocząć wykonywanie, przy użyciu tego switchpolecenia i pętli zewnętrznej, która wielokrotnie wywołuje funkcję na podstawie własnej wartości zwracanej . Niestety wykluczałoby to stosowanie zmiennych lokalnych, ponieważ tracą one swoje wartości z każdym goto.

Mogłem użyć withinstrukcji i przenieść wszystkie deklaracje zmiennych na początek funkcji, ale musiał być lepszy sposób. W końcu przyszło mi do głowy wykorzystanie wyjątków JavaScript . W rzeczywistości Joel Spolsky powiedział: „Uważam wyjątki za nie lepsze niż„ goto ... ” - oczywiście idealne dopasowanie.

Pomysł polegał na umieszczeniu nieskończonej pętli wewnątrz funkcji, zakończonej jedynie returninstrukcją lub nieprzechwyconym wyjątkiem. Wszystkie gotos, traktowane jako wyjątki, zostałyby złapane w pętlę, aby zapobiec jej zakończeniu. Oto wynik tego podejścia:

function rewriteGoTo(func) {
    var code = '(';
    code += func.toString()
        .replace(/^\s*(\w+)\s*:/gm, 'case "$1":')
        .replace('{', '{ var $_label = ""; function goTo(label) { $_label = label; throw goTo; } while(true) try { { switch($_label) { case "": ');
    code += '} return; } catch($_e) { if($_e !== goTo) throw $_e; } })';
    return code;
}

Możesz używać go w ten sposób - nawet w trybie ścisłym ES5 - z wyjątkiem przeglądarki Internet Explorer ( wersja demonstracyjna ):

var test = eval(rewriteGoTo(function(before) {
    var i = 1;
    again: print(before + i);
    i = i + 1;
    if(i <= 10) goTo('again');
}));

[Internet Explorer z jakiegoś powodu nie ewaluuje kodu funkcji anonimowej, więc należałoby nadać tej funkcji nazwę (przed przepisaniem) i wywołać ją przy użyciu tej nazwy. Oczywiście prawdopodobnie złamałoby to zasady trybu ścisłego.]

Nie pozwala to na przeskakiwanie do instrukcji znajdującej się w bloku (dopóki takie konstrukcje jak urządzenie Duffa nie staną się legalne), ale możemy sobie z tym poradzić (kolejna, samoczynnie wykonująca się przepisana funkcja), prawda?


1
Słodkie! Dobra robota upraszczająca to zadanie. Ciekawa ciekawostka: jeśli gotozostałyby w pełni zaimplementowane w JavaScript (gdzie można użyć, gotoaby wyskoczyć z dowolnego zakresu, nawet funkcji ), oznaczałoby to wsparcie dla kontynuacji.
Joey Adams

22

# zdefiniować w Javie

Pomyślałem, że fajnie byłoby wdrożyć makra w Javie.

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * defines the use of #define. Usage:
 *
 * #def toReplaceCanHaveNoSpaces replacement can have extra spaces
 *
 * must be at the beginning of the line (excluding starting spaces or tabs)
 * 
 * @author Quincunx
 */
public class Define {

    public static void main(String[] args) {
        if (args.length != 1) {
            err("Please provide exactly 1 argument");
        }
        File source = new File(args[0]);
        if (!source.exists()) {
            err("Supplied filepath does not point to an existing file");
        }
        if (!getExtension(args[0]).equalsIgnoreCase(".java")) {
            err("Supplied file is not of type .java");
        }
        ArrayList<String> sourceData = new ArrayList<>();
        ArrayList<String[]> replacements = new ArrayList<>();
        try {
            BufferedReader read = new BufferedReader(new FileReader(source));
            String data;
            while ((data = read.readLine()) != null) {
                sourceData.add(data);
            }
            read.close();
        } catch (IOException ex) {
            Logger.getLogger(Define.class.getName()).log(Level.SEVERE, null, ex);
        }
        for (int index = 0; index < sourceData.size(); index++) {
            String line = sourceData.get(index);
            line = line.replaceAll("\t", "    ");
            for (String[] e : replacements) {
                line = line.replace(e[0], e[1]);
            }

            if (line.trim().charAt(0) != '#') {
                sourceData.set(index, line);
                continue;
            }
            while (line.charAt(0) != '#') {
                line = line.substring(1);
            }
            int indexOf = line.indexOf(" ");
            String type = line.substring(1, indexOf);

            switch (type) {
                case "def":
                case "define":
                    String toReplace = line.substring(indexOf + 1, line.indexOf(" ", indexOf + 1));
                    replacements.add(new String[]{toReplace, line.substring(line.indexOf(":") + 1)});
                    break;
                default:
                    err("The source code contains a # in which there is no correct type");
            }
        }

        try {
            BufferedWriter write = new BufferedWriter(new FileWriter(source));
            for (String s : sourceData) {
                write.write(s);
                write.newLine();
            }
            write.close();
        } catch (IOException ex) {
            Logger.getLogger(Define.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static void err(String message) {
        System.err.println(message);
        System.exit(1);
    }

    public static String getExtension(String filePath) {
        return filePath.substring(filePath.lastIndexOf("."));
    }

}

Przykładowe użycie (konwertuje na wcześniej opublikowany kod; zróbmy to dziwne):

#def @ o
#def ~ a
#def $ i
#def ` e
#d`f % m
#d`f ! {
#d`f & d
#&`f _ }
#&`f 2 (
#&`f 7 )
#&`f $%p@rt$@. $%p@rt j~v~.$@.
#&`f $%p@rtu. $%p@rt j~v~.ut$l.
#&`f ps publ$c st~t$c
#&`f Str Str$ng

$%p@rt$@.Buff`r`&R`~&`r;
$%p@rt$@.Buff`r`&Wr$t`r;
$%p@rt$@.F$l`;
$%p@rt$@.F$l`R`~&`r;
$%p@rt$@.F$l`Wr$t`r;
$%p@rt$@.IOExc`pt$@n;
$%p@rtu.Arr~yL$st;
$%p@rtu.l@gg$ng.L`v`l;
$%p@rtu.l@gg$ng.L@gg`r;

#d`f L$st Arr~yL$st
#d`f l@g; L@gg`r.g`tL@gg`r2D`f$n`.cl~ss.g`tN~m`277.l@g2L`v`l.SEVERE, null, `x7;    

publ$c cl~ss D`f$n` !

    ps v@$d %ain2Str[] ~rgs7!
        $f 2~rgs.l`ngth != 17 !
            `rr2"Pl`~s` pr@v$&` `x~ctly 1 ~rgu%`nt"7;
        _
        F$l` squrc` = n`w F$l`2~rgs[0]7;
        $f 2!sourc`.`x$sts277 !
            `rr2"Suppli`& f$l`p~th &@`s n@t p@int t@ ~n `x$st$ng f$l`"7;
        _
        $f 2!g`tExt`ns$@n2~rgs[0]7.`qu~lsIgn@r`C~s`2".j~v~"77 !
            `rr2"Suppl$`& f$l` $s n@t @f typ` .j~v~"7;
        _
        L$st<Str> s@urceDat~ = n`w List<>27;
        L$st<Str[]> repl~cem`nts = n`w L$st<>27;
        try !
            Buff`r`&R`a&`r r`a& = new Buff`redRe~&`r2n`w F$l`R`~&`r2s@urc`77;
            Str &~t~;
            wh$l` 22&~t~ = r`~&.r`~&L$n`277 != null7 !
                s@urc`D~t~.~&&2&ata7;
            _
            re~&.cl@se27;
        _ c~tch 2IOExc`ption ex7 !
            log;
        _
        f@r 2$nt $n&`x = 0; $ndex < s@urc`D~t~.s$z`27; $nd`x++7 !
            Str l$n` = s@urc`D~ta.get2index7;
            line = line.r`pl~c`All2"\t", "    "7;
            for 2Str[] ` : r`pl~c`%`nts7 {
                line = line.r`pl~c`2`[0], e[1]7;
            _

            if 2l$ne.tr$%27.ch~rAt207 != '#'7 !
                sourc`D~t~.s`t2$n&`x, l$n`7;
                c@nt$nu`;
            _
            wh$l` 2line.ch~rAt207 != '#'7 !
                l$ne = l$ne.substr$ng217;
            _
            $nt in&`xOf = line.$n&`xOf2" "7;
            Str typ` = line.substring21, indexOf7;

            sw$tch 2type7 !
                c~s` "&`f":
                c~s` "def$n`":
                    str t@R`pl~c` = line.substring2indexOf + 1, line.indexOf2" ", indexOf + 177;
                    r`pl~c`%`nts.~&&2n`w s\Str[]!t@R`place, line.substring2line.indexOf2":"7 + 17_7;
                    br`~k;
                def~ult:
                    err2"Th` s@urc` c@&` c@nt~$ns ~ # $n wh$ch th`r` i$s n@ c@rr`ct typ`"7;
            _
        _

        try !
            Buff`r`&Wr$ter wr$te = new BufferedWriter2new F$l1Wr$t1r2s@urc177;
            for 2Str s : s@urceData7 !
                wr$te.write2s7;
                wr$te.n`wLin`27;
            _
            wr$t`.cl@s`27;
        _ c~tch 2IOExc`pt$@n `x7 !
            l@g;
        _
    _

    ps v@$& `rr2Str m`ss~g`7 !
        Syst`%.`rr.pr$ntln2message7;
        Syst`%.`x$t217;
    _

    ps Str g`tExt`nsi@n2Str fileP~th7 !
        r`turn f$lePath.substr$ng2f$l`P~th.l~stInd`xOf2"."77;
    _

_

7
Przewijałem drugi blok, a moją jedyną myślą było „... w dół króliczej nory”.
Soham Chowdhury,

18

Foreach in C

Iteruj tablice (działa dla tablic statycznych, a nie tych otrzymywanych przez wskaźnik)

//syntactic beauty
#define in ,    

//syntactic beauty's helper macro
#define foreach(a) _foreach(a)

//the real foreach macro
#define _foreach(e,arr)\
typeof (&arr[0]) e;\
for (e=&arr[0];e!=&arr[sizeof(arr)/sizeof(arr[0])];e++)

Aby to przetestować:

int int_arr[3]={10,20,30};    
char *strings[]={"Hello","World","Foreach","Test"};

foreach (num in int_arr) {
        printf ("num=%d\n",*num);
}

foreach (str in strings) {
        printf ("str=%s\n",*str);
}

wynik:

num=10
num=20
num=30
str=Hello
str=World
str=Foreach
str=Test

17

Właściwości w C.

Tomasz Wegrzanowski zaimplementował właściwości w zwykłym C, celowo segregując program, gdy właściwość jest dostępna.

Obiekt z „właściwością” jest konfigurowany przez utworzenie structprzecinającego wiele stron, zapewniając, że adres pamięci właściwości znajduje się na innej stronie niż rzeczywiste elementy danych. Strona właściwości jest oznaczona jako niedostępna, co gwarantuje, że próba uzyskania dostępu do właściwości spowoduje awarię. Następnie moduł obsługi błędów ustala, który dostęp do właściwości spowodował segfault, i wywołuje odpowiednią funkcję w celu obliczenia wartości właściwości, która jest przechowywana pod adresem pamięci właściwości.

Procedura obsługi błędów oznacza również stronę danych jako tylko do odczytu, aby zapewnić spójność obliczonej wartości; przy następnej próbie zapisu do elementu danych, który uruchamia segfault, którego moduł obsługi ustawia stronę danych jako odczyt-zapis, a stronę właściwości brak dostępu (wskazując, że należy ją ponownie obliczyć).


15

Obliczono, że pochodzi z Common Lisp

Początkowo wdrażałem come-from. Ale to nie wystarczyło.

Zainspirowany obliczonym goto, postanowiłem wdrożyć obliczone źródło.

(defmacro computed-come-from-tagbody (&rest statements)
  (let ((has-comp-come-from nil)
        (comp-come-from-var nil)
        (start-tag (gensym))
        (end-tag (gensym)))

    (let ((current-tag start-tag)
          (come-froms (make-hash-table :test #'eq)))

      (let ((clauses '()))
        (loop for statement in statements do
             (if (symbolp statement)
                 (setf current-tag statement))

             (cond
               ((and (consp statement)
                     (eql 'come-from (car statement)))

                (setf has-comp-come-from t)
                (setf (gethash (cadr statement) come-froms) current-tag))
               (t (push statement clauses))))


        (if (not has-comp-come-from)
            `(tagbody ,@(reverse clauses))
            (let ((res '())
                  (current-tag start-tag))
              (loop for clause in (reverse clauses) do
                   (cond
                     ((symbolp clause)
                      (push clause res)
                      (setf current-tag clause)
                      ;; check all vars for jumps
                      (push
                       `(progn ,@(loop for k being the hash-key of come-froms
                                    for v being the hash-value of come-froms collect
                                      `(when (eql ,k ,current-tag)
                                         (go ,v))))
                       res))
                     (t (push clause res))))
              `(macrolet ((come-from (idx)
                            (declare (ignore idx))
                            (error "Come-from cannot be used with another form.")))
                 (tagbody ,@(reverse res)))))))))

Przykłady użycia

(come-from x) ; whenever we're at the top of a labeled block and the value of x is equal to the label, jump back to this point.

Dla każdej deklaracji przychodzącej w tagbody sprawdzi na każdej etykiecie, czy zmienna przychodząca jest równa bieżącej etykiecie, a jeśli tak, przeskoczy do odpowiedniej deklaracji przychodzącej.

Pozdrawiacz

(let ((x :repeat)
      (y :exit))
   (computed-come-from-tagbody
      :loop              ;; when x == :loop jump to :loop.  when y == :loop jump to :exit
      (come-from x)
      (format t "What is your name? ")
      (let ((name (read-line)))
         (terpri)
         (format t "Hello ~a~%" name)
         (print (string= name "exit"))
         (when (string= name "exit")
             (setf x nil
                   y :repeat)))
       :repeat           ;; when x = :repeat jump to loop, when y = :repeat jump to exit
       :exit             ;; when x = :exit jump to loop, when y = :exit jump to exit
       (come-from y)))

FizzBuzz

(let ((i 0)
      (x nil)
      (y nil))
   (computed-come-from-tagbody
       :loop
       (come-from x)
       (cond
         ((> i 100)  (setf x nil
                           y :end-iteration)) 
         (t (or (and (zerop (mod i 3)) (zerop (mod i 5)) (print "FizzBuzz"))
                (and (zerop (mod i 3)) (print "Fizz"))
                (and (zerop (mod i 5)) (print "Buzz"))
                (print i))  
            (incf i)
            (setf x :end-iteration)))
       :end-iteration
       :end
       (come-from y)
       (print "done")))

14

„Automatyczne ciągi znaków” w Rubim

Kod jest dość prosty:

def self.method_missing *a; a.join ' '; end

Teraz możesz zrobić

print This is an automatic string #=> This is an automatic string
print hooray #=> hooray

x = code golf
print This is + ' ' + x + '!' #=> This is code golf!


13

Dodaj makra do PHP

Do tego zadania możemy po prostu użyć preprocesora C.

Skrypt php:

<?php

#define ERROR(str) trigger_error(#str, E_USER_ERROR)

function test() {
        ERROR(Oops);
}

Pipe to chociaż cpp:

cpp < test.php

Wynik:

<?php

function test() {
 trigger_error("Oops", E_USER_ERROR);
}

Czy to nie zepsuje się z funkcjami PHP, które nie istnieją w C? Takich jak heredoki. Afair PP PP był dość ściśle związany z gramatyką C.
Joey,

1
Myślę, że preprocesor sprawdza tylko dane wejściowe, nie próbując ich zrozumieć. An <<<HEREDOCjest niczym więcej niż 3 niższymi niż lub lewymi zmianami i identyfikatorem :-) To jednak spowoduje podstawienie makr w ciągach heredoc.
Arnaud Le Blanc

Preprocesor C dodaje dodatkowe śmieci do wyjścia, więc twój przykład nie działałby zgodnie z oczekiwaniami
anonimowy tchórz

1
Można grep -v ^#to naprawić. Myślę, że to wystarczy na to pytanie :-)
Arnaud Le Blanc

10

Wzorce dopasowywania wzorców w Pythonie

def pattern_match(n, s="__fns"):
 s=n+s;g=globals()
 def m(f):
  def a(*r):
   for f in g[s]:
    if reduce(lambda c,t:c and eval(t[1:],{},dict(zip(f.func_code.co_varnames,r))),filter(lambda x:x and x[0]is"|",map(lambda x:x.strip(),f.func_doc.split("\n")))): return f(*r)
  g[n]=a;g[s]=(g.get(s)or[])+[f]
  return a
 return m

Ciało funkcji ma 288 znaków.

Wzorce dopasowania wzorców pozwalają na używanie zupełnie różnych funkcji w zależności od wartości argumentów. Chociaż można go łatwo emulować za pomocą szeregu ifinstrukcji, osłony dopasowujące wzorce mogą pomóc w oddzieleniu sekcji kodu i jest to świetna wymówka, aby wykonać szalone metaprogramowanie.

pattern_matchjest dekoratorem, który tworzy nową funkcję, która implementuje zabezpieczenia dopasowywania wzorów . Warunki dla każdej „podfunkcji” podane w każdym dokumencie w wierszach rozpoczynających się od potoku ( |). Jeśli wszystkie warunki są zgodne z prawdą, uruchamiana jest ta wersja funkcji. Funkcje są testowane w kolejności, dopóki nie zostanie znalezione dopasowanie. W przeciwnym razie Nonejest zwracany.

Przykład pomoże wyjaśnić:

@pattern_match("test1")
def test1_a(a, b, c):
    """
    This guard tests if a and c are positive

    | a > 0
    | c > 0
    """
    return a + b + c

@pattern_match("test1")
def test1_b(a, b, c):
    """
    This pattern only ensures b is positive

    | b > 0
    """
    return b + c

@pattern_match("test1")
def test1_c(a, b, c):
    """
    Final catchall

    | True
    """
    return 0


print test1(1,2,3) # (a) >>> 6
print test1(1,2,0) # (b) >>> 2
print test1(1,0,0) # (c) >>> 0
print test1(0,0,1) # (b) >>> 1

W Haskell nazywa się to strażnikami , a nie dopasowaniem wzorów. W Haskell dopasowanie wzorca pozwala powiedzieć f [a,b,c] = ..., co nie tylko testuje argument względem predykatu, ale wiąże odpowiednie zmienne po pomyślnym dopasowaniu. Ale to wciąż całkiem fajne.
Joey Adams,

D'oy! Dziękujemy za poprawienie tego! Myślałem też o Haskellu, szczególnie skupiając się na zdefiniowaniu funkcji z dwoma różnymi predykatami (tj. f (x:xs) = ...I f [] = ...). W jakiś sposób zwiodłem tam strażników, ale od tego zacząłem |.
zbanks

To nie jest wyzwanie związane z golfem; możesz być bardziej szczegółowy (i czytelny), jeśli chcesz! :)
ReyCharles


7

Operatorzy celni w Lua

Pogs sprytnie wykorzystał przeciążanie operatora w Lua , aby umożliwić zdefiniowanie niestandardowych operatorów infix . Rozszerzyłem to, aby obsługiwać sekcje operatora (częściowo stosując operator z dowolnym operandem) i wywoływać wynikowy obiekt tak, jakby to była funkcja.

---- implementation
function infix(f)
  local function g(self, x)
    return f(self[1] or x, self[2] or x)
  end

  local mt   = { __sub = g, __call = g }
  local self = {}
  return setmetatable(self,
           { __sub = function (lhs,rhs)
                       return rhs == self and setmetatable({ lhs, nil }, mt)
                                           or setmetatable({ nil, rhs }, mt)
                     end })
end

---- testing
local eq   = infix(function (a, b) return a == b end)
local ge   = infix(function (a, b) return a >= b end)

local comp = infix(function (a, b) return a < b and -1
                                       or a > b and  1
                                       or            0 end)

function filter(pred, xs)
  local res = {}
  for i=1,#xs do
    if pred(xs[i]) then table.insert(res, xs[i]) end
  end
  return res
end

print(1  -eq-  1)                                      --> true
print(1 -comp- 0)                                      --> 1
print((4 -ge)(1))                                      --> true
print(table.unpack(filter(ge- 0, {1,-4,3,2,-8,0})))    --> 1   3   2   0

7

Ciągi wielowierszowe w javascript

w tej skomplikowanej składni dla ciągów wielowierszowych każdy ciąg wielowierszowy będzie poprzedzony (function(){/*znakiem nowej linii i znakiem nowej linii, a po nim znak nowej linii i */}+'').split('\n').slice(1,-1).join('\n').

używając tej niesamowitej, intuicyjnej składni, możemy w końcu użyć ciągów wieloliniowych:

var string = (function(){/*
THIS IS A MULTILINE STRING
HOORAY!!!
*/}+'').split('\n').slice(1,-1).join('\n');

console.log(string) // THIS IS A MULTILINE STRING
                    // HOORAY!!!

dla osób, które nie lubią naszej prostej składni, mamy kompilator naszego wspaniałego nowego języka:

function compile(code)
{
    return code.replace("#{", "(function(){/*").replace("}#", "*/}+'').split('\n').slice(1,-1).join('\n')")
}

ten sam przykład w skompilowanej wersji językowej:

var string = #{
THIS IS A MULTILINE STRING
HOORAY!!!
}#;
console.log(string) // THIS IS A MULTILINE STRING
                    // HOORAY!!!

1
Z jakiegoś powodu nie mogę wstawić */moich wielowierszowych ciągów. Jest to bardzo denerwujące, gdy zawiera wyrażenia regularne w ciągach!
FireFly,

@FireFly Właściwie myślę, że to nadal działa. Podświetlanie składni staje się jednak dziwne.
dumny haskeller

6

Listowalna lista w C # (jak Python)

Zawsze podobała mi się notacja plastra Pythona i chciałbym, żeby była dostępna w C #

Stosowanie:

SliceList<int> list = new SliceList<int>() { 5, 6, 2, 3, 1, 6 };
var a = list["-1"];     // Grab the last element (6)
var b = list["-2:"];    // Grab the last two elements (1,6)
var c = list[":-2"];    // Grab all but the last two elements (5,6,2,3)
var d = list["::-1"];   // Reverse the list (6,1,3,2,6,5)
var e = list["::2"];    // Grab every second item (5,2,1)

Kod daleki od odporności na błędy:

public class SliceList<T> : List<T>
{
    public object this[string slice]
    {
        get
        {
            if (string.IsNullOrWhiteSpace(slice))
                return this.ToList();
            int[] values = { 0, Count, 1 };
            string[] data = slice.Split(':');
            for(int i = 0; i < data.Length; i++)
            {
                if (string.IsNullOrEmpty(data[i])) continue;
                int value;
                int.TryParse(data[i], out value);
                if(value < 0 && i < 2)
                    value += Count;
                values[i] = value;
            }
            if (data.Length == 1)
                return this[values[0]];
            int start = Math.Min(values[0], values[1]);
            int stop = Math.Max(values[0], values[1]);
            int step = values[2];
            int sign = Math.Sign(step);
            if (sign < 0)
            {
                var temp = start;
                start = stop-1;
                stop = temp-1;
            }

            SliceList<T> newList = new SliceList<T>();
            for (int i = start; i != stop; i += step)
                newList.Add(this[i]);

            return newList;
        }
    }
}

Już dawno poprosiłem o krojenie, aby zostało uwzględnione w .NET, nadal jest po prostu ignorowane :(
Ray

6

Uprość C

Ten kod pozwala pisać programy w C, które bardziej przypominają język skryptowy. Zawiera słowa kluczowe, takie jak „var”, „is”, „string”, „plus”, „równo” i kilka innych. Działa poprzez wiele instrukcji definiujących.

// pretty.c

#include<stdio.h>

#define function int
#define var int
#define is =
#define then {
#define do {
#define does {
#define end }
#define equal ==
#define notequal !=
#define greater >
#define less <
#define greaterequal >=
#define lessequal <=
#define display printf
#define otherwise }else{
#define increase ++
#define decrease --
#define plus +
#define minus -
#define times *
#define divide /
#define character char
#define string char*
#define integer int

Umożliwia to pisanie kodu takiego jak:

/*
Preprocessor abuse, Yay!
*/

#include "pretty.c"

function main() does
    var myVar is 1;
    if(myVar greater 2)then
        display("Yep\n");
    otherwise
        display("Nope\n");
    end

    for(var i is 0; i less 10; i increase)do
        display("Loop: %d\n", i);
    end

    string myString = "Hello";
    display(myString);
end

Powyższe zostaje rozszerzone do:

int main() {
    int myVar = 1;
    if(myVar > 2){
        printf("Yep\n");
    }else{
        printf("Nope\n");
    }

    for(int i = 0; i < 10; i ++){
        printf("Loop: %d\n", i);
    }

    char* myString = "Hello";
    printf(myString);
}

Prawdopodobnie nie jest to zbyt przydatne, ale uznałem za całkiem interesujące, że można zasadniczo stworzyć cały język programowania za pomocą kilku #defines.


To wygląda jak połączenie Javascript / Ruby ...
Beta Decay

Nie ma w tym prawie żadnej górnej granicy - przy wystarczającej złożoności #defines możesz nawet nadać swojemu językowi takie funkcje, jak obsługa wyjątków i wyrzucanie elementów bezużytecznych przy jednoczesnym zachowaniu podstawowej warstwy C pod spodem.
Leushenko

5

Tcl

TCL nie ma do ... whilealbo do ... untiltak ...

proc do {body op expr} {
    uplevel 1 $body
    switch -exact -- $op {
        while {
            while {[uplevel 1 [list expr $expr]} {
                uplevel 1 $body
            }
        }
        until {
            while {![uplevel 1 [list expr $expr]} {
                 uplevel 1 $body
            }
        }
    }
}

Przykład:

do {
    puts -nonewline "Are you sure? "
    flush stdout
    set result [gets stdin]
} while {[string is boolean -strict $result]}

uplevel wykonuje skrypt w zakresie wywołującym.


5

Idź w PostScript

Moją pierwszą myślą było to, że musiałbym się zepsuć ze stosem exec, więc ten fałszywy start wykopuje operator kontynuacji dla zatrzymania z ghostscript (lub xpost).

/_stopped_mark
{countexecstack array execstack dup length 2 sub get}
stopped pop def 

Ale to jest prostsze niż to. Ponieważ pozycja pliku jest taka sama dla wszystkich duplikatów uchwytu pliku ( setfilepositionzużywa swój argument, więc jest to jedyna przydatna semantyka dla tej funkcji).

/LABELS 10 dict def 

/: { % n :  define label
    LABELS exch currentfile fileposition put 
} def 

/goto { % goto label
    currentfile exch LABELS exch get setfileposition
} def 

/x 0 def 

/here :
    /x x 1 add def 

    x 5 ne {
        /here goto
    } if

x =

Drukuje 5.

Istnieją pewne ograniczenia związane z powyższym. Skok nie jest natychmiastowy, ale ma miejsce, gdy if-body powraca na najwyższy poziom, a interpreter ponownie odczytuje z pliku (zamiast odczytywać z tablicy zawierającej if-body). W tym momencie plik został zmieniony i „goto” zaczyna obowiązywać.


I to tylko definicje w słowniku, więc możesz używać prawie każdego typu etykiet.
luser droog

Możesz także wykonywać skoki bezwzględnecurrentfile <pos> setfileposition , licząc bajty od początku pliku.
luser droog

4

Symbol#to_proc z argumentami w Ruby

Symbol#to_procjest prawdopodobnie jedną z moich ulubionych sztuczek polegających na pisaniu naprawdę zwięzłego kodu Ruby. Załóżmy, że masz

nums = [1, 2, 3, 4]
text = %w(this is a test)

i chcesz przekonwertować odpowiednio zawartość numsi textna zmiennoprzecinkowe i wielkie litery. Symbol#to_procpozwala skrócić kod w następujący sposób:

nums.map { |num| num.to_f }
text.map { |word| word.upcase }

do tego:

nums.map(&:to_f)
text.map(&:upcase)

Niesamowite! Ale co, jeśli chcemy podnieść każdy element numsdo iXX władzy, lub zastąpić każde wystąpienie sze *w text? Czy jest jakiś sposób na skrócenie takiego kodu?

nums.map { |num| num ** 1i }
nums.map { |word| word.gsub('s', '*') }

Niestety, nie ma łatwego sposobu przekazywania argumentów podczas używania Symbol#to_proc. Widziałem to na wiele sposobów, ale prawdopodobnie dwa najbardziej sprytne i użyteczne obejmują łatanie małp Symbolklasy [ 1 , 2 ]. Zilustruję pierwszy sposób poniżej.

class Symbol
  def with(*args, &block)
    ->(caller, *rest) { caller.send(self, *rest, *args, &block) }
  end
end

Teraz możesz robić takie rzeczy jak:

nums.map(&:**.with(1i))
text.map(&:gsub.with('s', '*'))
nums.take_while(&:<.with(3))
text.delete_if(&:[].with('is'))

3

Foreach JavaScript

var arr = ["Seattle", "WA", "New York", "NY", "Chicago", "IL"];

function foreach(fn, arr) {
  var s = fn.toString();
  var args = s.substring(s.indexOf('(')+1,s.indexOf(')')).split(",");
  var argsLen = args.length;
  var len = arr.length;
  for (var i = 0; i < len; i+=argsLen) {
    var part = arr.slice(i, i+argsLen);
    fn.apply(undefined, part);
  }
}

foreach (function(city, state) {
  console.log(city + ', ' + state);
}, arr);

Wynik

Seattle, WA
New York, NY
Chicago, IL

Alternatywna składnia, bardziej jak Tcl.

// Tcl's foreach loop for javascript.
// Keys in loop are prefixed with "this".
function tclForeach(keys, values, fn) {
  var obj={}, klen=keys.length, vlen=values.length, j, i;
  for (i=0, klen=keys.length; i < klen; i++) obj[keys[i]]=null;
  for(i = 0; i < vlen; i+=klen) {
    for(j=klen; j--;) obj[keys[j]] = values[i+j];
    fn.apply(obj);
  }
}

tclForeach(["city","state"], arr, function() {
  console.log(this.city + ', ' + this.state);
});

To nie jest zwykły foreach, ale jest bardziej interesujący. Sprawdza listę argumentów funkcji konsumującej. Możesz pójść dalej z tą sztuczką i robić naprawdę fajne rzeczy.
Joey Adams

1
Idę na foreach w stylu Tcl. Dodałem nieco inne podejście, które bardziej przypomina Tcl.
wolfhammer

2

Gotos w Haskell

podstawową ideą jest to, że gotos może być częściowo symulowany przy użyciu ostatniego dokomentarza instrukcji. na przykład:

main = do
  loop:
  print 3
  goto loop

jest równa

main = do
  loop
loop = do
  print 3
  loop

ponieważ wykonanie przeskoczy do ostatniej instrukcji, optymalne jest wyrażanie gotos.

ponieważ sposób, w jaki to jest zrobione, gotos skacze tylko wtedy, gdy znajdują się bezpośrednio w dobloku definicji najwyższego poziomu. w rzeczywistości jest to „wywołaj x i zignoruj ​​pozostałe stwierdzenia leksykalne ” zamiast „wszystkie x i zignoruj ​​resztę instrukcji”, jak prawdziwe goto.

największym problemem jest to, że gdy nie ma możliwości pozostawienia wykonania ze środka akcji IO - nawet returnnie; returnnic nie robi, gdy nie jest to ostatnie zdanie.

rozwiązuje to ten problem, przechwytując pozostałe instrukcje w innym dobloku.

goto loop
print 3

staje się

const loop $ do
print 3

print 3oświadczenie zostaje schwytany przez doblok, więc loopstaje się ostatnią wypowiedź.

transformacja ta obsługuje również zmienne występujące w zakresie działań. odbywa się to poprzez zapamiętywanie zmiennych, które są w zasięgu, i przekazywanie ich do akcji. na przykład:

printer r = do
  loop:
  putStrLn r
  goto loop
  print "this isn't executed"

to po prostu przekłada się na:

printer r = do
  loop r
loop = do
  putStrLn r
  const (loop r) $ do
  print "this isn't executed"

kilka notatek:

return undefineddodano również instrukcję, aby upewnić się, że doblok przechwytywania nie jest pusty.

ponieważ czasami w dobloku przechwytującym występuje niejednoznaczność typu , zamiast tego constużywamy asTypeOf, co jest takie samo, constale wymaga, aby oba jego parametry miały ten sam typ.

faktyczna implementacja (w javascript):

function makeGoto(code)
{
    var vars = [] // the known variables

    // add the arguments to the functions to scope
    code.split('\n')[0].split('=')[0].split(' ').slice(1).forEach(function(varname){vars.push(varname)})
    return code.replace(/([ \t]*)([a-zA-Z]+):|([ \t]*)goto[ \t]+([a-zA-Z]+)|[ \t]+([a-zA-Z]+)[ \t]*<-/gm, function match(match, labelSpaces, label, gotoSpaces, goto, x)
        {
            if (label != undefined)
                return labelSpaces+label+" "+vars.join(' ')+"\n"+label+" "+vars.join(' ')+"=do ";
            else if(goto != undefined)
                return gotoSpaces+"asTypeOf("+goto+" "+vars.join(' ')+")$do\n"+gotoSpaces+"return undefined";
            else
            {
                vars.push(x);
                return match
            }
        })
}

przykład:

main = do
    putSrtLn "a"
    goto label
    putStrLn "b"
    label:
    putStrLn "c"

staje się:

main = do
    putStrLn "a"
    asTypeOf(label )$do
    return undefined
    putStrLn "b"
    label 
label =do 
    putStrLn "c"

wynik:

a
c

Warto wyjaśnić, że returnw Haskell jest funkcją regularną i niezwiązaną ze słowem kluczowym w C / itp.
FireFly,

1

Python Goto

goto.py

import sys, re
globals_ = globals()
def setglobals(g):
    global globals_
    globals_ = g
def goto(l):
    global globals_ 
    with open(sys.argv[0], "rb") as f:    
        data = f.read()
        data_ = data.split('\n')
    if isinstance(l, int):
        l-=1 if l > 0 else 0
    elif isinstance(l, str):
        r=re.search(r"^\s*(#{0}|(def|class)\s+{0})".format(l), data, re.MULTILINE)
        l=len(data_)-(data[r.start():].count("\n")) if r else len(data_)
    if 0 < l < len(data_) or 0 < (l*-1) <= len(data_):
        exec("".join(data_[l:]),globals_)
        sys.exit(1)

Stosowanie

setglobals(globals()) #Set the globals to be used in exec to this file's globals (if imports or other variables are needed)
goto(8) #Goto line 8
goto(-8)#Goto 8th last line
goto("label")#Goto first occurrence of #label
goto("funcName")#Goto definition of funcName
goto("className")#Goto definition of className

Przykładowy przypadek testowy

import goto, sys
goto.goto(-1)
sys.exit(-1)

print "Asdf"

Dane wyjściowe przykładowego przypadku testowego

Asdf

Trochę zabawy z exec (). Może podnieść błąd maksymalnej głębokości rekurencji, jeśli nie zostanie właściwie użyty.


-2

// zaimportuj javascript bez specjalnego użycia znacznika script na stronie HTML

function i(u) {
  document.write("script src=\" + u + \"></script>");
}

i("http://www.mysite.com/myscript.js");

To kiepskie, tak, wiem. Długość: 99


@ user2509848: Ten wątek nie jest oznaczony kodem golf.
Joey Adams,

To, co opublikowałeś, wymaga scripttagu wokół tego. Gdzie dokładnie jest nowa funkcja?
manatwork

@JoeyAdams Ups, przepraszam.
Hosch250
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.