Thêm một tính năng cho ngôn ngữ lập trình [đã đóng]


55

Nhiệm vụ của bạn là giải quyết một tính năng cho ngôn ngữ lập trình, bằng cách triển khai một thư viện rất thông minh hoặc bằng cách xử lý văn bản đầu vào và / hoặc điều chỉnh quá trình biên dịch.

Ý tưởng:

  • Thêm bản trình bày kiểu PHP xen kẽ vào C (ví dụ <?c printf("Hello,"); ?> world!).
  • Thêm một toán tử hợp nhất null vào một trong những ngôn ngữ không phải là C #.
  • Thêm macro vào PHP.
  • Thêm gotovào JavaScript.
  • Thêm khớp mẫu cho ngôn ngữ X.
  • Thêm hỗ trợ không gian tên cho một ngôn ngữ không có ngôn ngữ đó.
  • Làm cho C trông giống như PHP.
  • Làm cho Haskell trông giống như Pascal.
  • ... (Hãy đăng ý tưởng trong phần bình luận)

Quy tắc:

  • Mang một cái gì đó lên bàn. Đừng chỉ nói "Mẫu Haskell" để thêm các tiện ích siêu lập trình vào Haskell. Đây không phải là StackOverflow.
  • Toàn bộ việc thực hiện phải phù hợp với một màn hình (không tính ví dụ).
  • Không lưu trữ mã trên một trang web bên ngoài đặc biệt cho nhiệm vụ này.
  • Các tính năng ấn tượng hoặc đáng ngạc nhiên nhất chiến thắng.

Đừng lo lắng về việc triển khai tính năng chính xác 100%. Cách xa nó! Thách thức chính là tìm ra những gì bạn muốn làm và luẩn quẩn cắt giảm chi tiết cho đến khi công việc theo kế hoạch của bạn trở nên khả thi.

Thí dụ:

Thêm một toán tử lambda vào ngôn ngữ lập trình C.

Tiếp cận ban đầu:

Được rồi, tôi biết tôi muốn sử dụng libgc vì vậy lambdas của tôi sẽ giải quyết các vấn đề funarg lên và xuống. Tôi đoán điều đầu tiên tôi cần làm là viết / tìm một trình phân tích cú pháp cho ngôn ngữ lập trình C, sau đó tôi cần tìm hiểu tất cả về hệ thống loại C. Tôi phải tìm ra làm thế nào để hiểu ý nghĩa của nó cho đến khi các loại đi. Tôi sẽ cần phải thực hiện suy luận kiểu hay đơn giản là tôi nên yêu cầu tham số chính thức được gõ như đã cho? Thế còn tất cả những tính năng điên rồ trong CI chưa biết đến thì sao?

Rõ ràng là việc triển khai lambda trong C một cách chính xác sẽ là một công việc to lớn. Hãy quên đi sự đúng đắn! Đơn giản hóa, đơn giản hóa.

Tốt hơn:

Vặn vít lên, ai cần em? Tôi có thể có thể làm điều gì đó khó khăn với của GNU C chức năng lồng nhaubiểu thức tuyên bố . Tôi muốn thể hiện một chuyển đổi cú pháp tuyệt vời trên C với mã ngắn gọn, mãnh liệt, nhưng tôi thậm chí sẽ không cần một trình phân tích cú pháp cho việc này. Điều đó có thể chờ đợi một ngày khác.

Kết quả (yêu cầu 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;
}

Điều đó thật dễ dàng phải không? Tôi thậm chí đã ném vào một mapmacro để làm cho nó hữu ích và đẹp.



4
Tôi không muốn tạo một câu trả lời đầy đủ, nhưng tôi đã thêm các lớp vào GNU C , trong trường hợp có ai quan tâm.
Richard J. Ross III

3
Bạn không chắc chắn nếu điều này đủ điều kiện, nhưng tôi đã viết một ví dụ về sự tiếp tục trong C . Một chút nhiều hơn một màn hình, mặc dù.
kẻ lừa đảo người lái xe

1
Tôi cảm ơn bất cứ ai đã hồi sinh câu hỏi này; Tôi có một ý tưởng tuyệt vời cho trình của tôi.
Jonathan Van Matre

2
Thêm một lambda vào C ... hey đừng nhìn tôi như thế.
Leushenko

Câu trả lời:


27

Cú pháp OOP trong Haskell

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

Các đối tượng có thể có các thuộc tính:

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

... và phương pháp:

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

