Tambahkan fitur ke bahasa pemrograman [tertutup]

55

Tugas Anda adalah untuk menempelkan fitur ke bahasa pemrograman, baik dengan menerapkan pustaka yang sangat pintar, atau dengan memproses teks input dan / atau mengubah proses kompilasi.

Ide ide:

  • Tambahkan presentasi PHP-style interleaving ke C (mis <?c printf("Hello,"); ?> world!).
  • Tambahkan operator penggabungan nol ke salah satu bahasa yang bukan C #.
  • Tambahkan makro ke PHP.
  • Tambahkan gotoke JavaScript.
  • Tambahkan pencocokan pola ke bahasa X.
  • Tambahkan dukungan namespace ke bahasa yang tidak memilikinya.
  • Buat C terlihat seperti PHP.
  • Buat Haskell terlihat seperti Pascal.
  • ... (jangan ragu untuk mengirim ide di bagian komentar)

Aturan:

  • Bawa sesuatu ke meja. Jangan hanya mengatakan "Templat Haskell" untuk menambahkan fasilitas metaprogramming ke Haskell. Ini bukan StackOverflow.
  • Seluruh implementasi harus sesuai dalam satu layar penuh (tidak termasuk contoh).
  • Jangan meng-host kode di situs eksternal khusus untuk tugas ini.
  • Fitur yang paling mengesankan atau mengejutkan menang.

Jangan khawatir tentang penerapan fitur 100% dengan benar. Jauh dari itu! Tantangan utama adalah mencari tahu apa yang ingin Anda lakukan dan dengan kejam memotong detail sampai usaha yang Anda rencanakan menjadi layak.

Contoh:

Tambahkan operator lambda ke bahasa pemrograman C.

Pendekatan awal:

Oke, saya tahu saya ingin menggunakan libgc sehingga lambda saya akan memecahkan masalah funarg ke atas dan ke bawah. Saya kira hal pertama yang perlu saya lakukan adalah menulis / menemukan parser untuk bahasa pemrograman C, maka saya harus belajar semua tentang sistem tipe C. Saya harus mencari cara untuk memahami sejauh jenis pergi. Apakah saya perlu menerapkan inferensi tipe, atau haruskah saya meminta agar parameter formal diketik seperti yang diberikan? Bagaimana dengan semua fitur gila di CI yang belum Anda ketahui?

Cukup jelas bahwa mengimplementasikan lambda di C dengan benar akan menjadi usaha yang sangat besar. Lupakan kebenaran! Sederhanakan, sederhanakan.

Lebih baik:

Persetan funargs ke atas, siapa yang butuh mereka? Saya mungkin bisa melakukan sesuatu yang rumit dengan fungsi bersarang GNU C dan ekspresi pernyataan . Saya ingin memamerkan transformasi sintaksis yang luar biasa pada C dengan kode pendek, kasar, tetapi saya bahkan tidak perlu parser untuk ini. Itu bisa menunggu satu hari lagi.

Hasil (membutuhkan 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;
}

Itu mudah, bukan? Saya bahkan melempar mapmakro untuk membuatnya berguna dan cantik.

Joey Adams
sumber
10
Saya pikir Ken Thompson telah mengalahkan kita semua : 0 byte kode.
dmckee
4
Saya tidak ingin membuat jawaban lengkap, tetapi saya telah menambahkan kelas ke GNU C , kalau-kalau ada yang tertarik.
Richard J. Ross III
3
Tidak yakin apakah memenuhi syarat ini, tapi saya sudah menulis contoh lanjutan di C . Sedikit lebih dari satu layar penuh.
luser droog
1
Terima kasih saya kepada siapa pun yang menghidupkan kembali pertanyaan ini; Saya punya ide bagus untuk kiriman saya.
Jonathan Van Matre
2
Tambahkan lambda ke C ... hei jangan lihat aku seperti itu.
Leushenko

Jawaban:

27

Sintaks OOP di Haskell

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

Objek dapat memiliki properti:

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

... dan metode:

"Hello world!".take(5) -- "Hello"
"Hello world!".splitAt(2) -- ("He","llo world!")
"Hello world!".map(toUpper) -- "HELLO WORLD!"
lortabac
sumber
2
Di suatu tempat saya melihat operator ini ditulis &dan didefinisikan seperti ini (&) = flip ($).
desir
6
@ harap saya tidak menggunakan &karena itu adalah 'alamat-dari' operator unary (implementasi pointer di Haskell dibiarkan sebagai latihan untuk pembaca).
lortabac
1
@ harap Anda dapat menyimpan karakter (dan siklus otak) dengan menggunakanflip id
Sean D
24

