プログラミング言語に機能を追加する[終了]


55

あなたの仕事は、非常に巧妙なライブラリを実装するか、入力テキストを処理したり、コンパイルプロセスを微調整することによって、プログラミング言語に機能を追加することです。

アイデア:

  • PHPスタイルのプレゼンテーションインターリーブをCに追加します(例:)<?c printf("Hello,"); ?> world!
  • C#以外の言語の1つにヌル合体演算子を追加します
  • PHPにマクロを追加します。
  • gotoJavaScriptに追加します。
  • 言語Xにパターンマッチングを追加します。
  • 名前空間のサポートを持たない言語に追加します。
  • CをPHPのように見せます。
  • HaskellをPascalのように見せます。
  • ...(コメントセクションにアイデアを投稿してください)

ルール:

  • テーブルに何かを持ってきてください。Haskellにメタプログラミング機能を追加するために「テンプレートHaskell」と言うだけではありません。これはStackOverflowではありません。
  • 実装全体が1画面に収まる必要があります(例をカウントしません)。
  • このタスク専用の外部サイトでコードをホストしないでください。
  • 最も印象的または驚くべき機能が勝ちます。

機能を100%正しく実装することを心配しないでください。それからほど遠い!主な課題は、何をしたいのかを把握し、詳細慎重に切り捨てることです。、計画された事業が実行可能になるまで。

例:

ラムダ演算子を追加するCプログラミング言語にをます。

最初のアプローチ:

さて、libgcを使用して、ラムダが上向きおよび下向きfunarg問題を解決するようにしたいと思います。私が最初にやらなければならないことは、Cプログラミング言語のパーサーを記述/検索することであり、その後、Cの型システムについてすべてを学ぶ必要があると思います。型が行く限り、それを理解する方法を理解する必要があります。型推論を実装する必要がありますか、それとも単に仮パラメータを指定どおりに入力する必要がありますか CIのこれらのクレイジーな機能がまだ知らないのはどうですか?

Cでラムダを正しく実装することは大きな仕事であることは明らかです。正確さを忘れてください!簡素化、簡素化。

より良い:

上向きのfunargsをねじ込みます、誰がそれらを必要としますか?GNU Cのネストされた関数ステートメント式を使用して、トリッキーなことができるかもしれません。簡潔でハックなコードを使用して、Cでの驚くべき構文変換を披露したかったのですが、これにはパーサーも必要ありません。それは別の日を待つことができます。

結果(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;
}

それは簡単でしたね。私もに投げmap、それは便利できれいにするマクロ。



4
完全な答えを作成したくありませんが、興味がある人のために、GNU Cクラスを追加しました
リチャードJ.ロスIII

3
これが適切かどうかはわかりませんが、Cでの継続の例を書いています。ただし、画面いっぱいではありません。
luser droog 14年

1
この質問を復活させた人に感謝します。私は自分の提出に対して素晴らしいアイデアを持っています。
ジョナサンヴァンマトレ14

2
Cにラムダを追加します...そんな風に私を見ないでください。
ルーシェンコ14年

回答:


27

HaskellのOOP構文

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

オブジェクトにはプロパティを設定できます:

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

...およびメソッド:

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

2
どこかで、この演算子がこの&ように記述され定義されているのを見ました(&) = flip ($)
スウィッシュ

6
@swish &これは「address-of」単項演算子であるため、使用しませんでした(Haskellでのポインターの実装は読者の演習として残されています)。
lortabac

1
@swishを使用してキャラクター(およびブレインサイクル)を保存できますflip id
ショーンD 14

24

goto JavaScriptで?

私が最初に考えたのは、機能的なアプローチでした。switchステートメントを実行し、独自の戻り値で関数を繰り返し呼び出す外部ループを使用して、実行を開始する場所を示すパラメーターを関数に追加します。残念なことに、ローカル変数はすべてのgotoで値を失うため、ローカル変数の使用はできません。

withステートメントを使用して、すべての変数宣言を関数の先頭に移動できましたが、より良い方法が必要でした。最終的に、JavaScriptの例外処理を使用するようになりました。実際、Joel Spolsky氏は、「例外は「goto's ...」よりも優れていると考えています。明らかに完璧に適合しています。