2
Đâu đó tôi thấy toán tử này được viết &và định nghĩa như thế này (&) = flip ($).
swish

6
@swish Tôi không sử dụng &vì đó là toán tử đơn vị 'địa chỉ' (việc triển khai các con trỏ trong Haskell được để lại như một bài tập cho người đọc).
lortabac

1
@swish bạn có thể lưu một nhân vật (và một chu kỳ não) bằng cách sử dụngflip id
Sean D

24

goto trong JavaScript?

Suy nghĩ đầu tiên của tôi là một cách tiếp cận chức năng - để thêm một tham số cho hàm để cho biết nơi bắt đầu thực thi, sử dụng điều đó với một switchcâu lệnh và một vòng lặp bên ngoài liên tục gọi hàm trên giá trị trả về của chính nó . Thật không may, điều đó sẽ ngăn cản việc sử dụng các biến cục bộ, vì chúng sẽ mất giá trị của chúng với mỗi goto.

Tôi có thể sử dụng một withcâu lệnh và di chuyển tất cả các khai báo biến sang đầu hàm, nhưng phải có một cách tốt hơn. Cuối cùng tôi đã sử dụng xử lý ngoại lệ của JavaScript . Trên thực tế, Joel Spolsky nói: "Tôi coi các trường hợp ngoại lệ không tốt hơn" goto's ... " - rõ ràng là một sự phù hợp hoàn hảo.

Ý tưởng là đặt một vòng lặp vô hạn bên trong một hàm, chỉ bị chấm dứt bởi một returncâu lệnh hoặc một ngoại lệ chưa được lưu. Tất cả các gotos, được coi là ngoại lệ, sẽ được bắt trong vòng lặp để ngăn chặn sự chấm dứt của nó. Đây là kết quả của cách tiếp cận đó:

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

Bạn có thể sử dụng nó như thế này - ngay cả trong chế độ nghiêm ngặt ES5 - ngoại trừ trong Internet Explorer ( bản demo ):

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

[Internet Explorer, vì một số lý do, không thể đánh dấu mã của hàm ẩn danh, do đó người ta sẽ phải đặt tên cho hàm (trước khi viết lại) và gọi nó bằng tên đó. Tất nhiên, điều đó có thể sẽ phá vỡ các quy tắc nghiêm ngặt của chế độ.]

Điều này không cho phép chuyển đến một tuyên bố nằm trong một khối (cho đến khi các cấu trúc như thiết bị của Duff trở thành hợp pháp), nhưng chúng ta có thể giải quyết điều đó (một chức năng tự viết lại khác), phải không?


1
Ngọt! Công việc tốt đẹp giữ cho nó đơn giản. Một câu đố nhỏ thú vị: nếu gotođược triển khai hoàn toàn bằng JavaScript (đến nơi bạn có thể sử dụng gotođể nhảy ra khỏi bất kỳ phạm vi nào, thậm chí là một hàm ), nó sẽ ngụ ý hỗ trợ cho các phần tiếp theo.
Joey Adams

22

#define trong Java

Tôi nghĩ sẽ rất vui khi triển khai các macro trong 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("."));
    }

}

Sử dụng mẫu (chuyển đổi thành mã được đăng trước đó; hãy làm cho nó lạ):

#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
Tôi đang cuộn qua khối thứ hai và suy nghĩ duy nhất của tôi là "... xuống hố thỏ".
Soham Chowdhury

18

Nghiên cứu trong C

Lặp lại mảng (hoạt động cho mảng tĩnh, không phải mảng, nhận được thông qua con trỏ)

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

Để kiểm tra nó:

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

kết quả:

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

17

Thuộc tính trong C

Tomasz Wegrzanowski đã triển khai các thuộc tính ở đồng bằng C, bằng cách cố ý phân tách chương trình khi tài sản được truy cập.

Một đối tượng có "thuộc tính" được thiết lập bằng cách tạo một đối structtượng vượt qua nhiều trang, đảm bảo rằng địa chỉ bộ nhớ của thuộc tính nằm trong một trang khác với các thành viên dữ liệu thực. Trang của tài sản được đánh dấu là không có quyền truy cập, đảm bảo rằng việc cố gắng truy cập vào tài sản sẽ gây ra lỗi. Sau đó, một bộ xử lý lỗi sẽ tìm ra quyền truy cập thuộc tính nào gây ra segfault và gọi hàm thích hợp để tính giá trị của thuộc tính, được lưu trữ tại địa chỉ bộ nhớ của thuộc tính.

