프로그래밍 언어에 기능 추가 [닫기]


55

당신의 임무는 매우 영리한 라이브러리를 구현하거나 입력 텍스트를 처리하거나 컴파일 프로세스를 조정하여 기능을 프로그래밍 언어에 고정시키는 것입니다.

아이디어 :

  • C에 인터리빙하는 PHP 스타일 프리젠 테이션을 추가하십시오 (예 :) <?c printf("Hello,"); ?> world!.
  • C #이 아닌 언어 중 하나에 null 통합 연산자 를 추가하십시오 .
  • PHP에 매크로를 추가하십시오.
  • gotoJavaScript에 추가하십시오 .
  • 언어 X와 일치하는 패턴을 추가하십시오.
  • 없는 언어에 네임 스페이스 지원을 추가하십시오.
  • C를 PHP처럼 보이게 만듭니다.
  • 하스켈을 파스칼처럼 보이게합니다.
  • ... (의견 섹션에 아이디어를 자유롭게 게시하십시오)

규칙 :

  • 테이블에 무언가를 가져옵니다. Haskell에 메타 프로그래밍 기능을 추가하기 위해 "템플릿 Haskell"이라고 말하지 마십시오. 이것은 StackOverflow가 아닙니다.
  • 전체 구현은 하나의 스크린에 맞아야합니다 (예제를 세지 않음).
  • 이 작업을 위해 외부 사이트에서 코드를 호스팅하지 마십시오.
  • 가장 인상적이거나 놀라운 기능이 승리합니다.

기능을 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매크로를 유용하고 예쁘게 만들기 위해 던졌습니다 .


10
나는 Ken Thompson이 우리 모두를 이길 것이라고 생각합니다 : 0 바이트의 코드.
dmckee

4
완전한 답변을 만들고 싶지 않지만 누구나 관심이있는 경우 GNU C에 클래스를 추가했습니다 .
Richard J. Ross III

3
이것이 자격이되는지 확실하지 않지만 C연속 예제를 작성했습니다 . 그러나 화면 전체보다 조금 더.
luser droog

1
이 질문을 부활시킨 사람에게 감사합니다. 제출에 대한 훌륭한 아이디어가 있습니다.
Jonathan Van Matre

2
C에 람다를 추가하십시오 ... 이런 날 보지 마십시오.
Leushenko

답변:


27

하스켈의 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 ($).
swish

6
@swish &'address-of'단항 연산자이기 때문에 사용하지 않았습니다 (Haskell에서 포인터 구현은 독자를위한 연습으로 남습니다).
lortabac

1
@swish 당신은 다음을 사용하여 캐릭터 (그리고 두뇌주기)를 절약 할 수 있습니다flip id
Sean D

24

goto JavaScript로?

첫 번째 생각은 함수형 접근 방식입니다 . 함수 에 매개 변수를 추가하여 실행을 시작해야하는 위치를 나타내는 switch문과 외부 루프를 사용 하여 반복적으로 함수를 자체 반환 값으로 호출하는 것을 나타냅니다 . 불행히도 지역 변수는 모든 goto마다 값을 잃을 수 있으므로 지역 변수를 사용할 수 없습니다.

with명령문을 사용하고 모든 변수 선언을 함수의 시작 부분으로 옮길 수는 있지만 더 좋은 방법이 있어야했습니다. 결국 JavaScript의 예외 처리 를 사용하게되었습니다 . 실제로 Joel Spolsky는 "예외가"goto 's ... "보다 더 나쁘지 않다고 생각합니다.

아이디어는 함수 안에 무한 루프를 넣고 return명령문이나 포착되지 않은 예외 로만 종료하는 것이 었습니다 . 예외로 취급되는 모든 gotos는 종료를 막기 위해 루프 내에서 포착됩니다. 그 접근법의 결과는 다음과 같습니다.

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 )를 제외하고 ES5 엄격 모드에서도 다음과 같이 사용할 수 있습니다 .

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

[어떻게 든 Internet Explorer는 익명 함수의 코드를 평가하지 못하므로 함수를 다시 작성하기 전에 이름을 지정하고 해당 이름을 사용하여 호출해야합니다. 물론, 그것은 엄격 모드의 규칙을 어길 것입니다.]

