Bir programlama diline bir özellik ekleyin [kapalı]


55

Göreviniz bir programlama dili için, çok akıllı bir kütüphane uygulayarak veya giriş metnini işleyerek ve / veya derleme işlemini ayarlayarak bir özelliği ele almaktır.

fikirler:

  • PHP'ye serpiştirme sunumunu C'ye (örn. <?c printf("Hello,"); ?> world!) Ekleyin .
  • Boş bir birleştirme işleci C # olmayan dillerden birine ekleyin .
  • PHP'ye makrolar ekleyin.
  • gotoJavaScript'e ekle .
  • X diline kalıp eşleştirme ekleyin
  • Sahip olmayan bir dile isim alanı desteği ekleyin.
  • C'yi PHP gibi görünmesini sağlayın.
  • Haskell'i Pascal gibi göster.
  • ... (yorum bölümüne fikir göndermekten çekinmeyin)

Kurallar:

  • Masaya bir şey getir. Sadece Haskell'e metaprogramlama olanakları eklemek için "Şablon Haskell" deme. Bu StackOverflow değil.
  • Tüm uygulama bir ekrana sığmalıdır (örneği saymaz).
  • Kodu özellikle bu görev için harici bir sitede barındırmayın.
  • En etkileyici ya da şaşırtıcı özellik kazanır.

Özelliği% 100 doğru uygulamak konusunda endişelenmeyin. Ne münasebet! Asıl zorluk, ne yapmak istediğinizi bulmak ve planlı girişiminiz uygulanabilir hale gelinceye kadar ayrıntılara şiddetle uymamak.

Örnek:

C programlama diline bir lambda operatörü ekleyin .

İlk yaklaşım:

Tamam, libgc kullanmak istediğimi biliyorum, böylece lambdalarım yukarı ve aşağı funarg sorunlarını çözecek. Sanırım yapmam gereken ilk şey C programlama dili için bir ayrıştırıcı yazmak / bulmak, sonra da C'nin tip sistemi hakkında her şeyi öğrenmem gerekiyor. Türler kadarıyla nasıl bir anlam çıkaracağını bulmak zorunda kalacağım. Tip çıkarımı yapmam gerekir mi yoksa basitçe formal parametrenin verildiği gibi yazılmasını mı talep etmeliyim? Peki ya CI’daki şu çılgın özellikler henüz bilmiyor?

C'ye lambda'yı doğru uygulamanın çok büyük bir girişim olacağı açıktır . Doğruluğunu unut! Basitleştirin, basitleştirin.

Daha iyi:

İhtiyacı olan yukarı hunileri boşver. GNU C'nin iç içe geçmiş işlevleri ve deyim ifadeleri ile zor bir şey yapabilirim . C'de şaşkın ve sahte kod ile inanılmaz bir sözdizimsel dönüşüm göstermek istedim, ancak bunun için bir çözümleyiciye bile ihtiyacım olmayacak. Başka bir gün bekleyebilir.

Sonuç (GCC gerektirir):

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

Bu kolaydı, değil mi? mapKullanışlı ve güzel olması için bir makroya bile attım .


10
Bence Ken Thompson hepimizi yendi : 0 bayt kodu.
dmckee

4
Tam bir cevap oluşturmak istemiyorum ama birinin ilgisini çekmesi durumunda GNU C'ye dersler ekledim .
Richard J. Ross III

3
Bunun uygun olup olmadığından emin değilim, ancak C’de süreklilik örneği yazdım . Yine de, bir ekrandan biraz daha fazlası.
kullanıcısı

1
Bu soruyu dirilten herkese teşekkürler; Gönderim için mükemmel bir fikrim var.
Jonathan Van Matre

2
C'ye bir lambda ekle ... hey bana öyle bakma.
Leushenko

Yanıtlar:


27

Haskell'de OOP sözdizimi

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

Nesnelerin özellikleri olabilir:

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

... ve yöntemler:

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

2
Bir yerlerde bu operatörü şöyle yazıp bunun &gibi tanımladım (&) = flip ($).
homoseksüel

