Aggiungi una funzione a un linguaggio di programmazione [chiuso]


55

Il tuo compito è quello di applicare una funzionalità a un linguaggio di programmazione, implementando una libreria molto intelligente, oppure elaborando il testo di input e / o modificando il processo di compilazione.

idee:

  • Aggiungi la presentazione in stile PHP interlacciata a C (ad es <?c printf("Hello,"); ?> world!.).
  • Aggiungi un operatore null a coalescenza in una di quelle lingue che non è C #.
  • Aggiungi macro a PHP.
  • Aggiungi gotoa JavaScript
  • Aggiungi la corrispondenza del modello alla lingua X.
  • Aggiungi il supporto dello spazio dei nomi a una lingua che non lo possiede.
  • Rendi C simile a PHP.
  • Fai sembrare Haskell come Pascal.
  • ... (sentiti libero di pubblicare idee nella sezione commenti)

Regole:

  • Porta qualcosa sul tavolo. Non basta dire "Template Haskell" per aggiungere strutture di metaprogrammazione a Haskell. Questo non è StackOverflow.
  • L'intera implementazione dovrebbe rientrare in una schermata (senza contare l'esempio).
  • Non ospitare codice su un sito esterno appositamente per questa attività.
  • Vince la caratteristica più impressionante o sorprendente.

Non preoccuparti di implementare correttamente la funzione al 100%. Lontano da esso! La sfida principale è capire cosa vuoi fare e tagliare ferocemente i dettagli fino a quando la tua impresa pianificata diventa fattibile.

Esempio:

Aggiungi un operatore lambda al linguaggio di programmazione C.

Approccio iniziale:

Ok, lo so che vorrei usare libgc così i miei lambda risolveranno i problemi di funarg verso l'alto e verso il basso. Immagino che la prima cosa che dovrei fare sia scrivere / trovare un parser per il linguaggio di programmazione C, quindi dovrei imparare tutto sul sistema di tipi C. Dovrei capire come darne un senso per quanto riguarda i tipi. Dovrei implementare l'inferenza del tipo o dovrei semplicemente richiedere che il parametro formale sia digitato come indicato? Che dire di tutte quelle folli funzionalità di CI che non conoscono ancora?

È abbastanza chiaro che implementare correttamente lambda in C sarebbe un'impresa enorme. Dimentica la correttezza! Semplifica, semplifica.

Meglio:

Fanculo verso l'alto, chi ne ha bisogno? Potrei essere in grado di fare qualcosa di complicato con GNU C funzioni nidificate e le espressioni dichiarazione . Volevo mostrare un'incredibile trasformazione sintattica su C con codice conciso, hacky, ma non mi servirà nemmeno un parser per questo. Che può aspettare un altro giorno.

Risultato (richiede 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;
}

È stato facile, no? Ho anche lanciato una mapmacro per renderla utile e carina.


10
Penso che Ken Thompson ci abbia battuto tutti : 0 byte di codice.
dmckee,

4
Non voglio creare una risposta completa, ma ho aggiunto classi a GNU C , nel caso qualcuno fosse interessato.
Richard J. Ross III,

3
Non so se questo si qualifica, ma ho scritto un esempio di prosecuzioni in C . Un po 'più di uno schermo, però.
Luser droog

1
I miei ringraziamenti a chiunque abbia fatto risorgere questa domanda; Ho un'idea eccellente per la mia presentazione.
Jonathan Van Matre,

2
Aggiungi un lambda alla C ... ehi, non guardarmi così.
Leushenko,

Risposte:


27

Sintassi OOP in Haskell

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

Gli oggetti possono avere proprietà:

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

... e metodi:

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

2
Da qualche parte ho visto questo operatore scritto come &e definito in questo modo (&) = flip ($).
Swish,

6
@swish Non l'ho usato &perché è l'operatore unario "address-of" (l'implementazione dei puntatori in Haskell è lasciata come esercizio per il lettore).
Lortabac,

1
@swish puoi salvare un personaggio (e un ciclo cerebrale) usandoflip id
Sean D

24

goto in JavaScript?

Il mio primo pensiero è stato un approccio funzionale : aggiungere un parametro alla funzione per indicare dove dovrebbe iniziare l'esecuzione, usando quello con switchun'istruzione e un ciclo esterno che chiama ripetutamente la funzione sul suo valore di ritorno . Sfortunatamente, ciò precluderebbe l'uso delle variabili locali, poiché perderebbero i loro valori con ogni goto.

Potrei usare withun'istruzione e spostare tutte le dichiarazioni variabili all'inizio della funzione, ma doveva esserci un modo migliore. Alla fine mi è venuto in mente di utilizzare la gestione delle eccezioni di JavaScript . In effetti, Joel Spolsky ha dichiarato: "Considero le eccezioni non migliori di" goto's ... " - ovviamente una misura perfetta.

L'idea era di inserire un ciclo infinito all'interno di una funzione, terminato solo da returnun'istruzione o un'eccezione non rilevata. Tutte le goto, trattate come eccezioni, verrebbero catturate all'interno del loop per impedirne la chiusura. Ecco il risultato di questo approccio:

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;
}