Trình xử lý lỗi cũng đánh dấu trang dữ liệu là chỉ đọc để đảm bảo giá trị tính toán vẫn nhất quán; Lần tới khi bạn cố gắng ghi vào một thành viên dữ liệu, điều đó sẽ kích hoạt một segfault, trình xử lý của nó đặt trang dữ liệu là đọc-ghi và trang thuộc tính là không truy cập (chỉ ra rằng nó cần được tính toán lại).


15

Tính toán đến từ Common Lisp

Tôi ban đầu thực hiện đến từ. Nhưng điều đó không đủ tốt.

Lấy cảm hứng từ goto tính toán, tôi quyết định thực hiện tính toán đến từ.

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

Ví dụ về việc sử dụng

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

Đối với mỗi khai báo xuất phát trong tagbody, nó sẽ kiểm tra tại mỗi nhãn nếu biến xuất phát bằng nhãn hiện tại và nếu vậy, hãy chuyển đến khai báo xuất phát tương ứng.

Chúc mừng

(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

"Chuỗi tự động" trong Ruby

Mã này khá đơn giản:

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

Bây giờ bạn có thể làm

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

Thêm macro vào PHP

Chúng ta chỉ có thể sử dụng bộ tiền xử lý C cho nhiệm vụ này.

Một tập lệnh php:

<?php

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

function test() {
        ERROR(Oops);
}

Ống nó mặc dù cpp:

cpp < test.php

Kết quả:

<?php

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

Sẽ không phá vỡ các tính năng PHP không tồn tại trong C? Chẳng hạn như heredocs. Afair the C PP khá chặt chẽ với ngữ pháp của C.
Joey

1
Tôi nghĩ rằng bộ tiền xử lý chỉ làm mất đầu vào mà không cố gắng hiểu ý nghĩa của nó. An <<<HEREDOCkhông có gì nhiều hơn 3 lần thấp hơn hoặc dịch chuyển trái và một mã định danh :-) Điều này sẽ thay thế macro trong chuỗi heredoc, tuy nhiên.
Arnaud Le Blanc

Bộ tiền xử lý C thêm rác vào đầu ra, vì vậy ví dụ của bạn sẽ không hoạt động như mong đợi
kẻ hèn nhát ẩn danh

1
Một grep -v ^#sửa chữa mà. Tôi đoán điều này là đủ cho câu hỏi này :-)
Arnaud Le Blanc

10

Bảo vệ khớp mẫu trong 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

Phần thân của hàm có 288 ký tự.

Bảo vệ khớp mẫu cho phép bạn sử dụng các hàm hoàn toàn khác nhau tùy thuộc vào giá trị đối số. Mặc dù có thể dễ dàng mô phỏng bằng một loạt các ifcâu lệnh, các bộ bảo vệ khớp mẫu có thể giúp tách các phần mã và đó là một lý do tuyệt vời để thực hiện một số siêu lập trình điên rồ.

pattern_matchlà một trang trí tạo ra một chức năng mới thực hiện mô hình phù hợp với bảo vệ. Các điều kiện cho mỗi "hàm phụ" được cung cấp trong mỗi chuỗi doc trên các dòng bắt đầu bằng một đường ống ( |). Nếu tất cả các điều kiện đánh giá trung thực, phiên bản của chức năng đó được chạy. Các chức năng được kiểm tra theo thứ tự cho đến khi tìm thấy kết quả khớp. Nếu không, Noneđược trả lại.

Một ví dụ sẽ giúp làm 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

Trong Haskell, đây được gọi là vệ sĩ , không khớp mẫu. Trong Haskell, khớp mẫu cho phép bạn nói f [a,b,c] = ..., điều này không chỉ kiểm tra đối số dựa trên một vị từ mà còn liên kết các biến tương ứng khi khớp thành công. Điều này vẫn còn khá mát mẻ, mặc dù.
Joey Adams

Ôi! Cảm ơn đã sửa nó! Tôi cũng đã suy nghĩ về Haskell, đặc biệt tập trung vào việc xác định một hàm với hai vị từ khác nhau (nghĩa là f (x:xs) = ...f [] = ...). Bằng cách nào đó tôi đã xúi giục lính gác vào đó, nhưng đó là nơi tôi lấy |từ đó.
zbanks

Đây không phải là một thử thách golf mã; bạn có thể dài dòng hơn (và có thể đọc được) nếu bạn muốn! :)
ReyCharles


7

Toán tử tùy chỉnh ở Lua