6
@swish Kullanmamıştım &çünkü 'tek adresli operatörün adresi' (Haskell'deki işaretçilerin uygulanması okuyucu için bir alıştırma olarak kaldı).
lortabac

1
@swish kullanarak bir karakteri (ve bir beyin döngüsünü) kaydedebilirsinizflip id
Sean D

24

goto JavaScript’te

Benim ilk düşüncem fonksiyonel bir yaklaşımdı - fonksiyonun yerine geri dönüş değerini tekrar tekrar çağıran bir switchdeyim ve bir dış döngü ile bunu kullanarak uygulamanın nerede başlayacağını gösterecek bir parametre eklemek . Ne yazık ki, yerel değişkenlerin kullanımını engelleyecektir, çünkü her goto ile değerlerini kaybedeceklerdir.

Kullanabilirim with ifade ve tüm değişken bildirimlerini işlevin başlangıcına taşıyabilirdim, ancak daha iyi bir yol olması gerekiyordu. Sonunda JavaScript'in istisna işleme kullanmak bana geldi . Aslında, Joel Spolsky, "İstisnaların" gitmekten daha iyi "olmadığını düşünüyorum - açıkçası mükemmel bir uyum.

Buradaki amaç, sadece bir returnifade veya yakalanmamış bir istisna ile sonlandırılan bir fonksiyonun içine sonsuz bir döngü koymaktı . İstisnalar olarak kabul edilen tüm goto'lar, sona ermesini önlemek için ilmeğe takılır. İşte bu yaklaşımın sonucu:

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

Internet Explorer ( demo ) hariç, bu şekilde kullanabilirsiniz - ES5 sıkı modunda bile -

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

[Internet Explorer, nedense, isimsiz bir işlevin kodunu değerlendirmekte başarısız olur, bu nedenle işleve bir isim vermek (yeniden yazmadan önce) ve bu ismi kullanarak çağırmak gerekir. Tabii ki, bu büyük olasılıkla katı modun kurallarına aykırı olurdu.]

Bu, bir bloğun içinde bulunan bir cümleye atlamaya izin vermez (Duff'un aygıtı gibi yasal olana kadar), ancak bununla başa çıkabiliriz (başka, kendi kendine çalışan yeniden yazılmış bir işlev), değil mi?


1
Tatlı! Güzel iş basit tutmak. İlginç bir bilgi: gotoJavaScript’te tam olarak uygulandıysa goto(herhangi bir kapsamdan, hatta bir işlevden çıkmak için kullanabileceğiniz ), süreklilik için destek anlamına gelir.
Joey Adams,

22

#define Java’da

Java'da makroları uygulamanın eğlenceli olacağını düşündüm.

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

}

Örnek kullanım (daha önce yayınlanan koda dönüştürür; garip hale getirelim):

#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
İkinci blokta ilerliyordum ve tek düşüncem "tavşan deliğinden aşağıya" oldu.
Soham Chowdhury

18

C Foreach

Sıralı diziler

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

Test etmek için:

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

sonuç:

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

17

C'deki Özellikler

Tomasz Wegrzanowski kasıtlı olarak segfaulting yaparak C ovasındaki özellikleri uygulamaya koydu. , mülklere erişildiğinde programı .

"Özelliği" olan bir nesne, structbirden fazla sayfayı geçen ve özelliğin hafıza adresinin gerçek veri üyelerinden farklı bir sayfada yer almasını sağlayan bir tane oluşturarak kurulur . Özelliğin sayfası, erişimsiz olarak işaretlenmiştir ve bu özelliğe erişmeye çalışılmasının segfault'a neden olacağını garanti eder. Bir hata işleyicisi daha sonra hangi özellik erişiminin segfault'a neden olduğunu tespit eder ve özelliğin hafıza adresinde saklanan özelliğin değerini hesaplamak için uygun işlevi çağırır.

Hata işleyicisi, hesaplanan değerin tutarlı kalmasını sağlamak için veri sayfasını salt okunur olarak işaretler; Bir veri üyesine daha sonra yazmaya çalıştığınızda, bu durum işleyiciyi veri sayfasını okuma-yazma ve özellik sayfasını erişimsiz olarak (yeniden hesaplanması gerektiğini belirtir) ayarlayan bir segfault'u tetikler.


15

Common Lisp'ten hesaplanan gelir

İlk başta gelenleri uyguladım. Ama bu yeterince iyi değildi.

Bilgisayarlı goto ilham, bilgisayarlı gel-gel uygulamaya karar verdim.

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

Kullanım örnekleri

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

Tagbody adresindeki her bir gelen bildirim için, gelen değişkenin geçerli etikete eşit olup olmadığını her etikette kontrol eder ve öyleyse ilgili gelen bildirime atlar.

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

Ruby'de "Otomatik dizeler"

Kod oldukça basit:

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

Şimdi yapabilirsin

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

PHP'ye makro ekle

Bu işlem için C önişlemcisini kullanabiliriz.

Bir php betiği:

<?php

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

function test() {
        ERROR(Oops);
}

Cpp olsa boru:

cpp < test.php

Sonuç:

<?php

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

Bu, C'de bulunmayan PHP özelliklerinden kopmaz mı? Heredocs gibi. C PP, C'nin gramerine sıkı sıkıya bağlıydı.
Joey

1
Sanırım önişlemci, girişi anlamayı denemeden sadece girdilere karşı çıkıyor An <<<HEREDOC, sola kayma değerinden 3 veya daha düşük bir kayma olan bir şey değildir ve bir tanımlayıcı :-) Bu, heredoc dizelerinde makro-sübstitüsyon yapar.
Arnaud Le Blanc