이것은 더프의 장치가 합법화 될 때까지 블록 안에있는 문장으로 뛰어 넘을 수는 없지만 우리는 그 (다른 자체 실행 재 작성 기능)를 처리 할 수 ​​있습니까?


1
단! 간단하게 유지하면서 좋은 일. 흥미로운 사소한 점 : gotoJavaScript로 완전히 구현 된 경우 ( goto어떤 범위에서나 함수 를 뛰어 넘기 위해 사용할 수있는 곳 까지 ) 계속을 지원한다는 의미입니다.
Joey Adams

22

# 자바 정의

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
나는 두 번째 블록을 스크롤하고 있었고, 유일한 생각은 "... 토끼 구멍 아래로"였습니다.
Soham Chowdhury

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속성의 메모리 주소가 실제 데이터 멤버와 다른 페이지에 있도록 여러 페이지에 걸쳐있는를 작성하여 "속성"이있는 개체를 설정합니다 . 숙박 업소의 페이지는 액세스 불가로 표시되어 있으며 해당 숙박 업소에 액세스하려고하면 segfault가 발생합니다. 그런 다음 결함 처리기는 어떤 속성 액세스로 인해 segfault가 발생했는지 파악하고 적절한 함수를 호출하여 속성 값을 계산합니다.이 값은 속성의 메모리 주소에 저장됩니다.

결함 핸들러는 또한 계산 된 값이 일관성을 유지하도록 데이터 페이지를 읽기 전용으로 표시합니다. 다음에 데이터 멤버에 쓰려고하면 segfault가 트리거되며,이 핸들러는 데이터 페이지를 읽기 / 쓰기로 설정하고 속성 페이지를 비 액세스로 설정합니다 (재 계산해야 함을 나타냄).


15

Common Lisp에서 계산 된 계산

나는 처음부터 시작했다. 그러나 그것은 충분하지 않았다.

계산 된 goto에서 영감을 얻어 계산 된 시작을 구현하기로 결정했습니다.

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

태그 본의 각 ​​발신 선언에 대해 각 발신 변수가 현재 레이블과 동일한 지 각 레이블에서 확인하고, 해당하는 경우 해당 발신 선언으로 이동합니다.

그 리터

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

피즈 버즈

(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

루비의 "자동 문자열"

코드는 매우 간단합니다.

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 기능을 사용하지 않습니까? heredocs와 같은. C PP는 C의 문법과 밀접한 관련이있었습니다.
Joey

1
전처리 기는 입력을 이해하려고 시도하지 않고 입력을 수행한다고 생각합니다. An <<<HEREDOC은 3보다 작거나 왼쪽으로 이동하고 식별자입니다. :-) 그러나 이것은 heredoc 문자열에서 매크로 대체를 수행합니다.
Arnaud Le Blanc 11

C 전처리 출력에 여분의 쓰레기를 추가, 그래서 당신의 예는 예상대로 작동하지 않을 것입니다
익명의 겁쟁이

1
A는 grep -v ^#그 문제를 해결 whould. 이 질문에 충분하다고 생각합니다 :-)
Arnaud Le Blanc

10

파이썬에서 패턴 매칭 가드

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패턴 일치 가드 를 구현하는 새로운 기능을 만드는 데코레이터입니다 . 파이프 ( |)로 시작하는 줄에 각 문서화 문자열에 제공된 각 "하위 기능"에 대한 조건 . 모든 조건이 진실로 평가되면 해당 버전의 함수가 실행됩니다. 일치하는 것을 찾을 때까지 함수가 테스트됩니다. 그렇지 않으면 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] = ...술어에 대해 인수를 테스트 할뿐만 아니라 성공적인 일치시 각 변수를 바인딩합니다. 그래도 여전히 멋지다.
Joey Adams

도이! 수정 해 주셔서 감사합니다! 나는 Haskell에 대해서도 생각하고 있었는데, 특히 두 개의 다른 술어 (즉 f (x:xs) = ..., 및 f [] = ...) 로 함수를 정의하는 데 중점을 두었습니다 . 어쨌든 나는 경비원을 거기로 뒤흔들 었습니다 |.
zbanks

이것은 코드 골프 도전이 아닙니다. 원한다면 더 장황하고 읽을 수 있습니다! :)
ReyCharles