goto dalam JavaScript?

Pikiran pertama saya adalah pendekatan fungsional - untuk menambahkan parameter ke fungsi untuk menunjukkan di mana eksekusi harus dimulai, menggunakannya dengan switchpernyataan dan loop luar berulang kali memanggil fungsi pada nilai kembali sendiri . Sayangnya, itu akan menghalangi penggunaan variabel lokal, karena mereka akan kehilangan nilainya dengan setiap kebohongan.

Saya bisa menggunakan withpernyataan dan memindahkan semua deklarasi variabel ke awal fungsi, tetapi harus ada cara yang lebih baik. Akhirnya saya sadar untuk menggunakan penanganan pengecualian JavaScript . Bahkan, Joel Spolsky berkata, "Saya menganggap pengecualian tidak lebih baik daripada" goto ... " - jelas sangat cocok.

Idenya adalah untuk menempatkan loop tak terbatas di dalam suatu fungsi, diakhiri hanya dengan returnpernyataan atau pengecualian tanpa tertangkap. Semua foto, diperlakukan sebagai pengecualian, akan ditangkap dalam loop untuk mencegah penghentiannya. Inilah hasil dari pendekatan itu:

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

Anda dapat menggunakannya seperti ini - bahkan dalam mode ketat ES5 - kecuali di 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, karena suatu alasan, gagal untuk mengevaluasi kode fungsi anonim, jadi orang harus memberi fungsi nama (sebelum menulis ulang) dan menyebutnya dengan menggunakan nama itu. Tentu saja, itu mungkin akan melanggar aturan mode ketat.]

Ini tidak memungkinkan melompat ke pernyataan yang terletak di dalam blok (sampai konstruksi seperti perangkat Duff menjadi legal), tetapi kita dapat mengatasinya (fungsi menulis ulang yang dijalankan sendiri), kan?

Tolong berdiri
sumber
1
Manis! Pekerjaan yang bagus menjaganya tetap sederhana. Sedikit hal-hal sepele yang menarik: jika gotoditerapkan sepenuhnya dalam JavaScript (ke tempat Anda dapat menggunakan gotountuk melompat keluar dari ruang lingkup apa pun, bahkan suatu fungsi ), itu akan menyiratkan dukungan untuk kelanjutan.
Joey Adams
22

#define di Jawa

Saya pikir akan menyenangkan untuk mengimplementasikan makro di Jawa.

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

}

Contoh penggunaan (konversi ke kode yang diposting sebelumnya; mari buat ini aneh):

#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@[email protected]`r`&R`~&`r;
$%p@[email protected]`r`&Wr$t`r;
$%p@[email protected]$l`;
$%p@[email protected]$l`R`~&`r;
$%p@[email protected]$l`Wr$t`r;
$%p@[email protected]`pt$@n;
$%[email protected]~yL$st;
$%[email protected]@gg$ng.L`v`l;
$%[email protected]@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;
    _

_
Justin
sumber
7
Saya sedang menggulir blok kedua, dan satu-satunya pikiran saya adalah "... menyusuri lubang kelinci."
Soham Chowdhury
18

Pejuang di C

Iterate array (berfungsi untuk array statis, bukan array, diterima melalui pointer)

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

Untuk mengujinya:

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

hasil:

num=10
num=20
num=30
str=Hello
str=World
str=Foreach
str=Test
Nuklir
sumber
17

Properti dalam C

Tomasz Wegrzanowski mengimplementasikan properti di plain C, dengan sengaja memisahkan program ketika properti diakses.

Objek dengan "properti" diatur dengan membuat structyang melintasi beberapa halaman, memastikan bahwa alamat memori properti terletak di halaman yang berbeda dari anggota data nyata. Halaman properti ditandai sebagai tidak ada akses, menjamin bahwa upaya untuk mengakses properti akan menyebabkan segfault. Penangan kesalahan kemudian mencari tahu akses properti mana yang menyebabkan segfault, dan memanggil fungsi yang sesuai untuk menghitung nilai properti, yang disimpan di alamat memori properti.