C önişlemcisi çıkışa fazladan çöp ekler, bu nedenle örneğiniz beklendiği gibi çalışmaz
anonim korkak 9

1
Bunu bir grep -v ^#tamir edebilirdi. Sanırım bu, bu soru için yeterliydi :-)
Arnaud Le Blanc

10

Python'daki Desen Eşleştirme Muhafızları

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

Fonksiyonun gövdesi 288 karakterde gelir.

Desen Eşleştirme Koruyucuları, argüman değerlerine bağlı olarak tamamen farklı fonksiyonlar kullanmanıza izin verir. Bir dizi ififadeyle kolayca taklit edilebilse de , desen eşleştirme korumaları kod bölümlerini ayırmaya yardımcı olabilir ve bazı çılgın metaprogramlama yapmak için harika bir bahane.

pattern_matchdesen eşleştirme korumalarını uygulayan yeni bir fonksiyon yaratan bir dekoratördür . Her bir dokümanda verilen her "alt işlev" koşulları bir pipe ( |) ile başlayan satırlarda . Tüm koşullar doğru değerlendirilirse, fonksiyonun bu sürümü çalıştırılır. İşlevler bir eşleşme bulunana kadar sırayla test edilir. Aksi takdirde Noneiade edilir.

Bir örnek netleşmeye yardımcı olacaktır:

@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

Haskell'de buna örüntü eşleme değil, gardiyan denir . Haskell'de, desen eşleştirmesi f [a,b,c] = ..., yalnızca argümanı bir yükleme karşı sınamakla kalmaz, aynı zamanda başarılı eşleşmelerde ilgili değişkenleri bağladığını söyler . Bu yine de oldukça havalı.
Joey Adams

D'oy! Düzeltdiğin için teşekkürler! Haskell'i de düşünüyordum, özellikle iki farklı yordamla (yani f (x:xs) = ...ve f [] = ...) bir işlevi tanımlamaya odaklandım . Her nasılsa gardiyanları oraya topladım, ama oradan aldım |.
zbanks

Bu bir kod golf mücadelesi değil; İsterseniz daha ayrıntılı (ve okunabilir) olabilir! :)
ReyCharles 16:14


7

Lua konumundaki Gümrük operatörleri

Domuzlar , özel giriş operatörlerinin tanımlanabilmesi için Lua'da operatörün aşırı yüklenmesini akıllıca kötüye kullandı . Bunu operatör bölümlemesini (kısmen her iki işlemciye sahip bir operatörü uygulayarak) desteklemek ve elde edilen nesneyi bir işlevmiş gibi çağırmak için genişlettim.

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