Pogs đã khéo léo lạm dụng toán tử quá tải trong Lua để cho phép các toán tử infix tùy chỉnh được xác định. Tôi đã mở rộng điều này để hỗ trợ phân chia toán tử (áp dụng một phần toán tử với toán hạng) và gọi đối tượng kết quả như thể nó là một hàm.

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

Chuỗi nhiều dòng trong javascript

trong cú pháp phức tạp này cho các chuỗi nhiều dòng, mọi chuỗi đa dòng sẽ được đi trước (function(){/*và một dòng mới, và theo sau là một dòng mới và */}+'').split('\n').slice(1,-1).join('\n').

sử dụng cú pháp trực quan, tuyệt vời này, cuối cùng chúng ta cũng có thể sử dụng các chuỗi đa dòng:

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

Đối với những người không thích cú pháp đơn giản của chúng tôi, chúng tôi có một trình biên dịch sang ngôn ngữ mới tuyệt vời của chúng tôi:

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

ví dụ tương tự, trong phiên bản ngôn ngữ biên dịch:

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

1
Vì một số lý do, tôi không thể đặt */chuỗi đa dòng của mình. Điều này là siêu khó chịu khi bao gồm regexps trong chuỗi!
FireFly

@FireFly Trên thực tế, tôi nghĩ rằng điều này vẫn hoạt động. Việc làm nổi bật cú pháp trở nên kỳ lạ mặc dù.
tự hào

6

Danh sách có thể cắt trong C # (như Python)

Tôi luôn thích ký hiệu lát của python và ước nó có sẵn trong C #

Sử dụng:

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)

Mã, xa bằng chứng lỗi:

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

Tôi đã yêu cầu cắt một thời gian dài trước đây để được đưa vào .NET, nó vẫn đơn giản bị bỏ qua :(
Ray

6

Làm cho C đơn giản hơn

Mã này cho phép bạn viết các chương trình C giống với ngôn ngữ kịch bản hơn một chút. Nó có các từ khóa như 'var', 'là', 'chuỗi', 'plus', 'bằng' và một số từ khác. Nó hoạt động thông qua rất nhiều tuyên bố xác định.

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

Điều này cho phép bạn viết mã như:

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

Ở trên được mở rộng thành:

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

Có lẽ không quá hữu ích nhưng tôi thấy khá thú vị khi về cơ bản bạn có thể tạo toàn bộ ngôn ngữ lập trình thông qua một loạt các #defines.


Trông giống như một bản mashup Javascript / Ruby ...
Beta Decay

Không có giới hạn nào cao cho điều này - với #defines đủ phức tạp , bạn thậm chí có thể cung cấp cho ngôn ngữ của mình những thứ như xử lý ngoại lệ và thu gom rác trong khi vẫn giữ lớp C cơ bản bên dưới.
Leushenko

5

Tcl

Tcl không có do ... whilehay 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
            }
        }
    }
}

Thí dụ:

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

uplevel thực thi một tập lệnh trong phạm vi người gọi.


5

Đi trong PostScript

Suy nghĩ đầu tiên của tôi là tôi phải làm quen với stack exec, do đó, việc khởi động sai này đào lên toán tử tiếp tục để dừng từ ghostscript (hoặc xpost).

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

Nhưng, nó đơn giản hơn thế. Bởi vì vị trí tệp là giống nhau cho tất cả các bản sao của xử lý tệp ( setfilepositiontiêu thụ đối số của nó, vì vậy đây là ngữ nghĩa hữu ích duy nhất cho chức năng đó).

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

Nó in 5.

Có một số hạn chế với những điều trên. Bước nhảy không phải là ngay lập tức, nhưng xảy ra khi phần thân if trở về mức cao nhất và trình thông dịch lại đọc từ tệp (thay vì đọc từ mảng có chứa phần thân if). Tại thời điểm đó, tệp đã được định vị lại và 'goto' có hiệu lực.


Và đó chỉ là định nghĩa trong từ điển, vì vậy bạn có thể sử dụng hầu hết mọi loại cho nhãn.
kẻ lừa đảo người lái xe

Bạn cũng có thể thực hiện các bước nhảy tuyệt đối với currentfile <pos> setfileposition, đếm byte từ đầu tệp.
luser droog

4

Symbol#to_proc với các đối số trong Ruby

Symbol#to_proccó lẽ là một trong những thủ thuật yêu thích của tôi để viết mã Ruby thực sự cô đọng. Giả sử bạn có

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