Puoi usarlo in questo modo - anche in modalità ES5 rigorosa - tranne in Internet Explorer ( demo ):

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

[Internet Explorer, per qualche motivo, non riesce a valutare il codice di una funzione anonima, quindi si dovrebbe dare un nome alla funzione (prima di riscriverla) e chiamarla usando quel nome. Naturalmente, ciò probabilmente infrangerebbe le regole della modalità rigorosa.]

Ciò non consente di saltare a un'istruzione situata all'interno di un blocco (fino a quando costrutti come il dispositivo di Duff non diventano legali), ma possiamo occuparcene (un'altra funzione auto-eseguita riscritta), giusto?


1
Dolce! Bel lavoro e semplice. Una curiosità interessante: se gotofossero stati implementati completamente in JavaScript (a cui si poteva usare gotoper saltare fuori da qualsiasi ambito, anche una funzione ), implicherebbe il supporto per le continuazioni.
Joey Adams,

22

#define in Java

Ho pensato che sarebbe stato divertente implementare macro in Java.

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("."));
    }

}

Esempio di utilizzo (converte in codice precedentemente pubblicato; rendiamolo strano):

#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
Stavo scorrendo il secondo blocco e il mio unico pensiero era "... nella tana del coniglio".
Soham Chowdhury,

18

Foreach in C

Array iterati (funziona per array statici, non per quelli ricevuti tramite puntatore)

//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++)

Per testarlo:

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);
}

risultato:

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

17

Proprietà in C.

Tomasz Wegrzanowski ha implementato le proprietà nella pianura C, confondendo intenzionalmente il programma quando si accede alla proprietà.

Un oggetto con una "proprietà" viene impostato creando un structche attraversa più pagine, garantendo che l'indirizzo di memoria della proprietà si trovi in ​​una pagina diversa dai membri dei dati reali. La pagina della proprietà è contrassegnata come non accessibile, garantendo che il tentativo di accedere alla proprietà causerà un segfault. Un gestore degli errori quindi determina quale accesso alla proprietà ha causato il segfault e chiama la funzione appropriata per calcolare il valore della proprietà, che viene memorizzato all'indirizzo di memoria della proprietà.

Il gestore degli errori contrassegna anche la pagina dei dati come di sola lettura per garantire che il valore calcolato rimanga coerente; quando si tenta in seguito di scrivere su un membro di dati, viene attivato un segfault, il cui gestore imposta la pagina di dati come lettura-scrittura e la pagina delle proprietà come non-accesso (indicando che è necessario ricalcolarlo).


15

Calcolato proveniente da Common Lisp

Inizialmente ho implementato come-from. Ma non era abbastanza buono.

Ispirato alla goto calcolata, ho deciso di implementare la provenienza calcolata.

(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)))))))))

Esempi di utilizzo