7

루아의 커스텀 연산자

딱지는 세라 루아 연산자 과부하 학대 맞춤 중위 연산자를 정의 할 수 있도록하기 위해. 연산자 섹션화 (부분적으로 피연산자로 연산자 적용)를 지원하고 결과 개체를 함수 인 것처럼 호출하도록이 기능을 확장했습니다.

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

자바 스크립트의 여러 줄 문자열

여러 줄 문자열에 대한이 정교한 구문에서 모든 (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 사실, 이것이 여전히 작동한다고 생각합니다. 그래도 syntex 강조 표시가 이상해집니다.
자랑스런 Haskeller

6

C #에서 슬라이스 가능한 목록 (예 : 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 매쉬업처럼 보입니다.
Beta Decay

이것에 대한 상한은 거의 없습니다. 복잡한 #defines로 기본 C 레이어를 계속 유지하면서 예외 처리 및 가비지 수집과 같은 언어를 제공 할 수도 있습니다.
Leushenko

5

Tcl

Tcl은 전혀 없다 do ... while거나 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
            }
        }
    }
}

예:

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

uplevel 발신자 범위에서 스크립트를 실행합니다.


5

포스트 스크립트로 이동

내 첫 번째 생각은 exec 스택과 관련이 있어야한다는 것이므로이 잘못된 시작은 ghostscript (또는 xpost)에서 중단 된 연속 연산자를 파헤칩니다.

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

그러나 그것보다 간단합니다. 파일 위치는 파일 핸들의 모든 복제본에 대해 동일하기 때문에 ( 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 droog

또한 파일 시작 부분부터 바이트 수를 세면서 절대 점프를 수행 할 수도 currentfile <pos> setfileposition있습니다.
luser droog

4

Symbol#to_proc 루비에서 인수로

Symbol#to_proc아마도 간결한 루비 코드를 작성하는 가장 좋아하는 요령 중 하나 일 것입니다. 당신이 가지고 있다고 가정

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)

대박! 그러나 우리의 모든 요소를 높이기 위해 무엇을 원하는 경우 nums받는 i일 전원, 또는 모든 항목을 바꾸 s*text? 이와 같은 코드를 줄이는 방법이 있습니까?

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

아아,를 사용할 때 인수를 전달하는 쉬운 방법은 없습니다 Symbol#to_proc. 나는 그것이 여러 가지 방법으로 수행되는 것을 보았지만 아마도 가장 영리하고 사용 가능한 것 중 두 가지는 Symbol클래스를 원숭이 패치하는 것과 관련이있을 것이다 [ 1 , 2 ]. 아래 첫 번째 방법을 설명하겠습니다.

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

이것은 평범한 것은 아니지만 더 흥미 롭습니다. 소비 함수의 인수 목록을 검사합니다. 이 트릭으로 더 나아가고 정말 멋진 일을 할 수 있습니다.
Joey Adams

1
나는 Tcl 스타일 foreach를 가고 있었다. Tcl과 비슷한 약간 다른 접근 방식을 추가했습니다.
wolfhammer

2

하스켈의 고 토스

기본 개념은 do-notations 의 마지막 문장을 사용하여 gotos를 부분적으로 시뮬레이션 할 수 있다는 것입니다. 예를 들면 다음과 같습니다.

main = do
  loop:
  print 3
  goto loop

에 해당

main = do
  loop
loop = do
  print 3
  loop

실행은 마지막 문장으로 넘어 가기 때문에 gotos를 표현하는 것이 가장 좋습니다.

그것이 수행되는 방식으로, gotos 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하지만 두 매개 변수가 동일한 유형을 갖도록 요구합니다.

실제 구현 (자바 스크립트) :

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

파이썬 고토

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 태그를 구체적으로 사용하지 않고 자바 스크립트 가져 오기

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

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

내가 아는 것은 절름발이입니다. 길이 : 99


@ user2509848 :이 스레드에는 코드 골프 태그가 없습니다.
Joey Adams

게시 한 내용에는 script태그 가 필요 합니다. 그렇다면 새로운 기능은 정확히 어디에 있습니까?
manatwork

@JoeyAdams 죄송합니다. 죄송합니다.
Hosch250
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.