Penangan kesalahan juga menandai halaman data sebagai hanya-baca untuk memastikan nilai yang dihitung tetap konsisten; ketika Anda selanjutnya mencoba menulis ke anggota data, yang memicu segfault, yang penangannya mengatur halaman data sebagai baca-tulis dan halaman properti sebagai tidak ada akses (menunjukkan bahwa itu perlu dihitung ulang).

Siput mekanik
sumber
15

Dihitung berasal dari Common Lisp

Awalnya saya menerapkan asal-usul. Tapi itu tidak cukup baik.

Terinspirasi oleh goto yang dihitung, saya memutuskan untuk menerapkan komputasi yang berasal.

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

Contoh penggunaan

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

Untuk setiap deklarasi berasal di tagbody, itu akan memeriksa pada setiap label jika variabel berasal dari sama dengan label saat ini, dan jika demikian, lompat ke deklarasi asal-datang yang sesuai.

Lebih ramah

(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")))
Erik Haliewicz
sumber
14

"Auto-string" di Ruby

Kode ini cukup sederhana:

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

Sekarang kamu bisa melakukannya

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!
Gagang pintu
sumber
14
wat
undergroundmonorail
13

Tambahkan makro ke PHP

Kita bisa menggunakan preprosesor C untuk tugas ini.

Script php:

<?php

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

function test() {
        ERROR(Oops);
}

Pipa itu melalui cpp:

cpp < test.php

Hasil:

<?php

function test() {
 trigger_error("Oops", E_USER_ERROR);
}
Arnaud Le Blanc
sumber
Tidakkah itu akan putus dengan fitur PHP yang tidak ada di C? Seperti heredocs. Setelah C PP itu terikat erat dengan tata bahasa C.
Joey
1
Saya pikir preprocessor hanya memasukkan input tanpa mencoba memahaminya. An <<<HEREDOCtidak lebih dari 3 shift bawah atau kiri dan pengidentifikasi :-) Ini akan melakukan substitusi makro dalam string heredoc.
Arnaud Le Blanc
Preprosesor C menambahkan sampah tambahan ke output, jadi contoh Anda tidak akan berfungsi seperti yang diharapkan
pengecut anonim
1
Seorang yang harus grep -v ^#memperbaikinya. Saya kira ini sudah cukup untuk pertanyaan ini :-)
Arnaud Le Blanc
10

Penjaga Pola Pencocokan dengan 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

Tubuh fungsi datang pada 288 karakter.

Pelindung Pencocokan Pola memungkinkan Anda menggunakan fungsi yang sama sekali berbeda tergantung pada nilai argumen. Meskipun dapat dengan mudah ditiru dengan serangkaian ifpernyataan, penjaga yang cocok dengan pola dapat membantu bagian kode yang terpisah, dan itu adalah alasan yang bagus untuk melakukan beberapa pemrograman metafila.

pattern_matchadalah dekorator yang menciptakan fungsi baru yang mengimplementasikan penjaga pencocokan pola . Kondisi untuk setiap "subfungsi" yang diberikan dalam setiap dokumen pada garis yang dimulai dengan pipa ( |). Jika semua kondisi mengevaluasi dengan benar, versi fungsi itu dijalankan. Fungsi diuji secara berurutan sampai kecocokan ditemukan. Kalau tidak, Nonedikembalikan.

Contoh akan membantu memperjelas:

@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
zbanks
sumber
Di Haskell, ini disebut penjaga , bukan pencocokan pola. Di Haskell, pencocokan pola memungkinkan Anda mengatakan f [a,b,c] = ..., yang tidak hanya menguji argumen terhadap predikat, tetapi juga mengikat masing-masing variabel saat pertandingan berhasil. Ini masih cukup keren.
Joey Adams
Baik! Terima kasih telah memperbaikinya! Saya juga berpikir tentang Haskell, secara khusus berfokus pada mendefinisikan fungsi dengan dua predikat yang berbeda (yaitu f (x:xs) = ...dan f [] = ...). Entah bagaimana aku berbelit penjaga ke sana, tapi di situlah aku mengambil |dari.
zbanks
Ini bukan tantangan kode golf; Anda bisa lebih verbose (dan dapat dibaca) jika Anda mau! :)
ReyCharles
7

Coroutine

Saya tidak bisa mengambil kredit untuk ini, jadi saya sudah menandainya CW.

Coroutines in C oleh Simon Tatham

st0le
sumber
7

Operator khusus di Lua