(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.

Per ogni dichiarazione di provenienza nel tagbody, verificherà su ciascuna etichetta se la variabile di origine è uguale all'etichetta corrente e, in tal caso, passa alla dichiarazione di provenienza corrispondente.

Greeter

(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

"Stringhe automatiche" in Ruby

Il codice è abbastanza semplice:

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

Adesso puoi farlo

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

Aggiungi macro a PHP

Possiamo semplicemente usare il preprocessore C per questa attività.

Uno script php:

<?php

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

function test() {
        ERROR(Oops);
}

Pipe it cpp:

cpp < test.php

Risultato:

<?php

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

Non si romperà con le funzionalità di PHP che non esistono in C? Come heredocs. Alla fine il PP C era abbastanza strettamente legato alla grammatica di C.
Joey,

1
Penso che il preprocessore lasci solo l'input senza cercare di dargli un senso. An <<<HEREDOCnon è altro che 3 spostamento inferiore o sinistro e un identificatore :-) Questo farà comunque una sostituzione macro nelle stringhe ereditarie.
Arnaud Le Blanc,

Il preprocessore C aggiunge ulteriore spazzatura all'output, quindi il tuo esempio non funzionerebbe come previsto
codardo anonimo

1
A grep -v ^#dovrebbe risolvere questo. Immagino che questo sia sufficiente per questa domanda :-)
Arnaud Le Blanc

10

Guardie di corrispondenza dei motivi in Python

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

Il corpo della funzione arriva a 288 caratteri.

Le Guardie di corrispondenza dei modelli consentono di utilizzare funzioni completamente diverse a seconda dei valori degli argomenti. Sebbene possa essere facilmente emulato con una serie di ifistruzioni, le protezioni di corrispondenza dei modelli possono aiutare a separare sezioni di codice, ed è un'ottima scusa per fare qualche metaprogrammazione pazza.

pattern_matchè un decoratore che crea una nuova funzione che implementa protezioni di corrispondenza del modello . Le condizioni per ciascuna "sotto-funzione" fornita in ogni docstring su righe che iniziano con una pipe ( |). Se tutte le condizioni vengono valutate in modo veritiero, viene eseguita quella versione della funzione. Le funzioni vengono testate in ordine fino a quando non viene trovata una corrispondenza. Altrimenti, Noneviene restituito.

Un esempio aiuterà a chiarire:

@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

In Haskell, questo si chiama guardie , non la corrispondenza del modello. In Haskell, la corrispondenza del modello consente di dire f [a,b,c] = ..., che non solo mette alla prova l'argomento rispetto a un predicato, ma lega le rispettive variabili in caso di corrispondenza corretta. Questo è comunque piuttosto interessante.
Joey Adams,

D'oy! Grazie per averlo corretto! Stavo pensando anche a Haskell, concentrandomi in particolare sulla definizione di una funzione con due predicati diversi (ie f (x:xs) = ...e f [] = ...). In qualche modo ho contorto le guardie lì dentro, ma è lì che ho preso il |da.
zbanks

Questa non è una sfida di golf del codice; puoi essere più prolisso (e leggibile) se vuoi! :)
ReyCharles,


7

Operatori doganali a Lua

Pogs ha abusato abilmente di un sovraccarico dell'operatore a Lua per consentire la definizione di operatori di infissi personalizzati. L'ho espanso per supportare il sezionamento dell'operatore (applicando parzialmente un operatore con uno degli operandi) e chiamando l'oggetto risultante come se fosse una funzione.

---- 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

Stringhe multilinea in javascript

in questa elaborata sintassi per le stringhe multilinea, ogni stringa multilinea sarà preceduta da (function(){/*una nuova riga e seguita da una nuova riga e */}+'').split('\n').slice(1,-1).join('\n').

usando questa sintassi sorprendente e intuitiva, possiamo finalmente usare stringhe multilinea:

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!!!

per le persone a cui non piace la nostra sintassi semplice, abbiamo un compilatore per il nostro favoloso nuovo linguaggio:

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

lo stesso esempio, nella versione in lingua compilata:

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

1
Per qualche motivo non riesco a inserire le */mie stringhe multilinea. Questo è super fastidioso quando si includono regexps nelle stringhe!
FireFly

@FireFly In realtà, penso che funzioni ancora. L'evidenziazione della sintassi diventa però strana.
orgoglioso haskeller il

6

Elenco di Sliceable in C # (come Python)

Mi è sempre piaciuta la notazione slice di Python e vorrei che fosse disponibile in C #

Uso:

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)

Codice, lungi dall'essere a prova di errore:

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;
        }
    }
}