Javascript'te çok satırlı dizeler

Çok satırlı dizgiler için bu ayrıntılı sözdiziminde, her çok satırlı dizgiden önce (function(){/*ve sonra yeni bir satır gelecek , ardından yeni bir satır ve */}+'').split('\n').slice(1,-1).join('\n').

Bu şaşırtıcı, sezgisel sözdizimini kullanarak nihayet çok satırlı dizeleri kullanabiliriz:

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

Basit sözdizimimizi sevmeyen insanlar için muhteşem yeni dilin derleyicisine sahibiz:

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

Aynı örnek, derlenmiş dilde:

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

1
Bazı nedenlerden dolayı */multiline tellerime koyamıyorum . Bu dizelerde regexps dahil süper can sıkıcı!
FireFly

@FireFly Aslında, bu hala çalışıyor düşünüyorum. Syntex vurgulaması olsa garip olur.
Gurur haskeller

6

C # dilimli listesi (Python gibi)

Python'un dilim gösterimini her zaman çok sevdim ve keşke C # 'da mevcut olsaydı

Kullanımı:

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, hatasız olmaktan uzak:

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

Uzun süre önce .NET'e dahil olmak için dilimleme talebinde bulundum, hala basitçe göz ardı ediliyor :(
Ray

6

C'yi daha basit hale getirin

Bu kod, bir kodlama diline benzeyen C programları yazmanıza izin verir. 'Var', 'is', 'string', 'plus', 'eşit' ve diğerleri gibi anahtar kelimeler içerir. Bu yoluyla çalışır bir çok ifadeleri tanımlamak ait.

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

Bu, şöyle bir kod yazmanıza izin verir:

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

Yukarıdakilere genişletildi:

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

Muhtemelen aşırı derecede kullanışlı değil, ancak temelde bütün bir programlama dilini bir demet aracılığıyla oluşturabilmenizi oldukça ilginç buldum #define.


Javascript / Ruby mashup'a benziyor ...
Beta Decay

Bunun üst sınırı yok. Yeterince karmaşık olanı #definekullanarak , temel C katmanını hala altında tutarken, dilinize istisna yönetimi ve çöp toplama gibi şeyler bile verebilirsiniz .
Leushenko

5

Tcl

Tcl hiçbir vardır do ... whileya do ... untilöylesine ...

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

Örnek:

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

uplevel arayanlar kapsamında bir komut dosyası yürütür.


5

PostScript'te Goto

İlk düşüncem, exec yığınıyla uğraşmak zorunda kalacağımdı, bu yüzden bu yanlış başlangıç, sürdürme operatörünü ghostscript (veya xpost) 'dan durması için kazıyor.

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

Ancak, bundan daha basit. Dosya konumu, dosya tanıtıcısının tüm kopyaları için aynı olduğundan ( setfilepositionbağımsız değişkenini kullanır, bu nedenle bu işlev için tek yararlı anlamdır).

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

Basar 5.

Yukarıdakilerle ilgili bazı sınırlamalar vardır. Atlama hemen gerçekleşmez, ancak if-body en üst seviyeye döndüğünde ve yorumlayıcı tekrar dosyadan okuduğunda (if-body içeren diziden okumak yerine) gerçekleşir. Bu noktada, dosya yeniden konumlandırıldı ve 'goto' etkili oldu.


Ve bu sadece sözlükteki tanımlar, böylece etiketler için hemen hemen her tipi kullanabilirsiniz.
kullanıcısı

Ayrıca , dosyanın başındaki baytları sayarak mutlak atlamalar da yapabilirsiniz currentfile <pos> setfileposition.
luser droog

4

Symbol#to_proc Ruby'de argümanlarla

Symbol#to_procMuhtemelen gerçekten özlü Ruby kodunu yazmak için en sevdiğim numaralardan biri. Varsayalım

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

ve içeriğini dönüştürmek istediğiniz numsve textsırasıyla Şamandıralar ve büyük harf kelimelere. Symbol#to_procBu gibi kodları kısaltmanıza izin verir:

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