アイデアは、関数内に無限ループを配置し、returnステートメントまたはキャッチされない例外によってのみ終了することでした。例外として扱われるすべてのgotoは、ループ内でキャッチされ、その終了を防ぎます。そのアプローチの結果は次のとおりです。

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

ES5 strictモードでも、Internet Explorer(デモ)を除き、次のように使用できます。

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

[Internet Explorerは、何らかの理由で、匿名関数のコードを評価できないため、関数に名前を付けて(書き換える前に)、その名前を使用して呼び出す必要があります。もちろん、それはおそらく厳格モードの規則を破るでしょう。]

これにより、ブロック内にあるステートメントへのジャンプは許可されません(Duffのデバイスなどの構造が合法になるまで)が、それに対処できます(別の、自己実行型の書き換えられた関数)?


1
甘い!シンプルにすてきな仕事です。おもしろい雑学:gotoJavaScriptで完全に実装された場合(関数goto、さらには任意のスコープから飛び出すために使用できる場所)、継続のサポートを意味します。
ジョーイアダムス

22

#define in Java

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

}

使用例(以前に投稿されたコードに変換します。奇妙にしましょう):

#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
私は2番目のブロックをスクロールしていましたが、私の考えは「...ウサギの穴を下る」だけでした。
ソーハムチョードリー

18

CのForeach

配列の反復(ポインターではなく静的配列で機能します)

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

テストするには:

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

結果:

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

17

Cのプロパティ

Tomasz Wegrzanowski は、プロパティへのアクセス時にプログラムを意図的にセグメンテーション違反にすることで、プレーンCでプロパティ実装しました

「プロパティ」を持つオブジェクトは、struct複数のページにまたがるを作成することにより設定され、プロパティのメモリアドレスが実際のデータメンバーとは異なるページにあることを確認します。プロパティのページはアクセス不可としてマークされ、プロパティにアクセスしようとするとセグメンテーション違反が発生することが保証されます。フォールトハンドラーは、どのプロパティアクセスがセグメンテーション違反を引き起こしたかを特定し、適切な関数を呼び出してプロパティの値を計算します。この値は、プロパティのメモリアドレスに格納されます。

また、フォールトハンドラーは、計算された値の一貫性を維持するために、データページを読み取り専用としてマークします。次にデータメンバーに書き込みをしようとすると、セグメンテーション違反がトリガーされます。セグメンテーション違反のハンドラーは、データページを読み書き可能に設定し、プロパティページをアクセスなしに設定します(再計算が必要であることを示します)。


15

Common Lispでの計算結果

最初にcome-fromを実装しました。しかし、それは十分ではありませんでした。

計算されたgotoに触発されて、計算されたcome-fromを実装することにしました。

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

使用例