và bạn muốn chuyển đổi nội dung của numstextthành Floats và các từ viết hoa tương ứng. Symbol#to_proccho phép bạn rút ngắn mã như thế này:

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

đến đây:

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

Tuyệt vời! Nhưng nếu chúng ta muốn nâng cao mọi phần tử trong numsvới ithứ quyền lực, hoặc thay thế tất cả xảy ra svới *trong text? Có cách nào để rút ngắn mã như thế này không?

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

Than ôi, không có cách dễ dàng để vượt qua đối số khi sử dụng Symbol#to_proc. Tôi đã thấy nó được thực hiện theo nhiều cách, nhưng có lẽ hai trong số những cách thông minh và có thể sử dụng nhất liên quan đến việc vá khỉ cho Symbollớp [ 1 , 2 ]. Tôi sẽ minh họa cách đầu tiên dưới đây.

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

Bây giờ bạn có thể làm những việc như:

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

3

Thuyết minh JavaScript

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

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

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

Đầu ra

Seattle, WA
New York, NY
Chicago, IL

Cú pháp thay thế, giống như 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);
});

Đây không phải là một lý thuyết đơn giản, nhưng thú vị hơn. Nó kiểm tra danh sách đối số của hàm tiêu thụ. Bạn có thể đi xa hơn với thủ thuật này và làm những điều thực sự tuyệt vời.
Joey Adams

1
Tôi đã đi cho một foreach phong cách Tcl. Tôi đã thêm một cách tiếp cận hơi khác giống như Tcl.
sói

2

Gotos ở Haskell

ý tưởng cơ bản là gotos có thể được mô phỏng một phần bằng cách sử dụng câu lệnh cuối cùng trong phần dochú thích. ví dụ:

main = do
  loop:
  print 3
  goto loop

tương đương với

main = do
  loop
loop = do
  print 3
  loop

bởi vì thực thi sẽ nhảy đến câu lệnh cuối cùng, nó là tối ưu để thể hiện gotos.

bởi vì cách nó được thực hiện, gotos chỉ nhảy khi chúng ở dokhối định nghĩa toplevel trực tiếp. nó thực sự là "gọi x và bỏ qua phần còn lại của các câu lệnh được nhìn từ vựng " chứ không phải là "tất cả x và bỏ qua phần còn lại của các câu lệnh", giống như một goto thực sự.

vấn đề lớn nhất là khi không có cách nào để thực thi từ giữa một hành động IO - thậm chí là returnkhông; returnkhông làm gì khi nó không phải là tuyên bố cuối cùng.

điều này khắc phục điều này bằng cách nắm bắt phần còn lại của các báo cáo bởi một dokhối khác .

goto loop
print 3

trở thành

const loop $ do
print 3

những print 3tuyên bố được chụp bởi các dokhối, do đó looptrở thành báo cáo kết quả cuối cùng.

phép chuyển đổi này cũng hỗ trợ các biến có mặt ở phạm vi của các hành động. điều này được thực hiện bằng cách ghi nhớ các biến trong phạm vi và chuyển chúng vào các hành động. ví dụ:

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

điều này chỉ đơn giản dịch thành:

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

một số lưu ý:

Ngoài ra, một return undefinedtuyên bố được thêm vào để đảm bảo dokhối chụp không trống.

bởi vì đôi khi có sự mơ hồ kiểu trong dokhối chụp , thay vì constchúng ta sử dụng asTypeOf, giống như constnhưng yêu cầu cả hai tham số của nó phải có cùng loại.

triển khai thực tế (trong 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
            }
        })
}

một exampe:

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

trở thành:

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

đầu ra:

a
c

Cần làm rõ rằng returntrong Haskell là một chức năng thông thường và không liên quan đến từ khóa trong C / etc.
FireFly

1

Goto Python

goto

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)

Sử dụng

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

Mẫu thử

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

print "Asdf"

Mẫu thử nghiệm đầu ra

Asdf

Chỉ cần một chút vui vẻ với exec (). Có thể tăng lỗi độ sâu đệ quy tối đa nếu không được sử dụng đúng cách.


-2

// nhập javascript mà không cần sử dụng thẻ script trong trang HTML

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

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

Tôi biết đó là khập khiễng. Độ dài: 99


@ user2509848: Chủ đề này không được gắn thẻ mã golf.
Joey Adams

Những gì bạn đăng yêu cầu scriptthẻ xung quanh nó. Vậy thì chính xác tính năng mới ở đâu?
manatwork

@JoeyAdams Rất tiếc, xin lỗi.
Hosch250 ngày
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.