buna:

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

Korku veren! Ama biz her eleman yetiştirmek ne isterseniz numsiçin iinci gücün veya her geçtiği yerini sile *de text? Böyle bir kodu kısaltmanın bir yolu var mı?

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

Ne yazık ki, kullanırken değişkenleri iletmenin kolay bir yolu yok Symbol#to_proc. Bunun birçok yolla yapıldığını gördüm, ancak muhtemelen en zeki ve kullanılabilir olanlardan ikisi, Symbolsınıftaki maymun yamalarını içerir [ 1 , 2 ]. Aşağıdaki ilk yolu açıklayacağım.

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

Şimdi şöyle şeyler yapabilirsiniz:

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

Çıktı

Seattle, WA
New York, NY
Chicago, IL

Alternatif sözdizimi, Tcl gibi.

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

Bu basit bir konuşma değil, ama daha ilginç. Tüketici fonksiyonunun argüman listesini inceler. Bu numara ile daha ileri gidebilir ve gerçekten harika şeyler yapabilirsiniz.
Joey Adams

1
Herşey için bir Tcl tarzı için gidiyordum. Tcl'ye daha çok benzeyen biraz farklı bir yaklaşım ekledim.
wolfhammer

2

Haskell'de Gotolar

temel fikir, gotos ifadelerinin son ifadesi kullanılarak kısmen simüle edilebileceğidir do. Örneğin:

main = do
  loop:
  print 3
  goto loop

eşittir

main = do
  loop
loop = do
  print 3
  loop

yürütme son ifadeye atlayacağından, artıkları ifade etmek en uygunudur.

çünkü bu şekilde yapılır, gotos sadece dodoğrudan bir üst seviye tanımlamasının blokundayken atlar . aslında "x" olarak adlandırılır ve "tüm x ve" ifadelerin geri kalanını yoksay "yerine gerçek bir goto gibi," sözcük olarak görülen ifadelerin geri kalanını yoksay "dır .

En büyük sorun şudur ki, yürütmeyi IO eyleminin ortasından terk etmenin bir yolu yoktur - returnöyle değil;returnson ifade olmadığında hiçbir şey yapmaz.

bu, ifadelerin geri kalanını başka bir doblok tarafından yakalayarak bunu ortadan kaldırır .

goto loop
print 3

olur

const loop $ do
print 3

print 3deyimi ile yakalanır doböylece bloğun loopson deyimi haline gelir.

Bu dönüşüm aynı zamanda eylemler kapsamında var olan değişkenleri de destekler. bu, kapsamdaki değişkenleri hatırlayarak ve bunları eylemlere geçirerek yapılır. Örneğin:

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

Bu sadece çevirir:

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

bazı notlar:

ayrıca, return undefinedyakalama dobloğunun boş olmadığından emin olmak için bir ifade eklenir .

çünkü bazen yakalama dobloğunda tip belirsizliği vardır, constbiz kullanmak yerine asTypeOf, aynı olan constancak her iki parametresinin de aynı tipte olmasını gerektiren kullanın.

fiili uygulama (javascript ile):

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

bir sınav:

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

dönüşür:

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

çıktı:

a
c

returnHaskell'de normal bir işlev olduğunu ve C / etc anahtar sözcüğüyle ilgisiz olduğunu açıklığa kavuşturmak faydalı olacaktır .
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)

kullanım

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

Örnek Test Durumu

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

print "Asdf"

Örnek Test Kılıfı Çıkışı

Asdf

Exec () ile sadece biraz eğlenceli. Doğru kullanılmazsa, maksimum yineleme derinliği hatası verebilir.


-2

// HTML sayfasındaki script etiketini kullanmadan javascript'i içe aktarın

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

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

Bu topal evet biliyorum. Uzunluk: 99


@ user2509848: Bu konu golf kodu olarak etiketlenmemiş.
Joey Adams

Gönderdiğiniz şey scriptetrafında etiket gerektirir . O zaman yeni özellik tam olarak nerede?
Manat çalışması

@JoeyAdams Üzgünüz, üzgünüz.
Hosch250,
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.