Ho richiesto molto tempo fa che il slicing fosse incluso in .NET, è ancora semplicemente ignorato :(
Ray

6

Rendi C più semplice

Questo codice consente di scrivere programmi C che somigliano un po 'di più a un linguaggio di scripting. Presenta parole chiave come "var", "is", "string", "plus", "equal" e molti altri. Funziona attraverso molte affermazioni definite.

// 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

Questo ti permette di scrivere codice come:

/*
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

Quanto sopra viene espanso in:

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);
}

Probabilmente non eccessivamente utile, ma ho trovato abbastanza interessante che potresti essenzialmente creare un intero linguaggio di programmazione attraverso un gruppo di #defines.


Sembra un mashup Javascript / Ruby ...
Decadimento beta

Non c'è praticamente nessun limite superiore a questo - con #defines abbastanza complessi , puoi persino dare al tuo linguaggio cose come la gestione delle eccezioni e la garbage collection mantenendo comunque il livello C fondamentale sottostante.
Leushenko,

5

Tcl

Tcl ha no do ... whileo do ... untilcosì ...

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
            }
        }
    }
}

Esempio:

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

uplevel esegue uno script nell'ambito dei chiamanti.


5

Vai a PostScript

Il mio primo pensiero è stato che avrei dovuto scherzare con lo stack exec, quindi questo falso inizio scava l'operatore di continuazione per fermarsi da ghostscript (o xpost).

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

Ma è più semplice di così. Poiché la posizione del file è la stessa per tutti i duplicati dell'handle del file ( setfilepositionconsuma il suo argomento, quindi questa è l'unica semantica utile per quella funzione).

/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 =

Stampa 5 .

Vi sono alcune limitazioni con quanto sopra. Il salto non è immediato, ma si verifica quando l'if-body torna al livello superiore e l'interprete sta di nuovo leggendo dal file (invece di leggere dall'array che contiene l'if-body). A quel punto, il file è stato riposizionato e il 'goto' ha effetto.


Ed è solo una definizione in un dizionario, quindi puoi usare quasi tutti i tipi per le etichette.
Luser droog

Puoi anche eseguire salti assoluti con currentfile <pos> setfileposition, contando i byte dall'inizio del file.
Luser droog,

4

Symbol#to_proc con argomenti in Ruby

Symbol#to_procè probabilmente uno dei miei trucchi preferiti per scrivere codice Ruby davvero succinto. Supponi di avere

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

e vuoi convertire il contenuto di numse textin float e parole maiuscole, rispettivamente. Symbol#to_procti permette di abbreviare il codice in questo modo:

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

a questo:

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

Eccezionale! E se volessimo elevare ogni elemento numsal ipotere th, o sostituire ogni ricorrenza di scon *in text? C'è un modo per abbreviare il codice in questo modo?

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

Purtroppo, non esiste un modo semplice per passare argomenti durante l'utilizzo Symbol#to_proc. L'ho visto in diversi modi, ma probabilmente due dei più intelligenti e utilizzabili riguardano l'applicazione di patch per scimmie alla Symbolclasse [ 1 , 2 ]. Illustrerò il primo modo di seguito.

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

Ora puoi fare cose come:

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

3

JavaScript foreach

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);

Produzione

Seattle, WA
New York, NY
Chicago, IL

Sintassi alternativa, più simile a 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);
});

Questa non è una semplice ricerca, ma è più interessante. Ispeziona l'elenco degli argomenti della funzione che consuma. Potresti andare oltre con questo trucco e fare cose davvero interessanti.
Joey Adams,

1
Stavo cercando una foreach in stile Tcl. Ho aggiunto un approccio leggermente diverso che è più simile a Tcl.
Wolfolfer,

2

Gotos a Haskell

l'idea di base è che le goto possono essere parzialmente simulate usando l'ultima affermazione in do-notations. per esempio:

main = do
  loop:
  print 3
  goto loop

è equivalente a

main = do
  loop
loop = do
  print 3
  loop

poiché l'esecuzione salterà all'ultima affermazione, è ottimale esprimere goto.

perché nel modo in cui viene fatto, gotos salta solo quando si trovano direttamente nel doblocco di una definizione di livello superiore. in realtà è "chiama x e ignora il resto delle istruzioni viste lessicamente " piuttosto che "tutte x e ignora il resto delle dichiarazioni", come un vero goto.

il problema più grande è che quando non c'è modo di lasciare l'esecuzione nel mezzo di un'azione di I / O, anche returnno; returnnon fa nulla quando non è l'ultima affermazione.

questo lo supera catturando il resto delle dichiarazioni da un altro doblocco.

goto loop
print 3

diventa

const loop $ do
print 3

l' print 3istruzione viene acquisita dal doblocco, quindi loopdiventa l'ultima istruzione.

questa trasformazione supporta anche le variabili presenti nell'ambito delle azioni. questo viene fatto ricordando le variabili che sono nell'ambito e passandole nelle azioni. per esempio:

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

questo si traduce semplicemente in:

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

alcune note:

anche un return undefined viene aggiunta un'istruzione per garantire che il doblocco di acquisizione non sia vuoto.

perché a volte c'è un'ambiguità di tipo nel doblocco di acquisizione , invece di constusarloasTypeOf , che è lo stesso di constma richiede che entrambi i suoi parametri abbiano lo stesso tipo.

l'implementazione effettiva (in 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
            }
        })
}

un esempio:

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

diventa:

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

produzione:

a
c

Vale la pena chiarire che returnin Haskell è una funzione regolare e non correlata alla parola chiave in C / etc.
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)

uso

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

Caso di prova del campione

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

print "Asdf"

Esempio di output del test case

Asdf

Solo un po 'di divertimento con exec (). Può generare un errore di profondità massima di ricorsione se non utilizzato correttamente.


-2

// importa javascript senza usare in modo specifico il tag script in una pagina HTML

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

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

È zoppo sì, lo so. Lunghezza: 99


@ user2509848: questa discussione non è taggata con codice golf.
Joey Adams,

Ciò che hai pubblicato richiede scripttag intorno ad esso. Allora dov'è esattamente la nuova funzionalità?
arte

@JoeyAdams Spiacenti.
Hosch250,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.