(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の各come-from宣言について、各ラベルでcome-from変数が現在のラベルと等しいかどうかをチェックし、等しい場合、対応するcome-from宣言にジャンプします。

グリーター

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

FizzBu​​zz

(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の「自動文字列」

コードは非常に簡単です:

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

今、あなたはできる

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にマクロを追加する

このタスクにはCプリプロセッサを使用するだけです。

PHPスクリプト:

<?php

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

function test() {
        ERROR(Oops);
}

cppでパイプしてください:

cpp < test.php

結果:

<?php

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

これは、Cには存在しないPHPの機能を壊さないでしょうか?ヒアドキュメントなど。Afair the C PPは、Cの文法とかなり密接に結びついていました。
ジョーイ

1
プリプロセッサは、入力の意味を理解しようとせずに、入力のみを字句化すると思います。an <<<HEREDOCは3桁以下または左シフトと識別子に過ぎません:-)ただし、これはheredoc文字列のマクロ置換を行います。
アルノールブラン

Cプリプロセッサは出力に余分なガベージを追加するため、あなたの例は期待通りに動作しません
匿名

1
grep -v ^#これを修正whould。この質問にはこれで十分だと思います:
アルノールブラン

10

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

関数の本体は288文字です。

パターンマッチングガードを使用すると、引数値に応じて完全に異なる関数を使用できます。一連のコードで簡単にエミュレートできますがifステートメントで、パターンマッチングガードはコードのセクションを分けるのに役立ちます。

pattern_matchパターンマッチングガードを実装する新しい関数を作成するデコレータです。パイプで始まる行の各docstringで指定された各「サブ関数」の条件(|)で。すべての条件が真に評価されると、そのバージョンの関数が実行されます。一致が見つかるまで、関数は順番にテストされます。そうでなければ、Noneが返されます。

例は明確にするのに役立ちます:

@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では、これはパターンマッチングではなくguardsと呼ばれます。Haskellでは、パターンマッチングを使用してを指定できますf [a,b,c] = ...。これは、述語に対して引数をテストするだけでなく、一致の成功時にそれぞれの変数をバインドします。ただし、これはまだかなりクールです。
ジョーイアダムス

ドイ!それを修正してくれてありがとう!私はHaskellについても考えていました。特に、2つの異なる述語(f (x:xs) = ...およびf [] = ...)を使用して関数を定義することに焦点を当てていました。どういうわけか私はそこに警備員を巻き込みましたが、そこ|から私は連れて行きました。
-zbanks

これはコードゴルフの挑戦ではありません。必要に応じて、より詳細な(そして読みやすい)ことができます!:)
ReyCharles 14


7

Luaのカスタムオペレーター

Pogsは、カスタム中置演算子を定義できるようにするために、Lua演算子のオーバーロードを巧妙に乱用しました。これを拡張して、演算子セクショニング(いずれかのオペランドで演算子を部分的に適用する)をサポートし、結果オブジェクトをあたかも関数であるかのように呼び出すようにしました。

---- 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の複数行の文字列

複数行の文字列に対するこの手の込んだ構文では、すべての複数行の文字列の前に(function(){/*は改行と改行が付き、その後に改行とが続きます*/}+'').split('\n').slice(1,-1).join('\n')

この驚くほど直感的な構文を使用して、最終的に複数行の文字列を使用できます。

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

単純な構文が気に入らない人のために、すばらしい新しい言語のコンパイラを用意しています。

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

コンパイル言語バージョンの同じ例:

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

1
何らかの理由*/で、複数行の文字列を入力できません。文字列に正規表現を含めると、これは非常に面倒です!
FireFly

@FireFly実際、これはまだ機能していると思います。しかし、シンテックスの強調表示は奇妙になります。
誇りに思ってhaskeller 14年

6

C#のスライス可能リスト(Pythonなど)

私はいつもPythonのスライス表記を楽しんでいて、それがC#で利用可能だったらいいのに

使用法:

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)

コード、エラープルーフにはほど遠い:

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

私はずっと前にスライスを.NETに含めるように要求しましたが、それはまだ単純に無視されます:(
Ray

6

Cをもっとシンプルにする

このコードにより、スクリプト言語に少し似たCプログラムを作成できます。「var」、「is」、「string」、「plus」、「equal」などのキーワードが特徴です。それは多くの定義ステートメントを通して機能します。

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

これにより、次のようなコードを記述できます。

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

上記は次のように展開されます。

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

おそらくあまり便利ではありませんが、基本的にプログラミング言語全体を多数の#definesで作成できることは非常に興味深いことがわかりました。


それは... Javascriptを/ Rubyのマッシュアップのように見える
ベータ崩壊

上限はほとんどありません-十分に複雑な#definesで、基本的なC層を下に保ちながら、例外処理やガベージコレクションなどの言語を与えることさえできます。
ルーシェンコ14年

5

Tcl

Tclにはないdo ... whiledo ... 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
            }
        }
    }
}

例:

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

uplevel 呼び出し元のスコープでスクリプトを実行します。


5

PostScriptのGoto

最初に考えたのは、execスタックをいじる必要があるので、この誤った開始は、ゴーストスクリプト(またはxpost)から停止するための継続演算子を掘り下げることでした。

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

しかし、それはそれよりも簡単です。file-positionはファイルハンドルのすべての重複に対して同じであるため(setfileposition引数を消費するため、これがその関数の唯一の有用なセマンティクスです)。

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