Pogs secara cerdik menyalahgunakan overloading operator di Lua untuk memungkinkan operator infix kustom untuk didefinisikan. Saya telah memperluas ini untuk mendukung bagian operator (sebagian menerapkan operator dengan salah satu operan) dan memanggil objek yang dihasilkan seolah-olah itu adalah fungsi.

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

String multiline dalam javascript

dalam sintaks yang rumit ini untuk string multiline, setiap string multiline akan didahului dengan (function(){/*dan baris baru, dan diikuti oleh baris baru dan */}+'').split('\n').slice(1,-1).join('\n').

menggunakan sintaks yang luar biasa dan intuitif ini, akhirnya kita bisa menggunakan string multiline:

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

untuk orang-orang yang tidak menyukai sintaksis sederhana kami, kami memiliki kompiler untuk bahasa baru kami yang luar biasa:

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

contoh yang sama, dalam versi bahasa yang dikompilasi:

var string = #{
THIS IS A MULTILINE STRING
HOORAY!!!
}#;
console.log(string) // THIS IS A MULTILINE STRING
                    // HOORAY!!!
haskeller bangga
sumber
1
Untuk beberapa alasan saya tidak bisa memasukkan */string multiline saya. Ini sangat menjengkelkan saat menyertakan regexps di string!
FireFly
@ FireFly Sebenarnya, saya pikir ini masih berfungsi. Penyorotan syntex menjadi aneh.
haskeller bangga
6

Daftar Sliceable dalam C # (seperti Python)

Saya selalu menikmati notasi potongan python dan berharap itu tersedia dalam C #

Pemakaian:

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)

Kode, jauh dari bukti kesalahan:

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;
        }
    }
}
Moop
sumber
Saya meminta slicing sejak lama untuk dimasukkan ke dalam. NET, masih saja diabaikan :(
Ray
6

Jadikan C lebih sederhana

Kode ini memungkinkan Anda untuk menulis program C yang agak mirip dengan bahasa skrip. Ini menampilkan kata kunci seperti 'var', 'is', 'string', 'plus', 'equal' dan beberapa lainnya. Ia bekerja melalui banyak pernyataan yang didefinisikan.

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

Ini memungkinkan Anda untuk menulis kode seperti:

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

Di atas akan diperluas ke:

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

Mungkin tidak terlalu berguna tetapi saya merasa cukup menarik bahwa Anda pada dasarnya dapat membuat seluruh bahasa pemrograman melalui sekelompok #defines.

icedvariables
sumber
Itu terlihat seperti Javascript / Ruby mashup ...
Beta Decay
Hampir tidak ada batas atas untuk ini - dengan #defines yang cukup kompleks , Anda bahkan dapat memberikan hal-hal bahasa Anda seperti penanganan pengecualian dan pengumpulan sampah sambil tetap menjaga lapisan C fundamental di bawahnya.
Leushenko
5

Tcl

Tcl tidak do ... whileatau kurang do ... until...

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

Contoh:

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

uplevel mengeksekusi skrip dalam ruang lingkup penelepon.

Johannes Kuhn
sumber
5

Masuk dalam PostScript

Pikiran pertama saya adalah bahwa saya harus muck sekitar dengan tumpukan exec, jadi ini mulai salah menggali operator lanjutan untuk berhenti dari ghostscript (atau xpost).

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

Tapi, itu lebih sederhana dari itu. Karena posisi file sama untuk semua duplikat dari pegangan file ( setfilepositionmenggunakan argumennya, jadi ini adalah satu-satunya semantik yang berguna untuk fungsi itu).

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

Mencetak 5 .

Ada beberapa batasan dengan hal di atas. Lompatannya tidak langsung, tetapi terjadi ketika if-body kembali ke level atas dan penerjemah membaca lagi dari file (alih-alih membaca dari array yang berisi if-body). Pada saat itu, file telah diposisikan ulang dan 'goto' mulai berlaku.

luser droog
sumber
Dan itu hanya definisi dalam kamus, sehingga Anda dapat menggunakan hampir semua jenis label.
luser droog
Anda juga dapat melakukan lompatan absolut dengan currentfile <pos> setfileposition, menghitung byte dari awal file.
luser droog
4

Symbol#to_proc dengan argumen di Ruby

Symbol#to_procmungkin salah satu trik favorit saya untuk menulis kode Ruby yang sangat singkat. Misalkan Anda punya

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

dan Anda ingin mengonversi konten dari numsdan textke Mengapung dan huruf besar, masing-masing. Symbol#to_procmemungkinkan Anda untuk mempersingkat kode seperti ini:

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

untuk ini:

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

Luar biasa! Tetapi bagaimana jika kita ingin meningkatkan setiap elemen numsmenjadi ikekuatan th, atau mengganti setiap kejadian sdengan *in text? Apakah ada cara untuk mempersingkat kode seperti ini?

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

Sayangnya, tidak ada cara mudah untuk menyampaikan argumen saat menggunakan Symbol#to_proc. Saya telah melihatnya melakukan banyak cara, tetapi mungkin dua yang paling pintar dan bisa digunakan adalah menambal monyet di Symbolkelas [ 1 , 2 ]. Saya akan menggambarkan cara pertama di bawah ini.

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

Sekarang Anda dapat melakukan hal-hal seperti:

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

JavaScript sebelumnya

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

Keluaran

Seattle, WA
New York, NY
Chicago, IL

Sintaks alternatif, lebih seperti 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);
});
wolfhammer
sumber
Ini bukan langkah awal yang sederhana, tetapi lebih menarik. Ini memeriksa daftar argumen fungsi konsumsi. Anda bisa melangkah lebih jauh dengan trik ini dan melakukan hal-hal yang sangat keren.
Joey Adams
1
Saya pergi untuk foreach gaya Tcl. Saya telah menambahkan pendekatan yang sedikit berbeda yang lebih mirip Tcl.
wolfhammer
2