印刷し5ます。

上記にはいくつかの制限があります。ジャンプは即時ではありませんが、if-bodyが最上位に戻り、インタープリターが(if-bodyを含む配列からではなく)ファイルから再度読み取りを行うときに発生します。その時点で、ファイルは再配置され、「goto」が有効になります。


そして、それは辞書内の単なる定義なので、ラベルにはほとんどすべてのタイプを使用できます。
luserのドローグ

また、ファイルの先頭からバイトをカウントして、絶対ジャンプを行うこともできcurrentfile <pos> setfilepositionます。
luserのドローグ

4

Symbol#to_proc Rubyの引数付き

Symbol#to_procはおそらく、本当に簡潔なRubyコードを書くための私のお気に入りのトリックの1つです。あなたが持っていると仮定します

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

あなたがの内容変換したいnumstext、それぞれ、フロートと大文字の単語にします。Symbol#to_proc次のようなコードを短縮できます。

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

これに:

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

驚くばかり!しかし、我々は内のすべての要素を高めるために何をしたい場合numsi乗、またはのすべての発生を置き換えるs*text?このようなコードを短縮する方法はありますか?

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

残念ながら、を使用するときに引数を渡す簡単な方法はありませんSymbol#to_proc。私はそれが複数の方法を行って見てきましたが、おそらく最も賢いと使用可能なの二人は猿パッチング伴うSymbolクラス[ 12を ]。以下に、最初の方法を示します。

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

次のようなことができます:

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

出力

Seattle, WA
New York, NY
Chicago, IL

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

これは単なるforeachではありませんが、より興味深いものです。消費関数の引数リストを検査します。このトリックをさらに進めて、本当にクールなことをすることができます。
ジョーイアダムス

1
私はTclスタイルのforeachを探していました。Tclに似た、少し異なるアプローチを追加しました。
ウルフハンマー14

2

ハスケルのゴトス

基本的な考え方は、-notationsの最後のステートメントを使用してgotoを部分的にシミュレートできるということdoです。例えば:

main = do
  loop:
  print 3
  goto loop

に等しい

main = do
  loop
loop = do
  print 3
  loop

実行は最後のステートメントにジャンプするため、gotoを表現するのが最適です。

方法が行われるため、goto doはトップレベル定義のブロックに直接ある場合にのみジャンプします。実際のgotoのように、「すべてのxを使用して残りの文を無視する」のではなく、実際に「xを呼び出して残りの語彙的に見られる文を無視する」。

最大の問題は、IOアクションの途中から実行を終了する方法がない場合、そうでさえreturnないことです。return最後のステートメントでない場合は何もしません。

これは、別のdoブロックで残りのステートメントをキャプチャすることでこれを克服します。

goto loop
print 3

になる

const loop $ do
print 3

print 3文はによって捕獲されるdoので、ブロックloopの最後の文になります。

この変換は、アクションのスコープに存在する変数もサポートします。これは、スコープ内の変数を記憶し、それらをアクションに渡すことで行われます。例えば:

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

これは単に次のように変換されます。

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

いくつかのメモ:

また、return undefinedキャプチャdoブロックが空でないことを確認するステートメントが追加されます。

キャプチャdoブロックに型のあいまいさが存在することがあるため、constを使用する代わりにを使用しますasTypeOf。これは同じですが、const両方のパラメータに同じ型が必要です。

実際の実装(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
            }
        })
}

例:

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

になる:

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

出力:

a
c

returnHaskellでは通常の関数であり、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)

使用法

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

サンプルテストケース

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

print "Asdf"

サンプルテストケースの出力

Asdf

exec()を少しお楽しみください。適切に使用しないと、最大再帰深度エラーが発生する可能性があります。


-2

// HTMLページでscriptタグを特に使用せずにJavaScriptをインポートします

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

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

それは私が知っている足の不自由です。長さ:99


@ user2509848:このスレッドはタグ付きのゴルフではありません。
ジョーイアダムス14

投稿にはscriptタグが必要です。それでは、新機能は正確にどこにありますか?
マナトワーク14

@JoeyAdamsおっと、すみません。
Hosch250 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.