Gotos di Haskell

ide dasarnya adalah gotos dapat disimulasikan sebagian menggunakan pernyataan terakhir di do -notations. sebagai contoh:

main = do
  loop:
  print 3
  goto loop

setara dengan

main = do
  loop
loop = do
  print 3
  loop

karena eksekusi akan melompat ke pernyataan terakhir, itu optimal untuk mengekspresikan gotos.

karena cara itu dilakukan, gotos hanya melompat ketika mereka berada di doblok definisi tingkat atas secara langsung. sebenarnya "panggil x dan abaikan sisa pernyataan yang terlihat secara leksikal " daripada "semua x dan abaikan sisa pernyataan", seperti kebohongan nyata.

masalah terbesar adalah ketika tidak ada cara untuk meninggalkan eksekusi dari tengah tindakan IO - bahkan returntidak; returntidak melakukan apa-apa ketika itu bukan pernyataan terakhir.

ini mengatasi ini dengan menangkap sisa pernyataan oleh orang lain do blok .

goto loop
print 3

menjadi

const loop $ do
print 3

yang print 3pernyataan ditangkap olehdo blok, sehingga loopmenjadi pernyataan terakhir.

transformasi ini juga mendukung variabel yang hadir di lingkup tindakan. ini dilakukan dengan mengingat variabel yang ada dalam ruang lingkup, dan meneruskannya ke tindakan. sebagai contoh:

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

ini hanya diterjemahkan menjadi:

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

beberapa catatan:

juga, sebuah return undefinedpernyataan ditambahkan untuk memastikan penangkapando blok tidak kosong.

karena kadang-kadang ada tipe ambiguitas di doblok penangkap , alih-alih constkami gunakan asTypeOf, yang sama consttetapi membutuhkan kedua parameternya untuk memiliki tipe yang sama.

implementasi aktual (dalam 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
            }
        })
}

contoh:

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

menjadi:

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

keluaran:

a
c
haskeller bangga
sumber
Perlu dijelaskan bahwa returndi Haskell adalah fungsi biasa, dan tidak terkait dengan kata kunci di C / etc.
FireFly
1

Python Goto

mengerti

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)

Pemakaian

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

Contoh Uji Kasus

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

print "Asdf"

Contoh Hasil Uji Kasus

Asdf

Hanya sedikit bersenang-senang dengan exec (). Dapat meningkatkan kesalahan kedalaman rekursi maksimum jika tidak digunakan dengan benar.

globby
sumber
-2

// impor javascript tanpa menggunakan tag skrip khusus di halaman HTML

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

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

Itu timpang ya aku tahu. Durasi: 99

Mauro
sumber
@ user2509848: Utas ini bukan tag kode golf.
Joey Adams
Apa yang Anda posting memerlukan scripttag di sekitarnya. Lalu di mana tepatnya fitur baru itu?
manatwork
@ JoeyAdams Ups, maaf.
Hosch250